/spare/repo/netdev-2.6 branch 'ieee80211'
[linux-2.6] / drivers / net / wireless / hostap / hostap_plx.c
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
28 static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
29 static char *dev_info = "hostap_plx";
30
31
32 MODULE_AUTHOR("Jouni Malinen");
33 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
34                    "cards (PLX).");
35 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
36 MODULE_LICENSE("GPL");
37 MODULE_VERSION(PRISM2_VERSION);
38
39
40 static int ignore_cis;
41 module_param(ignore_cis, int, 0444);
42 MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
43
44
45 /* struct local_info::hw_priv */
46 struct hostap_plx_priv {
47         void __iomem *attr_mem;
48         unsigned int cor_offset;
49 };
50
51
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
67 static 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. */
87 static 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
110 static 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
125 static 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
142 static 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
157 static 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
174 static 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
190 static 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
225 static 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
245 static 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
268 static void prism2_plx_cor_sreset(local_info_t *local)
269 {
270         unsigned char corsave;
271         struct hostap_plx_priv *hw_priv = local->hw_priv;
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
278         if (hw_priv->attr_mem == NULL) {
279                 /* TMD7160 - COR at card's first I/O addr */
280                 corsave = inb(hw_priv->cor_offset);
281                 outb(corsave | COR_SRESET, hw_priv->cor_offset);
282                 mdelay(2);
283                 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
284                 mdelay(2);
285         } else {
286                 /* PLX9052 */
287                 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
288                 writeb(corsave | COR_SRESET,
289                        hw_priv->attr_mem + hw_priv->cor_offset);
290                 mdelay(2);
291                 writeb(corsave & ~COR_SRESET,
292                        hw_priv->attr_mem + hw_priv->cor_offset);
293                 mdelay(2);
294         }
295 }
296
297
298 static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
299 {
300         unsigned char corsave;
301         struct hostap_plx_priv *hw_priv = local->hw_priv;
302
303         if (hw_priv->attr_mem == NULL) {
304                 /* TMD7160 - COR at card's first I/O addr */
305                 corsave = inb(hw_priv->cor_offset);
306                 outb(corsave | COR_SRESET, hw_priv->cor_offset);
307                 mdelay(10);
308                 outb(hcr, hw_priv->cor_offset + 2);
309                 mdelay(10);
310                 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
311                 mdelay(10);
312         } else {
313                 /* PLX9052 */
314                 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
315                 writeb(corsave | COR_SRESET,
316                        hw_priv->attr_mem + hw_priv->cor_offset);
317                 mdelay(10);
318                 writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
319                 mdelay(10);
320                 writeb(corsave & ~COR_SRESET,
321                        hw_priv->attr_mem + hw_priv->cor_offset);
322                 mdelay(10);
323         }
324 }
325
326
327 static 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
338 static 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
435 static 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;
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));
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
541         dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
542                                      &pdev->dev);
543         if (dev == NULL)
544                 goto fail;
545         iface = netdev_priv(dev);
546         local = iface->local;
547         local->hw_priv = hw_priv;
548         cards_found++;
549
550         dev->irq = pdev->irq;
551         dev->base_addr = pccard_ioaddr;
552         hw_priv->attr_mem = attr_mem;
553         hw_priv->cor_offset = cor_offset;
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:
573         kfree(hw_priv);
574         if (local)
575                 local->hw_priv = NULL;
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
590 static void prism2_plx_remove(struct pci_dev *pdev)
591 {
592         struct net_device *dev;
593         struct hostap_interface *iface;
594         struct hostap_plx_priv *hw_priv;
595
596         dev = pci_get_drvdata(pdev);
597         iface = netdev_priv(dev);
598         hw_priv = iface->local->hw_priv;
599
600         /* Reset the hardware, and ensure interrupts are disabled. */
601         prism2_plx_cor_sreset(iface->local);
602         hfa384x_disable_interrupts(dev);
603
604         if (hw_priv->attr_mem)
605                 iounmap(hw_priv->attr_mem);
606         if (dev->irq)
607                 free_irq(dev->irq, dev);
608
609         kfree(iface->local->hw_priv);
610         iface->local->hw_priv = NULL;
611         prism2_free_local_data(dev);
612         pci_disable_device(pdev);
613 }
614
615
616 MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
617
618 static 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
629 static 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
637 static 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
644 module_init(init_prism2_plx);
645 module_exit(exit_prism2_plx);