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/config.h>
11 #include <linux/module.h>
12 #include <linux/init.h>
14 #include <linux/skbuff.h>
15 #include <linux/netdevice.h>
16 #include <linux/workqueue.h>
17 #include <linux/wireless.h>
18 #include <net/iw_handler.h>
20 #include <linux/ioport.h>
21 #include <linux/pci.h>
24 #include "hostap_wlan.h"
27 static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
28 static char *dev_info = "hostap_plx";
31 MODULE_AUTHOR("Jouni Malinen");
32 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
34 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
35 MODULE_LICENSE("GPL");
36 MODULE_VERSION(PRISM2_VERSION);
39 static int ignore_cis;
40 module_param(ignore_cis, int, 0444);
41 MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
44 /* struct local_info::hw_priv */
45 struct hostap_plx_priv {
46 void __iomem *attr_mem;
47 unsigned int cor_offset;
51 #define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */
52 #define COR_SRESET 0x80
53 #define COR_LEVLREQ 0x40
54 #define COR_ENABLE_FUNC 0x01
55 /* PCI Configuration Registers */
56 #define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */
57 /* Local Configuration Registers */
58 #define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */
59 #define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
60 #define PLX_CNTRL 0x50
61 #define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
64 #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
66 static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
67 PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
68 PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
69 PLXDEV(0x126c, 0x8030, "Nortel emobility"),
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, 0x1101, "Global Sun Tech GL24110P (?)"),
75 PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
76 PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
77 PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
78 PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
83 /* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid
84 * is not listed here, you will need to add it here to get the driver
86 static struct prism2_plx_manfid {
88 } prism2_plx_known_manfids[] = {
89 { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */,
90 { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */,
91 { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */,
92 { 0x0126, 0x8000 } /* Proxim RangeLAN */,
93 { 0x0138, 0x0002 } /* Compaq WL100 */,
94 { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */,
95 { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */,
96 { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */,
97 { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */,
98 { 0x028a, 0x0002 } /* D-Link DRC-650 */,
99 { 0x0250, 0x0002 } /* Samsung SWL2000-N */,
100 { 0xc250, 0x0002 } /* EMTAC A2424i */,
101 { 0xd601, 0x0002 } /* Z-Com XI300 */,
102 { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */,
107 #ifdef PRISM2_IO_DEBUG
109 static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
111 struct hostap_interface *iface;
115 iface = netdev_priv(dev);
116 local = iface->local;
118 spin_lock_irqsave(&local->lock, flags);
119 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
120 outb(v, dev->base_addr + a);
121 spin_unlock_irqrestore(&local->lock, flags);
124 static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
126 struct hostap_interface *iface;
131 iface = netdev_priv(dev);
132 local = iface->local;
134 spin_lock_irqsave(&local->lock, flags);
135 v = inb(dev->base_addr + a);
136 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
137 spin_unlock_irqrestore(&local->lock, flags);
141 static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
143 struct hostap_interface *iface;
147 iface = netdev_priv(dev);
148 local = iface->local;
150 spin_lock_irqsave(&local->lock, flags);
151 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
152 outw(v, dev->base_addr + a);
153 spin_unlock_irqrestore(&local->lock, flags);
156 static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
158 struct hostap_interface *iface;
163 iface = netdev_priv(dev);
164 local = iface->local;
166 spin_lock_irqsave(&local->lock, flags);
167 v = inw(dev->base_addr + a);
168 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
169 spin_unlock_irqrestore(&local->lock, flags);
173 static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
176 struct hostap_interface *iface;
180 iface = netdev_priv(dev);
181 local = iface->local;
183 spin_lock_irqsave(&local->lock, flags);
184 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
185 outsw(dev->base_addr + a, buf, wc);
186 spin_unlock_irqrestore(&local->lock, flags);
189 static inline void hfa384x_insw_debug(struct net_device *dev, int a,
192 struct hostap_interface *iface;
196 iface = netdev_priv(dev);
197 local = iface->local;
199 spin_lock_irqsave(&local->lock, flags);
200 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
201 insw(dev->base_addr + a, buf, wc);
202 spin_unlock_irqrestore(&local->lock, flags);
205 #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
206 #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
207 #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
208 #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
209 #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
210 #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
212 #else /* PRISM2_IO_DEBUG */
214 #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
215 #define HFA384X_INB(a) inb(dev->base_addr + (a))
216 #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
217 #define HFA384X_INW(a) inw(dev->base_addr + (a))
218 #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
219 #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
221 #endif /* PRISM2_IO_DEBUG */
224 static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
230 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
234 HFA384X_INSW(d_off, buf, len / 2);
238 *((char *) pos) = HFA384X_INB(d_off);
244 static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
249 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
253 HFA384X_OUTSW(d_off, buf, len / 2);
257 HFA384X_OUTB(*((char *) pos), d_off);
263 /* FIX: This might change at some point.. */
264 #include "hostap_hw.c"
267 static void prism2_plx_cor_sreset(local_info_t *local)
269 unsigned char corsave;
270 struct hostap_plx_priv *hw_priv = local->hw_priv;
272 printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
275 /* Set sreset bit of COR and clear it after hold time */
277 if (hw_priv->attr_mem == NULL) {
278 /* TMD7160 - COR at card's first I/O addr */
279 corsave = inb(hw_priv->cor_offset);
280 outb(corsave | COR_SRESET, hw_priv->cor_offset);
282 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
286 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
287 writeb(corsave | COR_SRESET,
288 hw_priv->attr_mem + hw_priv->cor_offset);
290 writeb(corsave & ~COR_SRESET,
291 hw_priv->attr_mem + hw_priv->cor_offset);
297 static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
299 unsigned char corsave;
300 struct hostap_plx_priv *hw_priv = local->hw_priv;
302 if (hw_priv->attr_mem == NULL) {
303 /* TMD7160 - COR at card's first I/O addr */
304 corsave = inb(hw_priv->cor_offset);
305 outb(corsave | COR_SRESET, hw_priv->cor_offset);
307 outb(hcr, hw_priv->cor_offset + 2);
309 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
313 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
314 writeb(corsave | COR_SRESET,
315 hw_priv->attr_mem + hw_priv->cor_offset);
317 writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
319 writeb(corsave & ~COR_SRESET,
320 hw_priv->attr_mem + hw_priv->cor_offset);
326 static struct prism2_helper_functions prism2_plx_funcs =
328 .card_present = NULL,
329 .cor_sreset = prism2_plx_cor_sreset,
330 .genesis_reset = prism2_plx_genesis_reset,
331 .hw_type = HOSTAP_HW_PLX,
335 static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
336 unsigned int *cor_offset,
337 unsigned int *cor_index)
339 #define CISTPL_CONFIG 0x1A
340 #define CISTPL_MANFID 0x20
341 #define CISTPL_END 0xFF
342 #define CIS_MAX_LEN 256
345 unsigned int rmsz, rasz, manfid1, manfid2;
346 struct prism2_plx_manfid *manfid;
348 cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
352 /* read CIS; it is in even offsets in the beginning of attr_mem */
353 for (i = 0; i < CIS_MAX_LEN; i++)
354 cis[i] = readb(attr_mem + 2 * i);
355 printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n",
356 dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]);
358 /* set reasonable defaults for Prism2 cards just in case CIS parsing
362 manfid1 = manfid2 = 0;
365 while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
366 if (pos + cis[pos + 1] >= CIS_MAX_LEN)
371 if (cis[pos + 1] < 2)
373 rmsz = (cis[pos + 2] & 0x3c) >> 2;
374 rasz = cis[pos + 2] & 0x03;
375 if (4 + rasz + rmsz > cis[pos + 1])
377 *cor_index = cis[pos + 3] & 0x3F;
379 for (i = 0; i <= rasz; i++)
380 *cor_offset += cis[pos + 4 + i] << (8 * i);
381 printk(KERN_DEBUG "%s: cor_index=0x%x "
382 "cor_offset=0x%x\n", dev_info,
383 *cor_index, *cor_offset);
384 if (*cor_offset > attr_len) {
385 printk(KERN_ERR "%s: COR offset not within "
386 "attr_mem\n", dev_info);
393 if (cis[pos + 1] < 5)
395 manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
396 manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
397 printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
398 dev_info, manfid1, manfid2);
402 pos += cis[pos + 1] + 2;
405 if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
408 for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
409 if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
414 printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
415 " not supported card\n", dev_info, manfid1, manfid2);
419 printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
424 printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
425 "errors during CIS verification\n", dev_info);
432 static int prism2_plx_probe(struct pci_dev *pdev,
433 const struct pci_device_id *id)
435 unsigned int pccard_ioaddr, plx_ioaddr;
436 unsigned long pccard_attr_mem;
437 unsigned int pccard_attr_len;
438 void __iomem *attr_mem = NULL;
439 unsigned int cor_offset, cor_index;
441 local_info_t *local = NULL;
442 struct net_device *dev = NULL;
443 struct hostap_interface *iface;
444 static int cards_found /* = 0 */;
445 int irq_registered = 0;
447 struct hostap_plx_priv *hw_priv;
449 hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
452 memset(hw_priv, 0, sizeof(*hw_priv));
454 if (pci_enable_device(pdev))
457 /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
458 tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
460 plx_ioaddr = pci_resource_start(pdev, 1);
461 pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
465 attr_mem = NULL; /* no access to PC Card attribute memory */
467 printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
468 "irq=%d, pccard_io=0x%x\n",
469 plx_ioaddr, pdev->irq, pccard_ioaddr);
471 cor_offset = plx_ioaddr;
474 outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
476 reg = inb(plx_ioaddr);
477 if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
478 printk(KERN_ERR "%s: Error setting COR (expected="
479 "0x%02x, was=0x%02x)\n", dev_info,
480 cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
485 pccard_attr_mem = pci_resource_start(pdev, 2);
486 pccard_attr_len = pci_resource_len(pdev, 2);
487 if (pccard_attr_len < PLX_MIN_ATTR_LEN)
491 attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
492 if (attr_mem == NULL) {
493 printk(KERN_ERR "%s: cannot remap attr_mem\n",
498 printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
499 "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
500 pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
502 if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
503 &cor_offset, &cor_index)) {
504 printk(KERN_INFO "Unknown PC Card CIS - not a "
505 "Prism2/2.5 card?\n");
509 printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
512 /* Write COR to enable PC Card */
513 writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
514 attr_mem + cor_offset);
516 /* Enable PCI interrupts if they are not already enabled */
517 reg = inl(plx_ioaddr + PLX_INTCSR);
518 printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
519 if (!(reg & PLX_INTCSR_PCI_INTEN)) {
520 outl(reg | PLX_INTCSR_PCI_INTEN,
521 plx_ioaddr + PLX_INTCSR);
522 if (!(inl(plx_ioaddr + PLX_INTCSR) &
523 PLX_INTCSR_PCI_INTEN)) {
524 printk(KERN_WARNING "%s: Could not enable "
525 "Local Interrupts\n", dev_info);
530 reg = inl(plx_ioaddr + PLX_CNTRL);
531 printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
533 reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
534 /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
535 * not present; but are there really such cards in use(?) */
538 dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
542 iface = netdev_priv(dev);
543 local = iface->local;
544 local->hw_priv = hw_priv;
547 dev->irq = pdev->irq;
548 dev->base_addr = pccard_ioaddr;
549 hw_priv->attr_mem = attr_mem;
550 hw_priv->cor_offset = cor_offset;
552 pci_set_drvdata(pdev, dev);
554 if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
556 printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
561 if (prism2_hw_config(dev, 1)) {
562 printk(KERN_DEBUG "%s: hardware initialization failed\n",
567 return hostap_hw_ready(dev);
570 if (irq_registered && dev)
571 free_irq(dev->irq, dev);
576 pci_disable_device(pdev);
577 prism2_free_local_data(dev);
586 static void prism2_plx_remove(struct pci_dev *pdev)
588 struct net_device *dev;
589 struct hostap_interface *iface;
590 struct hostap_plx_priv *hw_priv;
592 dev = pci_get_drvdata(pdev);
593 iface = netdev_priv(dev);
594 hw_priv = iface->local->hw_priv;
596 /* Reset the hardware, and ensure interrupts are disabled. */
597 prism2_plx_cor_sreset(iface->local);
598 hfa384x_disable_interrupts(dev);
600 if (hw_priv->attr_mem)
601 iounmap(hw_priv->attr_mem);
603 free_irq(dev->irq, dev);
605 prism2_free_local_data(dev);
607 pci_disable_device(pdev);
611 MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
613 static struct pci_driver prism2_plx_drv_id = {
614 .name = "hostap_plx",
615 .id_table = prism2_plx_id_table,
616 .probe = prism2_plx_probe,
617 .remove = prism2_plx_remove,
624 static int __init init_prism2_plx(void)
626 printk(KERN_INFO "%s: %s\n", dev_info, version);
628 return pci_register_driver(&prism2_plx_drv_id);
632 static void __exit exit_prism2_plx(void)
634 pci_unregister_driver(&prism2_plx_drv_id);
635 printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
639 module_init(init_prism2_plx);
640 module_exit(exit_prism2_plx);