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