3 /* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is
5 * - Host AP driver patch from james@madingley.org
6 * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc.
10 #include <linux/module.h>
11 #include <linux/init.h>
13 #include <linux/skbuff.h>
14 #include <linux/netdevice.h>
15 #include <linux/workqueue.h>
16 #include <linux/wireless.h>
17 #include <net/iw_handler.h>
19 #include <linux/ioport.h>
20 #include <linux/pci.h>
23 #include "hostap_wlan.h"
26 static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
27 static char *dev_info = "hostap_plx";
30 MODULE_AUTHOR("Jouni Malinen");
31 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
33 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
34 MODULE_LICENSE("GPL");
35 MODULE_VERSION(PRISM2_VERSION);
38 static int ignore_cis;
39 module_param(ignore_cis, int, 0444);
40 MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
43 /* struct local_info::hw_priv */
44 struct hostap_plx_priv {
45 void __iomem *attr_mem;
46 unsigned int cor_offset;
50 #define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */
51 #define COR_SRESET 0x80
52 #define COR_LEVLREQ 0x40
53 #define COR_ENABLE_FUNC 0x01
54 /* PCI Configuration Registers */
55 #define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */
56 /* Local Configuration Registers */
57 #define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */
58 #define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
59 #define PLX_CNTRL 0x50
60 #define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
63 #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
65 static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
66 PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
67 PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
68 PLXDEV(0x126c, 0x8030, "Nortel emobility"),
69 PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
70 PLXDEV(0x1385, 0x4100, "Netgear MA301"),
71 PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
72 PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
73 PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
74 PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
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"),
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
87 static struct prism2_plx_manfid {
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 */,
108 #ifdef PRISM2_IO_DEBUG
110 static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
112 struct hostap_interface *iface;
116 iface = netdev_priv(dev);
117 local = iface->local;
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);
125 static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
127 struct hostap_interface *iface;
132 iface = netdev_priv(dev);
133 local = iface->local;
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);
142 static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
144 struct hostap_interface *iface;
148 iface = netdev_priv(dev);
149 local = iface->local;
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);
157 static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
159 struct hostap_interface *iface;
164 iface = netdev_priv(dev);
165 local = iface->local;
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);
174 static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
177 struct hostap_interface *iface;
181 iface = netdev_priv(dev);
182 local = iface->local;
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);
190 static inline void hfa384x_insw_debug(struct net_device *dev, int a,
193 struct hostap_interface *iface;
197 iface = netdev_priv(dev);
198 local = iface->local;
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);
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))
213 #else /* PRISM2_IO_DEBUG */
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)
222 #endif /* PRISM2_IO_DEBUG */
225 static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
231 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
235 HFA384X_INSW(d_off, buf, len / 2);
239 *((char *) pos) = HFA384X_INB(d_off);
245 static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
250 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
254 HFA384X_OUTSW(d_off, buf, len / 2);
258 HFA384X_OUTB(*((char *) pos), d_off);
264 /* FIX: This might change at some point.. */
265 #include "hostap_hw.c"
268 static void prism2_plx_cor_sreset(local_info_t *local)
270 unsigned char corsave;
271 struct hostap_plx_priv *hw_priv = local->hw_priv;
273 printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
276 /* Set sreset bit of COR and clear it after hold time */
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);
283 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
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);
291 writeb(corsave & ~COR_SRESET,
292 hw_priv->attr_mem + hw_priv->cor_offset);
298 static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
300 unsigned char corsave;
301 struct hostap_plx_priv *hw_priv = local->hw_priv;
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);
308 outb(hcr, hw_priv->cor_offset + 2);
310 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
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);
318 writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
320 writeb(corsave & ~COR_SRESET,
321 hw_priv->attr_mem + hw_priv->cor_offset);
327 static struct prism2_helper_functions prism2_plx_funcs =
329 .card_present = NULL,
330 .cor_sreset = prism2_plx_cor_sreset,
331 .genesis_reset = prism2_plx_genesis_reset,
332 .hw_type = HOSTAP_HW_PLX,
336 static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
337 unsigned int *cor_offset,
338 unsigned int *cor_index)
340 #define CISTPL_CONFIG 0x1A
341 #define CISTPL_MANFID 0x20
342 #define CISTPL_END 0xFF
343 #define CIS_MAX_LEN 256
346 unsigned int rmsz, rasz, manfid1, manfid2;
347 struct prism2_plx_manfid *manfid;
349 cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
353 /* read CIS; it is in even offsets in the beginning of attr_mem */
354 for (i = 0; i < CIS_MAX_LEN; i++)
355 cis[i] = readb(attr_mem + 2 * i);
356 printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n",
357 dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]);
359 /* set reasonable defaults for Prism2 cards just in case CIS parsing
363 manfid1 = manfid2 = 0;
366 while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
367 if (pos + cis[pos + 1] >= CIS_MAX_LEN)
372 if (cis[pos + 1] < 2)
374 rmsz = (cis[pos + 2] & 0x3c) >> 2;
375 rasz = cis[pos + 2] & 0x03;
376 if (4 + rasz + rmsz > cis[pos + 1])
378 *cor_index = cis[pos + 3] & 0x3F;
380 for (i = 0; i <= rasz; i++)
381 *cor_offset += cis[pos + 4 + i] << (8 * i);
382 printk(KERN_DEBUG "%s: cor_index=0x%x "
383 "cor_offset=0x%x\n", dev_info,
384 *cor_index, *cor_offset);
385 if (*cor_offset > attr_len) {
386 printk(KERN_ERR "%s: COR offset not within "
387 "attr_mem\n", dev_info);
394 if (cis[pos + 1] < 5)
396 manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
397 manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
398 printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
399 dev_info, manfid1, manfid2);
403 pos += cis[pos + 1] + 2;
406 if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
409 for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
410 if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
415 printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
416 " not supported card\n", dev_info, manfid1, manfid2);
420 printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
425 printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
426 "errors during CIS verification\n", dev_info);
433 static int prism2_plx_probe(struct pci_dev *pdev,
434 const struct pci_device_id *id)
436 unsigned int pccard_ioaddr, plx_ioaddr;
437 unsigned long pccard_attr_mem;
438 unsigned int pccard_attr_len;
439 void __iomem *attr_mem = NULL;
440 unsigned int cor_offset, cor_index;
442 local_info_t *local = NULL;
443 struct net_device *dev = NULL;
444 struct hostap_interface *iface;
445 static int cards_found /* = 0 */;
446 int irq_registered = 0;
448 struct hostap_plx_priv *hw_priv;
450 hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
453 memset(hw_priv, 0, sizeof(*hw_priv));
455 if (pci_enable_device(pdev))
458 /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
459 tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
461 plx_ioaddr = pci_resource_start(pdev, 1);
462 pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
466 attr_mem = NULL; /* no access to PC Card attribute memory */
468 printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
469 "irq=%d, pccard_io=0x%x\n",
470 plx_ioaddr, pdev->irq, pccard_ioaddr);
472 cor_offset = plx_ioaddr;
475 outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
477 reg = inb(plx_ioaddr);
478 if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
479 printk(KERN_ERR "%s: Error setting COR (expected="
480 "0x%02x, was=0x%02x)\n", dev_info,
481 cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
486 pccard_attr_mem = pci_resource_start(pdev, 2);
487 pccard_attr_len = pci_resource_len(pdev, 2);
488 if (pccard_attr_len < PLX_MIN_ATTR_LEN)
492 attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
493 if (attr_mem == NULL) {
494 printk(KERN_ERR "%s: cannot remap attr_mem\n",
499 printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
500 "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
501 pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
503 if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
504 &cor_offset, &cor_index)) {
505 printk(KERN_INFO "Unknown PC Card CIS - not a "
506 "Prism2/2.5 card?\n");
510 printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
513 /* Write COR to enable PC Card */
514 writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
515 attr_mem + cor_offset);
517 /* Enable PCI interrupts if they are not already enabled */
518 reg = inl(plx_ioaddr + PLX_INTCSR);
519 printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
520 if (!(reg & PLX_INTCSR_PCI_INTEN)) {
521 outl(reg | PLX_INTCSR_PCI_INTEN,
522 plx_ioaddr + PLX_INTCSR);
523 if (!(inl(plx_ioaddr + PLX_INTCSR) &
524 PLX_INTCSR_PCI_INTEN)) {
525 printk(KERN_WARNING "%s: Could not enable "
526 "Local Interrupts\n", dev_info);
531 reg = inl(plx_ioaddr + PLX_CNTRL);
532 printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
534 reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
535 /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
536 * not present; but are there really such cards in use(?) */
539 dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
543 iface = netdev_priv(dev);
544 local = iface->local;
545 local->hw_priv = hw_priv;
548 dev->irq = pdev->irq;
549 dev->base_addr = pccard_ioaddr;
550 hw_priv->attr_mem = attr_mem;
551 hw_priv->cor_offset = cor_offset;
553 pci_set_drvdata(pdev, dev);
555 if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
557 printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
562 if (prism2_hw_config(dev, 1)) {
563 printk(KERN_DEBUG "%s: hardware initialization failed\n",
568 return hostap_hw_ready(dev);
571 if (irq_registered && dev)
572 free_irq(dev->irq, dev);
577 pci_disable_device(pdev);
578 prism2_free_local_data(dev);
587 static void prism2_plx_remove(struct pci_dev *pdev)
589 struct net_device *dev;
590 struct hostap_interface *iface;
591 struct hostap_plx_priv *hw_priv;
593 dev = pci_get_drvdata(pdev);
594 iface = netdev_priv(dev);
595 hw_priv = iface->local->hw_priv;
597 /* Reset the hardware, and ensure interrupts are disabled. */
598 prism2_plx_cor_sreset(iface->local);
599 hfa384x_disable_interrupts(dev);
601 if (hw_priv->attr_mem)
602 iounmap(hw_priv->attr_mem);
604 free_irq(dev->irq, dev);
606 prism2_free_local_data(dev);
608 pci_disable_device(pdev);
612 MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
614 static struct pci_driver prism2_plx_drv_id = {
615 .name = "hostap_plx",
616 .id_table = prism2_plx_id_table,
617 .probe = prism2_plx_probe,
618 .remove = prism2_plx_remove,
625 static int __init init_prism2_plx(void)
627 printk(KERN_INFO "%s: %s\n", dev_info, version);
629 return pci_register_driver(&prism2_plx_drv_id);
633 static void __exit exit_prism2_plx(void)
635 pci_unregister_driver(&prism2_plx_drv_id);
636 printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
640 module_init(init_prism2_plx);
641 module_exit(exit_prism2_plx);