Main Page | Data Structures | Directories | File List | Data Fields | Globals

hostap_plx.c

Go to the documentation of this file.
00001 #define PRISM2_PLX
00002 
00003 /* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is
00004  * based on:
00005  * - Host AP driver patch from james@madingley.org
00006  * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc.
00007  */
00008 
00009 
00010 #include <linux/config.h>
00011 #include <linux/version.h>
00012 #include <linux/module.h>
00013 #include <linux/init.h>
00014 #include <linux/if.h>
00015 #include <linux/skbuff.h>
00016 #include <linux/netdevice.h>
00017 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44))
00018 #include <linux/tqueue.h>
00019 #else
00020 #include <linux/workqueue.h>
00021 #endif
00022 #include "hostap_wext.h"
00023 
00024 #include <linux/ioport.h>
00025 #include <linux/pci.h>
00026 
00027 #include "hostap_wlan.h"
00028 
00029 
00030 static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
00031 static char *dev_info = "hostap_plx";
00032 
00033 
00034 MODULE_AUTHOR("SSH Communications Security Corp, Jouni Malinen");
00035 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
00036                    "cards (PLX).");
00037 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
00038 MODULE_LICENSE("GPL");
00039 
00040 
00041 static int ignore_cis = 0;
00042 MODULE_PARM(ignore_cis, "i");
00043 MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
00044 
00045 
00046 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
00047 /* PCI initialization uses Linux 2.4.x version and older kernels do not support
00048  * this */
00049 #error PLX9052 version requires at least Linux kernel version 2.4.0
00050 #endif /* kernel < 2.4.0 */
00051 
00052 
00053 #define PLX_MIN_ATTR_LEN 512    /* at least 2 x 256 is needed for CIS */
00054 #define COR_SRESET       0x80
00055 #define COR_LEVLREQ      0x40
00056 #define COR_ENABLE_FUNC  0x01
00057 /* PCI Configuration Registers */
00058 #define PLX_PCIIPR       0x3d   /* PCI Interrupt Pin */
00059 /* Local Configuration Registers */
00060 #define PLX_INTCSR       0x4c   /* Interrupt Control/Status Register */
00061 #define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
00062 #define PLX_CNTRL        0x50
00063 #define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
00064 
00065 
00066 #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
00067 
00068 static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
00069         PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
00070         PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
00071         PLXDEV(0x126c, 0x8030, "Nortel emobility"),
00072         PLXDEV(0x1385, 0x4100, "Netgear MA301"),
00073         PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
00074         PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
00075         PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
00076         PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
00077         PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
00078         PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
00079         PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
00080         PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
00081         { 0 }
00082 };
00083 
00084 
00085 /* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid
00086  * is not listed here, you will need to add it here to get the driver
00087  * initialized. */
00088 static struct prism2_plx_manfid {
00089         u16 manfid1, manfid2;
00090 } prism2_plx_known_manfids[] = {
00091         { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */,
00092         { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */,
00093         { 0x0126, 0x8000 } /* Proxim RangeLAN */,
00094         { 0x0138, 0x0002 } /* Compaq WL100 */,
00095         { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */,
00096         { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */,
00097         { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */,
00098         { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */,
00099         { 0x028a, 0x0002 } /* D-Link DRC-650 */,
00100         { 0x0250, 0x0002 } /* Samsung SWL2000-N */,
00101         { 0xc250, 0x0002 } /* EMTAC A2424i */,
00102         { 0xd601, 0x0002 } /* Z-Com XI300 */,
00103         { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */,
00104         { 0, 0}
00105 };
00106 
00107 
00108 #ifdef PRISM2_IO_DEBUG
00109 
00110 static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
00111 {
00112         struct hostap_interface *iface = dev->priv;
00113         local_info_t *local = iface->local;
00114         unsigned long flags;
00115 
00116         spin_lock_irqsave(&local->lock, flags);
00117         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
00118         outb(v, dev->base_addr + a);
00119         spin_unlock_irqrestore(&local->lock, flags);
00120 }
00121 
00122 static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
00123 {
00124         struct hostap_interface *iface = dev->priv;
00125         local_info_t *local = iface->local;
00126         unsigned long flags;
00127         u8 v;
00128 
00129         spin_lock_irqsave(&local->lock, flags);
00130         v = inb(dev->base_addr + a);
00131         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
00132         spin_unlock_irqrestore(&local->lock, flags);
00133         return v;
00134 }
00135 
00136 static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
00137 {
00138         struct hostap_interface *iface = dev->priv;
00139         local_info_t *local = iface->local;
00140         unsigned long flags;
00141 
00142         spin_lock_irqsave(&local->lock, flags);
00143         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
00144         outw(v, dev->base_addr + a);
00145         spin_unlock_irqrestore(&local->lock, flags);
00146 }
00147 
00148 static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
00149 {
00150         struct hostap_interface *iface = dev->priv;
00151         local_info_t *local = iface->local;
00152         unsigned long flags;
00153         u16 v;
00154 
00155         spin_lock_irqsave(&local->lock, flags);
00156         v = inw(dev->base_addr + a);
00157         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
00158         spin_unlock_irqrestore(&local->lock, flags);
00159         return v;
00160 }
00161 
00162 static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
00163                                        u8 *buf, int wc)
00164 {
00165         struct hostap_interface *iface = dev->priv;
00166         local_info_t *local = iface->local;
00167         unsigned long flags;
00168 
00169         spin_lock_irqsave(&local->lock, flags);
00170         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
00171         outsw(dev->base_addr + a, buf, wc);
00172         spin_unlock_irqrestore(&local->lock, flags);
00173 }
00174 
00175 static inline void hfa384x_insw_debug(struct net_device *dev, int a,
00176                                       u8 *buf, int wc)
00177 {
00178         struct hostap_interface *iface = dev->priv;
00179         local_info_t *local = iface->local;
00180         unsigned long flags;
00181 
00182         spin_lock_irqsave(&local->lock, flags);
00183         prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
00184         insw(dev->base_addr + a, buf, wc);
00185         spin_unlock_irqrestore(&local->lock, flags);
00186 }
00187 
00188 #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
00189 #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
00190 #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
00191 #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
00192 #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
00193 #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
00194 
00195 #else /* PRISM2_IO_DEBUG */
00196 
00197 #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
00198 #define HFA384X_INB(a) inb(dev->base_addr + (a))
00199 #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
00200 #define HFA384X_INW(a) inw(dev->base_addr + (a))
00201 #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
00202 #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
00203 
00204 #endif /* PRISM2_IO_DEBUG */
00205 
00206 
00207 static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
00208                             int len)
00209 {
00210         u16 d_off;
00211         u16 *pos;
00212 
00213         d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
00214         pos = (u16 *) buf;
00215 
00216         if (len / 2)
00217                 HFA384X_INSW(d_off, buf, len / 2);
00218         pos += len / 2;
00219 
00220         if (len & 1)
00221                 *((char *) pos) = HFA384X_INB(d_off);
00222 
00223         return 0;
00224 }
00225 
00226 
00227 static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
00228 {
00229         u16 d_off;
00230         u16 *pos;
00231 
00232         d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
00233         pos = (u16 *) buf;
00234 
00235         if (len / 2)
00236                 HFA384X_OUTSW(d_off, buf, len / 2);
00237         pos += len / 2;
00238 
00239         if (len & 1)
00240                 HFA384X_OUTB(*((char *) pos), d_off);
00241 
00242         return 0;
00243 }
00244 
00245 
00246 /* FIX: This might change at some point.. */
00247 #include "hostap_hw.c"
00248 
00249 
00250 static void prism2_plx_cor_sreset(local_info_t *local)
00251 {
00252         unsigned char corsave;
00253 
00254         printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
00255                dev_info);
00256 
00257         /* Set sreset bit of COR and clear it after hold time */
00258 
00259         if (local->attr_mem == 0) {
00260                 /* TMD7160 - COR at card's first I/O addr */
00261                 corsave = inb(local->cor_offset);
00262                 outb(corsave | COR_SRESET, local->cor_offset);
00263                 mdelay(1);
00264                 outb(corsave & ~COR_SRESET, local->cor_offset);
00265                 mdelay(1);
00266         } else {
00267                 /* PLX9052 */
00268                 corsave = readb(local->attr_mem + local->cor_offset);
00269                 writeb(corsave | COR_SRESET,
00270                        local->attr_mem + local->cor_offset);
00271                 mdelay(1);
00272                 writeb(corsave & ~COR_SRESET,
00273                        local->attr_mem + local->cor_offset);
00274                 mdelay(1);
00275         }
00276 }
00277 
00278 
00279 static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
00280 {
00281         unsigned char corsave;
00282 
00283         if (local->attr_mem == 0) {
00284                 /* TMD7160 - COR at card's first I/O addr */
00285                 corsave = inb(local->cor_offset);
00286                 outb(corsave | COR_SRESET, local->cor_offset);
00287                 mdelay(10);
00288                 outb(hcr, local->cor_offset + 2);
00289                 mdelay(10);
00290                 outb(corsave & ~COR_SRESET, local->cor_offset);
00291                 mdelay(10);
00292         } else {
00293                 /* PLX9052 */
00294                 corsave = readb(local->attr_mem + local->cor_offset);
00295                 writeb(corsave | COR_SRESET,
00296                        local->attr_mem + local->cor_offset);
00297                 mdelay(10);
00298                 writeb(hcr, local->attr_mem + local->cor_offset + 2);
00299                 mdelay(10);
00300                 writeb(corsave & ~COR_SRESET,
00301                        local->attr_mem + local->cor_offset);
00302                 mdelay(10);
00303         }
00304 }
00305 
00306 
00307 static struct prism2_helper_functions prism2_plx_funcs =
00308 {
00309         .card_present   = NULL,
00310         .cor_sreset     = prism2_plx_cor_sreset,
00311         .dev_open       = NULL,
00312         .dev_close      = NULL,
00313         .genesis_reset  = prism2_plx_genesis_reset,
00314 };
00315 
00316 
00317 static int prism2_plx_check_cis(unsigned long attr_mem, int attr_len,
00318                                 unsigned int *cor_offset,
00319                                 unsigned int *cor_index)
00320 {
00321 #define CISTPL_CONFIG 0x1A
00322 #define CISTPL_MANFID 0x20
00323 #define CISTPL_END 0xFF
00324 #define CIS_MAX_LEN 256
00325         u8 cis[CIS_MAX_LEN];
00326         int i, pos;
00327         unsigned int rmsz, rasz, manfid1, manfid2;
00328         struct prism2_plx_manfid *manfid;
00329 
00330         /* read CIS; it is in even offsets in the beginning of attr_mem */
00331         for (i = 0; i < CIS_MAX_LEN; i++)
00332                 cis[i] = readb(attr_mem + 2 * i);
00333         printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n",
00334                dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]);
00335 
00336         /* set reasonable defaults for Prism2 cards just in case CIS parsing
00337          * fails */
00338         *cor_offset = 0x3e0;
00339         *cor_index = 0x01;
00340         manfid1 = manfid2 = 0;
00341 
00342         pos = 0;
00343         while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
00344                 if (pos + cis[pos + 1] >= CIS_MAX_LEN)
00345                         goto cis_error;
00346 
00347                 switch (cis[pos]) {
00348                 case CISTPL_CONFIG:
00349                         if (cis[pos + 1] < 1)
00350                                 goto cis_error;
00351                         rmsz = (cis[pos + 2] & 0x3c) >> 2;
00352                         rasz = cis[pos + 2] & 0x03;
00353                         if (4 + rasz + rmsz > cis[pos + 1])
00354                                 goto cis_error;
00355                         *cor_index = cis[pos + 3] & 0x3F;
00356                         *cor_offset = 0;
00357                         for (i = 0; i <= rasz; i++)
00358                                 *cor_offset += cis[pos + 4 + i] << (8 * i);
00359                         printk(KERN_DEBUG "%s: cor_index=0x%x "
00360                                "cor_offset=0x%x\n", dev_info,
00361                                *cor_index, *cor_offset);
00362                         if (*cor_offset > attr_len) {
00363                                 printk(KERN_ERR "%s: COR offset not within "
00364                                        "attr_mem\n", dev_info);
00365                                 return -1;
00366                         }
00367                         break;
00368 
00369                 case CISTPL_MANFID:
00370                         if (cis[pos + 1] < 4)
00371                                 goto cis_error;
00372                         manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
00373                         manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
00374                         printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
00375                                dev_info, manfid1, manfid2);
00376                         break;
00377                 }
00378 
00379                 pos += cis[pos + 1] + 2;
00380         }
00381 
00382         if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
00383                 goto cis_error;
00384 
00385         for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
00386                 if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2)
00387                         return 0;
00388 
00389         printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
00390                " not supported card\n", dev_info, manfid1, manfid2);
00391         goto fail;
00392 
00393  cis_error:
00394         printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
00395 
00396  fail:
00397         if (ignore_cis) {
00398                 printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
00399                        "errors during CIS verification\n", dev_info);
00400                 return 0;
00401         }
00402         return -1;
00403 }
00404 
00405 
00406 static int prism2_plx_probe(struct pci_dev *pdev,
00407                             const struct pci_device_id *id)
00408 {
00409         unsigned int pccard_ioaddr, plx_ioaddr;
00410         unsigned long pccard_attr_mem;
00411         unsigned int pccard_attr_len;
00412         unsigned long attr_mem = 0;
00413         unsigned int cor_offset, cor_index;
00414         u32 reg;
00415         local_info_t *local = NULL;
00416         struct net_device *dev = NULL;
00417         struct hostap_interface *iface;
00418         static int cards_found /* = 0 */;
00419         int irq_registered = 0;
00420         int tmd7160;
00421 
00422         if (pci_enable_device(pdev))
00423                 return -EIO;
00424 
00425         /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
00426         tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
00427 
00428         plx_ioaddr = pci_resource_start(pdev, 1);
00429         pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
00430 
00431         if (tmd7160) {
00432                 /* TMD7160 */
00433                 attr_mem = 0; /* no access to PC Card attribute memory */
00434 
00435                 printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
00436                        "irq=%d, pccard_io=0x%x\n",
00437                        plx_ioaddr, pdev->irq, pccard_ioaddr);
00438 
00439                 cor_offset = plx_ioaddr;
00440                 cor_index = 0x04;
00441 
00442                 outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
00443                 mdelay(1);
00444                 reg = inb(plx_ioaddr);
00445                 if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
00446                         printk(KERN_ERR "%s: Error setting COR (expected="
00447                                "0x%02x, was=0x%02x)\n", dev_info,
00448                                cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
00449                         goto fail;
00450                 }
00451         } else {
00452                 /* PLX9052 */
00453                 pccard_attr_mem = pci_resource_start(pdev, 2);
00454                 pccard_attr_len = pci_resource_len(pdev, 2);
00455                 if (pccard_attr_len < PLX_MIN_ATTR_LEN)
00456                         goto fail;
00457 
00458 
00459                 attr_mem = (unsigned long) ioremap(pccard_attr_mem,
00460                                                    pccard_attr_len);
00461                 if (!attr_mem) {
00462                         printk(KERN_ERR "%s: cannot remap attr_mem\n",
00463                                dev_info);
00464                         goto fail;
00465                 }
00466 
00467                 printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
00468                        "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
00469                        pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
00470 
00471                 if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
00472                                          &cor_offset, &cor_index)) {
00473                         printk(KERN_INFO "Unknown PC Card CIS - not a "
00474                                "Prism2/2.5 card?\n");
00475                         goto fail;
00476                 }
00477 
00478                 printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
00479                        "adapter\n");
00480 
00481                 /* Write COR to enable PC Card */
00482                 writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
00483                        attr_mem + cor_offset);
00484 
00485                 /* Enable PCI interrupts if they are not already enabled */
00486                 reg = inl(plx_ioaddr + PLX_INTCSR);
00487                 printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
00488                 if (!(reg & PLX_INTCSR_PCI_INTEN)) {
00489                         outl(reg | PLX_INTCSR_PCI_INTEN,
00490                              plx_ioaddr + PLX_INTCSR);
00491                         if (!(inl(plx_ioaddr + PLX_INTCSR) &
00492                               PLX_INTCSR_PCI_INTEN)) {
00493                                 printk(KERN_WARNING "%s: Could not enable "
00494                                        "Local Interrupts\n", dev_info);
00495                                 goto fail;
00496                         }
00497                 }
00498 
00499                 reg = inl(plx_ioaddr + PLX_CNTRL);
00500                 printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
00501                        "present=%d)\n",
00502                        reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
00503                 /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
00504                  * not present; but are there really such cards in use(?) */
00505         }
00506 
00507         dev = prism2_init_local_data(&prism2_plx_funcs, cards_found);
00508         if (dev == NULL)
00509                 goto fail;
00510         iface = dev->priv;
00511         local = iface->local;
00512         cards_found++;
00513 
00514         dev->irq = pdev->irq;
00515         dev->base_addr = pccard_ioaddr;
00516         local->attr_mem = attr_mem;
00517         local->cor_offset = cor_offset;
00518 
00519         if (prism2_init_dev(local))
00520                 goto fail;
00521 
00522         pci_set_drvdata(pdev, dev);
00523 
00524         if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
00525                         dev)) {
00526                 printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
00527                 goto fail;
00528         } else
00529                 irq_registered = 1;
00530 
00531         if (prism2_hw_config(dev, 1)) {
00532                 printk(KERN_DEBUG "%s: hardware initialization failed\n",
00533                        dev_info);
00534                 goto fail;
00535         }
00536 
00537         return 0;
00538 
00539  fail:
00540         prism2_free_local_data(dev);
00541 
00542         if (irq_registered && dev)
00543                 free_irq(dev->irq, dev);
00544 
00545         if (attr_mem)
00546                 iounmap((void *) attr_mem);
00547 
00548 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4))
00549         pci_disable_device(pdev);
00550 #endif
00551 
00552         return -ENODEV;
00553 }
00554 
00555 
00556 static void prism2_plx_remove(struct pci_dev *pdev)
00557 {
00558         struct net_device *dev = pci_get_drvdata(pdev);
00559         struct hostap_interface *iface = dev->priv;
00560 
00561         /* Reset the hardware, and ensure interrupts are disabled. */
00562         prism2_plx_cor_sreset(iface->local);
00563         hfa384x_disable_interrupts(dev);
00564 
00565         if (iface->local->attr_mem)
00566                 iounmap((void *) iface->local->attr_mem);
00567         if (dev->irq)
00568                 free_irq(dev->irq, dev);
00569 
00570         prism2_free_local_data(dev);
00571 
00572 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4))
00573         pci_disable_device(pdev);
00574 #endif
00575 }
00576 
00577 
00578 MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
00579 
00580 static struct pci_driver prism2_plx_drv_id = {
00581         .name           = "prism2_plx",
00582         .id_table       = prism2_plx_id_table,
00583         .probe          = prism2_plx_probe,
00584         .remove         = prism2_plx_remove,
00585 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6))
00586         .suspend        = NULL,
00587         .resume         = NULL,
00588         .enable_wake    = NULL
00589 #else /* Linux < 2.4.6 */
00590         .suspend        = NULL,
00591         .resume         = NULL
00592 #endif /* Linux >= 2.4.6 */
00593 };
00594 
00595 
00596 static int __init init_prism2_plx(void)
00597 {
00598         printk(KERN_INFO "%s: %s\n", dev_info, version);
00599 
00600         if (pci_register_driver(&prism2_plx_drv_id) <= 0) {
00601                 printk("hostap_plx: No devices found, driver not "
00602                        "installed.\n");
00603                 pci_unregister_driver(&prism2_plx_drv_id);
00604                 return -ENODEV;
00605         }
00606 
00607         return 0;
00608 }
00609 
00610 
00611 static void __exit exit_prism2_plx(void)
00612 {
00613         pci_unregister_driver(&prism2_plx_drv_id);
00614         printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
00615 }
00616 
00617 
00618 module_init(init_prism2_plx);
00619 module_exit(exit_prism2_plx);

Generated on Mon Nov 21 15:58:09 2005 for openwifi by  doxygen 1.4.1