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/version.h>
12 #include <linux/module.h>
13 #include <linux/init.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>
21 #include <linux/ioport.h>
22 #include <linux/pci.h>
25 #include "hostap_wlan.h"
28 static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
29 static char *dev_info = "hostap_plx";
32 MODULE_AUTHOR("Jouni Malinen");
33 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
35 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
36 MODULE_LICENSE("GPL");
37 MODULE_VERSION(PRISM2_VERSION);
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");
45 /* struct local_info::hw_priv */
46 struct hostap_plx_priv {
47 void __iomem *attr_mem;
48 unsigned int cor_offset;
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)
65 #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
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"),
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,
333 .genesis_reset = prism2_plx_genesis_reset,
334 .hw_type = HOSTAP_HW_PLX,
338 static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
339 unsigned int *cor_offset,
340 unsigned int *cor_index)
342 #define CISTPL_CONFIG 0x1A
343 #define CISTPL_MANFID 0x20
344 #define CISTPL_END 0xFF
345 #define CIS_MAX_LEN 256
348 unsigned int rmsz, rasz, manfid1, manfid2;
349 struct prism2_plx_manfid *manfid;
351 cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
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]);
361 /* set reasonable defaults for Prism2 cards just in case CIS parsing
365 manfid1 = manfid2 = 0;
368 while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
369 if (pos + cis[pos + 1] >= CIS_MAX_LEN)
374 if (cis[pos + 1] < 1)
376 rmsz = (cis[pos + 2] & 0x3c) >> 2;
377 rasz = cis[pos + 2] & 0x03;
378 if (4 + rasz + rmsz > cis[pos + 1])
380 *cor_index = cis[pos + 3] & 0x3F;
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);
396 if (cis[pos + 1] < 4)
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);
405 pos += cis[pos + 1] + 2;
408 if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
411 for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
412 if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
417 printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
418 " not supported card\n", dev_info, manfid1, manfid2);
422 printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
427 printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
428 "errors during CIS verification\n", dev_info);
435 static int prism2_plx_probe(struct pci_dev *pdev,
436 const struct pci_device_id *id)
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;
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;
450 struct hostap_plx_priv *hw_priv;
452 hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
455 memset(hw_priv, 0, sizeof(*hw_priv));
457 if (pci_enable_device(pdev))
460 /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
461 tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
463 plx_ioaddr = pci_resource_start(pdev, 1);
464 pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
468 attr_mem = NULL; /* no access to PC Card attribute memory */
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);
474 cor_offset = plx_ioaddr;
477 outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
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);
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)
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",
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);
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");
512 printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
515 /* Write COR to enable PC Card */
516 writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
517 attr_mem + cor_offset);
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);
533 reg = inl(plx_ioaddr + PLX_CNTRL);
534 printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
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(?) */
541 dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
545 iface = netdev_priv(dev);
546 local = iface->local;
547 local->hw_priv = hw_priv;
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;
555 pci_set_drvdata(pdev, dev);
557 if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
559 printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
564 if (prism2_hw_config(dev, 1)) {
565 printk(KERN_DEBUG "%s: hardware initialization failed\n",
570 return hostap_hw_ready(dev);
575 local->hw_priv = NULL;
576 prism2_free_local_data(dev);
578 if (irq_registered && dev)
579 free_irq(dev->irq, dev);
584 pci_disable_device(pdev);
590 static void prism2_plx_remove(struct pci_dev *pdev)
592 struct net_device *dev;
593 struct hostap_interface *iface;
594 struct hostap_plx_priv *hw_priv;
596 dev = pci_get_drvdata(pdev);
597 iface = netdev_priv(dev);
598 hw_priv = iface->local->hw_priv;
600 /* Reset the hardware, and ensure interrupts are disabled. */
601 prism2_plx_cor_sreset(iface->local);
602 hfa384x_disable_interrupts(dev);
604 if (hw_priv->attr_mem)
605 iounmap(hw_priv->attr_mem);
607 free_irq(dev->irq, dev);
609 kfree(iface->local->hw_priv);
610 iface->local->hw_priv = NULL;
611 prism2_free_local_data(dev);
612 pci_disable_device(pdev);
616 MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
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,
629 static int __init init_prism2_plx(void)
631 printk(KERN_INFO "%s: %s\n", dev_info, version);
633 return pci_register_driver(&prism2_plx_drv_id);
637 static void __exit exit_prism2_plx(void)
639 pci_unregister_driver(&prism2_plx_drv_id);
640 printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
644 module_init(init_prism2_plx);
645 module_exit(exit_prism2_plx);