[TCP]: Ratelimit debugging warning.
[deliverable/linux.git] / 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);
This page took 0.053374 seconds and 5 git commands to generate.