root/drivers/net/wireless/intersil/hostap/hostap_plx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hfa384x_outb_debug
  2. hfa384x_inb_debug
  3. hfa384x_outw_debug
  4. hfa384x_inw_debug
  5. hfa384x_outsw_debug
  6. hfa384x_insw_debug
  7. hfa384x_from_bap
  8. hfa384x_to_bap
  9. prism2_plx_cor_sreset
  10. prism2_plx_genesis_reset
  11. prism2_plx_check_cis
  12. prism2_plx_probe
  13. prism2_plx_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 #define PRISM2_PLX
   3 
   4 /* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is
   5  * based on:
   6  * - Host AP driver patch from james@madingley.org
   7  * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc.
   8  */
   9 
  10 
  11 #include <linux/module.h>
  12 #include <linux/if.h>
  13 #include <linux/skbuff.h>
  14 #include <linux/netdevice.h>
  15 #include <linux/slab.h>
  16 #include <linux/workqueue.h>
  17 #include <linux/wireless.h>
  18 #include <net/iw_handler.h>
  19 
  20 #include <linux/ioport.h>
  21 #include <linux/pci.h>
  22 #include <asm/io.h>
  23 
  24 #include "hostap_wlan.h"
  25 
  26 
  27 static char *dev_info = "hostap_plx";
  28 
  29 
  30 MODULE_AUTHOR("Jouni Malinen");
  31 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
  32                    "cards (PLX).");
  33 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
  34 MODULE_LICENSE("GPL");
  35 
  36 
  37 static int ignore_cis;
  38 module_param(ignore_cis, int, 0444);
  39 MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
  40 
  41 
  42 /* struct local_info::hw_priv */
  43 struct hostap_plx_priv {
  44         void __iomem *attr_mem;
  45         unsigned int cor_offset;
  46 };
  47 
  48 
  49 #define PLX_MIN_ATTR_LEN 512    /* at least 2 x 256 is needed for CIS */
  50 #define COR_SRESET       0x80
  51 #define COR_LEVLREQ      0x40
  52 #define COR_ENABLE_FUNC  0x01
  53 /* PCI Configuration Registers */
  54 #define PLX_PCIIPR       0x3d   /* PCI Interrupt Pin */
  55 /* Local Configuration Registers */
  56 #define PLX_INTCSR       0x4c   /* Interrupt Control/Status Register */
  57 #define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
  58 #define PLX_CNTRL        0x50
  59 #define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
  60 
  61 
  62 #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
  63 
  64 static const struct pci_device_id prism2_plx_id_table[] = {
  65         PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
  66         PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
  67         PLXDEV(0x126c, 0x8030, "Nortel emobility"),
  68         PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
  69         PLXDEV(0x1385, 0x4100, "Netgear MA301"),
  70         PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
  71         PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
  72         PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
  73         PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
  74         PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
  75         PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
  76         PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
  77         PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
  78         PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
  79         { 0 }
  80 };
  81 
  82 
  83 /* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid
  84  * is not listed here, you will need to add it here to get the driver
  85  * initialized. */
  86 static struct prism2_plx_manfid {
  87         u16 manfid1, manfid2;
  88 } prism2_plx_known_manfids[] = {
  89         { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */,
  90         { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */,
  91         { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */,
  92         { 0x0126, 0x8000 } /* Proxim RangeLAN */,
  93         { 0x0138, 0x0002 } /* Compaq WL100 */,
  94         { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */,
  95         { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */,
  96         { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */,
  97         { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */,
  98         { 0x028a, 0x0002 } /* D-Link DRC-650 */,
  99         { 0x0250, 0x0002 } /* Samsung SWL2000-N */,
 100         { 0xc250, 0x0002 } /* EMTAC A2424i */,
 101         { 0xd601, 0x0002 } /* Z-Com XI300 */,
 102         { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */,
 103         { 0, 0}
 104 };
 105 
 106 
 107 #ifdef PRISM2_IO_DEBUG
 108 
 109 static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
 110 {
 111         struct hostap_interface *iface;
 112         local_info_t *local;
 113         unsigned long flags;
 114 
 115         iface = netdev_priv(dev);
 116         local = iface->local;
 117 
 118         spin_lock_irqsave(&local->lock, flags);
 119         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
 120         outb(v, dev->base_addr + a);
 121         spin_unlock_irqrestore(&local->lock, flags);
 122 }
 123 
 124 static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
 125 {
 126         struct hostap_interface *iface;
 127         local_info_t *local;
 128         unsigned long flags;
 129         u8 v;
 130 
 131         iface = netdev_priv(dev);
 132         local = iface->local;
 133 
 134         spin_lock_irqsave(&local->lock, flags);
 135         v = inb(dev->base_addr + a);
 136         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
 137         spin_unlock_irqrestore(&local->lock, flags);
 138         return v;
 139 }
 140 
 141 static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
 142 {
 143         struct hostap_interface *iface;
 144         local_info_t *local;
 145         unsigned long flags;
 146 
 147         iface = netdev_priv(dev);
 148         local = iface->local;
 149 
 150         spin_lock_irqsave(&local->lock, flags);
 151         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
 152         outw(v, dev->base_addr + a);
 153         spin_unlock_irqrestore(&local->lock, flags);
 154 }
 155 
 156 static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
 157 {
 158         struct hostap_interface *iface;
 159         local_info_t *local;
 160         unsigned long flags;
 161         u16 v;
 162 
 163         iface = netdev_priv(dev);
 164         local = iface->local;
 165 
 166         spin_lock_irqsave(&local->lock, flags);
 167         v = inw(dev->base_addr + a);
 168         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
 169         spin_unlock_irqrestore(&local->lock, flags);
 170         return v;
 171 }
 172 
 173 static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
 174                                        u8 *buf, int wc)
 175 {
 176         struct hostap_interface *iface;
 177         local_info_t *local;
 178         unsigned long flags;
 179 
 180         iface = netdev_priv(dev);
 181         local = iface->local;
 182 
 183         spin_lock_irqsave(&local->lock, flags);
 184         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
 185         outsw(dev->base_addr + a, buf, wc);
 186         spin_unlock_irqrestore(&local->lock, flags);
 187 }
 188 
 189 static inline void hfa384x_insw_debug(struct net_device *dev, int a,
 190                                       u8 *buf, int wc)
 191 {
 192         struct hostap_interface *iface;
 193         local_info_t *local;
 194         unsigned long flags;
 195 
 196         iface = netdev_priv(dev);
 197         local = iface->local;
 198 
 199         spin_lock_irqsave(&local->lock, flags);
 200         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
 201         insw(dev->base_addr + a, buf, wc);
 202         spin_unlock_irqrestore(&local->lock, flags);
 203 }
 204 
 205 #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
 206 #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
 207 #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
 208 #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
 209 #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
 210 #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
 211 
 212 #else /* PRISM2_IO_DEBUG */
 213 
 214 #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
 215 #define HFA384X_INB(a) inb(dev->base_addr + (a))
 216 #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
 217 #define HFA384X_INW(a) inw(dev->base_addr + (a))
 218 #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
 219 #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
 220 
 221 #endif /* PRISM2_IO_DEBUG */
 222 
 223 
 224 static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
 225                             int len)
 226 {
 227         u16 d_off;
 228         u16 *pos;
 229 
 230         d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
 231         pos = (u16 *) buf;
 232 
 233         if (len / 2)
 234                 HFA384X_INSW(d_off, buf, len / 2);
 235         pos += len / 2;
 236 
 237         if (len & 1)
 238                 *((char *) pos) = HFA384X_INB(d_off);
 239 
 240         return 0;
 241 }
 242 
 243 
 244 static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
 245 {
 246         u16 d_off;
 247         u16 *pos;
 248 
 249         d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
 250         pos = (u16 *) buf;
 251 
 252         if (len / 2)
 253                 HFA384X_OUTSW(d_off, buf, len / 2);
 254         pos += len / 2;
 255 
 256         if (len & 1)
 257                 HFA384X_OUTB(*((char *) pos), d_off);
 258 
 259         return 0;
 260 }
 261 
 262 
 263 /* FIX: This might change at some point.. */
 264 #include "hostap_hw.c"
 265 
 266 
 267 static void prism2_plx_cor_sreset(local_info_t *local)
 268 {
 269         unsigned char corsave;
 270         struct hostap_plx_priv *hw_priv = local->hw_priv;
 271 
 272         printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
 273                dev_info);
 274 
 275         /* Set sreset bit of COR and clear it after hold time */
 276 
 277         if (hw_priv->attr_mem == NULL) {
 278                 /* TMD7160 - COR at card's first I/O addr */
 279                 corsave = inb(hw_priv->cor_offset);
 280                 outb(corsave | COR_SRESET, hw_priv->cor_offset);
 281                 mdelay(2);
 282                 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
 283                 mdelay(2);
 284         } else {
 285                 /* PLX9052 */
 286                 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
 287                 writeb(corsave | COR_SRESET,
 288                        hw_priv->attr_mem + hw_priv->cor_offset);
 289                 mdelay(2);
 290                 writeb(corsave & ~COR_SRESET,
 291                        hw_priv->attr_mem + hw_priv->cor_offset);
 292                 mdelay(2);
 293         }
 294 }
 295 
 296 
 297 static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
 298 {
 299         unsigned char corsave;
 300         struct hostap_plx_priv *hw_priv = local->hw_priv;
 301 
 302         if (hw_priv->attr_mem == NULL) {
 303                 /* TMD7160 - COR at card's first I/O addr */
 304                 corsave = inb(hw_priv->cor_offset);
 305                 outb(corsave | COR_SRESET, hw_priv->cor_offset);
 306                 mdelay(10);
 307                 outb(hcr, hw_priv->cor_offset + 2);
 308                 mdelay(10);
 309                 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
 310                 mdelay(10);
 311         } else {
 312                 /* PLX9052 */
 313                 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
 314                 writeb(corsave | COR_SRESET,
 315                        hw_priv->attr_mem + hw_priv->cor_offset);
 316                 mdelay(10);
 317                 writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
 318                 mdelay(10);
 319                 writeb(corsave & ~COR_SRESET,
 320                        hw_priv->attr_mem + hw_priv->cor_offset);
 321                 mdelay(10);
 322         }
 323 }
 324 
 325 
 326 static struct prism2_helper_functions prism2_plx_funcs =
 327 {
 328         .card_present   = NULL,
 329         .cor_sreset     = prism2_plx_cor_sreset,
 330         .genesis_reset  = prism2_plx_genesis_reset,
 331         .hw_type        = HOSTAP_HW_PLX,
 332 };
 333 
 334 
 335 static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
 336                                 unsigned int *cor_offset,
 337                                 unsigned int *cor_index)
 338 {
 339 #define CISTPL_CONFIG 0x1A
 340 #define CISTPL_MANFID 0x20
 341 #define CISTPL_END 0xFF
 342 #define CIS_MAX_LEN 256
 343         u8 *cis;
 344         int i, pos;
 345         unsigned int rmsz, rasz, manfid1, manfid2;
 346         struct prism2_plx_manfid *manfid;
 347 
 348         cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
 349         if (cis == NULL)
 350                 return -ENOMEM;
 351 
 352         /* read CIS; it is in even offsets in the beginning of attr_mem */
 353         for (i = 0; i < CIS_MAX_LEN; i++)
 354                 cis[i] = readb(attr_mem + 2 * i);
 355         printk(KERN_DEBUG "%s: CIS: %6ph ...\n", dev_info, cis);
 356 
 357         /* set reasonable defaults for Prism2 cards just in case CIS parsing
 358          * fails */
 359         *cor_offset = 0x3e0;
 360         *cor_index = 0x01;
 361         manfid1 = manfid2 = 0;
 362 
 363         pos = 0;
 364         while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
 365                 if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN)
 366                         goto cis_error;
 367 
 368                 switch (cis[pos]) {
 369                 case CISTPL_CONFIG:
 370                         if (cis[pos + 1] < 2)
 371                                 goto cis_error;
 372                         rmsz = (cis[pos + 2] & 0x3c) >> 2;
 373                         rasz = cis[pos + 2] & 0x03;
 374                         if (4 + rasz + rmsz > cis[pos + 1])
 375                                 goto cis_error;
 376                         *cor_index = cis[pos + 3] & 0x3F;
 377                         *cor_offset = 0;
 378                         for (i = 0; i <= rasz; i++)
 379                                 *cor_offset += cis[pos + 4 + i] << (8 * i);
 380                         printk(KERN_DEBUG "%s: cor_index=0x%x "
 381                                "cor_offset=0x%x\n", dev_info,
 382                                *cor_index, *cor_offset);
 383                         if (*cor_offset > attr_len) {
 384                                 printk(KERN_ERR "%s: COR offset not within "
 385                                        "attr_mem\n", dev_info);
 386                                 kfree(cis);
 387                                 return -1;
 388                         }
 389                         break;
 390 
 391                 case CISTPL_MANFID:
 392                         if (cis[pos + 1] < 4)
 393                                 goto cis_error;
 394                         manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
 395                         manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
 396                         printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
 397                                dev_info, manfid1, manfid2);
 398                         break;
 399                 }
 400 
 401                 pos += cis[pos + 1] + 2;
 402         }
 403 
 404         if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
 405                 goto cis_error;
 406 
 407         for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
 408                 if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
 409                         kfree(cis);
 410                         return 0;
 411                 }
 412 
 413         printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
 414                " not supported card\n", dev_info, manfid1, manfid2);
 415         goto fail;
 416 
 417  cis_error:
 418         printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
 419 
 420  fail:
 421         kfree(cis);
 422         if (ignore_cis) {
 423                 printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
 424                        "errors during CIS verification\n", dev_info);
 425                 return 0;
 426         }
 427         return -1;
 428 }
 429 
 430 
 431 static int prism2_plx_probe(struct pci_dev *pdev,
 432                             const struct pci_device_id *id)
 433 {
 434         unsigned int pccard_ioaddr, plx_ioaddr;
 435         unsigned long pccard_attr_mem;
 436         unsigned int pccard_attr_len;
 437         void __iomem *attr_mem = NULL;
 438         unsigned int cor_offset = 0, cor_index = 0;
 439         u32 reg;
 440         local_info_t *local = NULL;
 441         struct net_device *dev = NULL;
 442         struct hostap_interface *iface;
 443         static int cards_found /* = 0 */;
 444         int irq_registered = 0;
 445         int tmd7160;
 446         struct hostap_plx_priv *hw_priv;
 447 
 448         hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
 449         if (hw_priv == NULL)
 450                 return -ENOMEM;
 451 
 452         if (pci_enable_device(pdev))
 453                 goto err_out_free;
 454 
 455         /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
 456         tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
 457 
 458         plx_ioaddr = pci_resource_start(pdev, 1);
 459         pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
 460 
 461         if (tmd7160) {
 462                 /* TMD7160 */
 463                 attr_mem = NULL; /* no access to PC Card attribute memory */
 464 
 465                 printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
 466                        "irq=%d, pccard_io=0x%x\n",
 467                        plx_ioaddr, pdev->irq, pccard_ioaddr);
 468 
 469                 cor_offset = plx_ioaddr;
 470                 cor_index = 0x04;
 471 
 472                 outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
 473                 mdelay(1);
 474                 reg = inb(plx_ioaddr);
 475                 if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
 476                         printk(KERN_ERR "%s: Error setting COR (expected="
 477                                "0x%02x, was=0x%02x)\n", dev_info,
 478                                cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
 479                         goto fail;
 480                 }
 481         } else {
 482                 /* PLX9052 */
 483                 pccard_attr_mem = pci_resource_start(pdev, 2);
 484                 pccard_attr_len = pci_resource_len(pdev, 2);
 485                 if (pccard_attr_len < PLX_MIN_ATTR_LEN)
 486                         goto fail;
 487 
 488 
 489                 attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
 490                 if (attr_mem == NULL) {
 491                         printk(KERN_ERR "%s: cannot remap attr_mem\n",
 492                                dev_info);
 493                         goto fail;
 494                 }
 495 
 496                 printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
 497                        "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
 498                        pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
 499 
 500                 if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
 501                                          &cor_offset, &cor_index)) {
 502                         printk(KERN_INFO "Unknown PC Card CIS - not a "
 503                                "Prism2/2.5 card?\n");
 504                         goto fail;
 505                 }
 506 
 507                 printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
 508                        "adapter\n");
 509 
 510                 /* Write COR to enable PC Card */
 511                 writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
 512                        attr_mem + cor_offset);
 513 
 514                 /* Enable PCI interrupts if they are not already enabled */
 515                 reg = inl(plx_ioaddr + PLX_INTCSR);
 516                 printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
 517                 if (!(reg & PLX_INTCSR_PCI_INTEN)) {
 518                         outl(reg | PLX_INTCSR_PCI_INTEN,
 519                              plx_ioaddr + PLX_INTCSR);
 520                         if (!(inl(plx_ioaddr + PLX_INTCSR) &
 521                               PLX_INTCSR_PCI_INTEN)) {
 522                                 printk(KERN_WARNING "%s: Could not enable "
 523                                        "Local Interrupts\n", dev_info);
 524                                 goto fail;
 525                         }
 526                 }
 527 
 528                 reg = inl(plx_ioaddr + PLX_CNTRL);
 529                 printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
 530                        "present=%d)\n",
 531                        reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
 532                 /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
 533                  * not present; but are there really such cards in use(?) */
 534         }
 535 
 536         dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
 537                                      &pdev->dev);
 538         if (dev == NULL)
 539                 goto fail;
 540         iface = netdev_priv(dev);
 541         local = iface->local;
 542         local->hw_priv = hw_priv;
 543         cards_found++;
 544 
 545         dev->irq = pdev->irq;
 546         dev->base_addr = pccard_ioaddr;
 547         hw_priv->attr_mem = attr_mem;
 548         hw_priv->cor_offset = cor_offset;
 549 
 550         pci_set_drvdata(pdev, dev);
 551 
 552         if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
 553                         dev)) {
 554                 printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
 555                 goto fail;
 556         } else
 557                 irq_registered = 1;
 558 
 559         if (prism2_hw_config(dev, 1)) {
 560                 printk(KERN_DEBUG "%s: hardware initialization failed\n",
 561                        dev_info);
 562                 goto fail;
 563         }
 564 
 565         return hostap_hw_ready(dev);
 566 
 567  fail:
 568         if (irq_registered && dev)
 569                 free_irq(dev->irq, dev);
 570 
 571         if (attr_mem)
 572                 iounmap(attr_mem);
 573 
 574         pci_disable_device(pdev);
 575         prism2_free_local_data(dev);
 576 
 577  err_out_free:
 578         kfree(hw_priv);
 579 
 580         return -ENODEV;
 581 }
 582 
 583 
 584 static void prism2_plx_remove(struct pci_dev *pdev)
 585 {
 586         struct net_device *dev;
 587         struct hostap_interface *iface;
 588         struct hostap_plx_priv *hw_priv;
 589 
 590         dev = pci_get_drvdata(pdev);
 591         iface = netdev_priv(dev);
 592         hw_priv = iface->local->hw_priv;
 593 
 594         /* Reset the hardware, and ensure interrupts are disabled. */
 595         prism2_plx_cor_sreset(iface->local);
 596         hfa384x_disable_interrupts(dev);
 597 
 598         if (hw_priv->attr_mem)
 599                 iounmap(hw_priv->attr_mem);
 600         if (dev->irq)
 601                 free_irq(dev->irq, dev);
 602 
 603         prism2_free_local_data(dev);
 604         kfree(hw_priv);
 605         pci_disable_device(pdev);
 606 }
 607 
 608 
 609 MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
 610 
 611 static struct pci_driver prism2_plx_driver = {
 612         .name           = "hostap_plx",
 613         .id_table       = prism2_plx_id_table,
 614         .probe          = prism2_plx_probe,
 615         .remove         = prism2_plx_remove,
 616 };
 617 
 618 module_pci_driver(prism2_plx_driver);

/* [<][>][^][v][top][bottom][index][help] */