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