1 // SPDX-License-Identifier: GPL-2.0-only
4 /* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is
7 * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc.
11 #include <linux/module.h>
13 #include <linux/skbuff.h>
14 #include <linux/netdevice.h>
15 #include <linux/slab.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 *dev_info = "hostap_plx";
30 MODULE_AUTHOR("Jouni Malinen");
31 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
33 MODULE_LICENSE("GPL");
36 static int ignore_cis;
37 module_param(ignore_cis, int, 0444);
38 MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
41 /* struct local_info::hw_priv */
42 struct hostap_plx_priv {
43 void __iomem *attr_mem;
44 unsigned int cor_offset;
48 #define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */
49 #define COR_SRESET 0x80
50 #define COR_LEVLREQ 0x40
51 #define COR_ENABLE_FUNC 0x01
52 /* PCI Configuration Registers */
53 #define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */
54 /* Local Configuration Registers */
55 #define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */
56 #define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
57 #define PLX_CNTRL 0x50
58 #define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
61 #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
63 static const struct pci_device_id prism2_plx_id_table[] = {
64 PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
65 PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
66 PLXDEV(0x126c, 0x8030, "Nortel emobility"),
67 PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
68 PLXDEV(0x1385, 0x4100, "Netgear MA301"),
69 PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
70 PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
71 PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
72 PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
73 PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
74 PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
75 PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
76 PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
77 PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
82 /* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid
83 * is not listed here, you will need to add it here to get the driver
85 static struct prism2_plx_manfid {
87 } prism2_plx_known_manfids[] = {
88 { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */,
89 { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */,
90 { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */,
91 { 0x0126, 0x8000 } /* Proxim RangeLAN */,
92 { 0x0138, 0x0002 } /* Compaq WL100 */,
93 { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */,
94 { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */,
95 { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */,
96 { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */,
97 { 0x028a, 0x0002 } /* D-Link DRC-650 */,
98 { 0x0250, 0x0002 } /* Samsung SWL2000-N */,
99 { 0xc250, 0x0002 } /* EMTAC A2424i */,
100 { 0xd601, 0x0002 } /* Z-Com XI300 */,
101 { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */,
106 #ifdef PRISM2_IO_DEBUG
108 static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
110 struct hostap_interface *iface;
114 iface = netdev_priv(dev);
115 local = iface->local;
117 spin_lock_irqsave(&local->lock, flags);
118 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
119 outb(v, dev->base_addr + a);
120 spin_unlock_irqrestore(&local->lock, flags);
123 static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
125 struct hostap_interface *iface;
130 iface = netdev_priv(dev);
131 local = iface->local;
133 spin_lock_irqsave(&local->lock, flags);
134 v = inb(dev->base_addr + a);
135 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
136 spin_unlock_irqrestore(&local->lock, flags);
140 static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
142 struct hostap_interface *iface;
146 iface = netdev_priv(dev);
147 local = iface->local;
149 spin_lock_irqsave(&local->lock, flags);
150 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
151 outw(v, dev->base_addr + a);
152 spin_unlock_irqrestore(&local->lock, flags);
155 static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
157 struct hostap_interface *iface;
162 iface = netdev_priv(dev);
163 local = iface->local;
165 spin_lock_irqsave(&local->lock, flags);
166 v = inw(dev->base_addr + a);
167 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
168 spin_unlock_irqrestore(&local->lock, flags);
172 static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
175 struct hostap_interface *iface;
179 iface = netdev_priv(dev);
180 local = iface->local;
182 spin_lock_irqsave(&local->lock, flags);
183 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
184 outsw(dev->base_addr + a, buf, wc);
185 spin_unlock_irqrestore(&local->lock, flags);
188 static inline void hfa384x_insw_debug(struct net_device *dev, int a,
191 struct hostap_interface *iface;
195 iface = netdev_priv(dev);
196 local = iface->local;
198 spin_lock_irqsave(&local->lock, flags);
199 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
200 insw(dev->base_addr + a, buf, wc);
201 spin_unlock_irqrestore(&local->lock, flags);
204 #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
205 #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
206 #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
207 #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
208 #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
209 #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
211 #else /* PRISM2_IO_DEBUG */
213 #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
214 #define HFA384X_INB(a) inb(dev->base_addr + (a))
215 #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
216 #define HFA384X_INW(a) inw(dev->base_addr + (a))
217 #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
218 #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
220 #endif /* PRISM2_IO_DEBUG */
223 static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
229 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
233 HFA384X_INSW(d_off, buf, len / 2);
237 *((char *) pos) = HFA384X_INB(d_off);
243 static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
248 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
252 HFA384X_OUTSW(d_off, buf, len / 2);
256 HFA384X_OUTB(*((char *) pos), d_off);
262 /* FIX: This might change at some point.. */
263 #include "hostap_hw.c"
266 static void prism2_plx_cor_sreset(local_info_t *local)
268 unsigned char corsave;
269 struct hostap_plx_priv *hw_priv = local->hw_priv;
271 printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
274 /* Set sreset bit of COR and clear it after hold time */
276 if (hw_priv->attr_mem == NULL) {
277 /* TMD7160 - COR at card's first I/O addr */
278 corsave = inb(hw_priv->cor_offset);
279 outb(corsave | COR_SRESET, hw_priv->cor_offset);
281 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
285 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
286 writeb(corsave | COR_SRESET,
287 hw_priv->attr_mem + hw_priv->cor_offset);
289 writeb(corsave & ~COR_SRESET,
290 hw_priv->attr_mem + hw_priv->cor_offset);
296 static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
298 unsigned char corsave;
299 struct hostap_plx_priv *hw_priv = local->hw_priv;
301 if (hw_priv->attr_mem == NULL) {
302 /* TMD7160 - COR at card's first I/O addr */
303 corsave = inb(hw_priv->cor_offset);
304 outb(corsave | COR_SRESET, hw_priv->cor_offset);
306 outb(hcr, hw_priv->cor_offset + 2);
308 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
312 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
313 writeb(corsave | COR_SRESET,
314 hw_priv->attr_mem + hw_priv->cor_offset);
316 writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
318 writeb(corsave & ~COR_SRESET,
319 hw_priv->attr_mem + hw_priv->cor_offset);
325 static struct prism2_helper_functions prism2_plx_funcs =
327 .card_present = NULL,
328 .cor_sreset = prism2_plx_cor_sreset,
329 .genesis_reset = prism2_plx_genesis_reset,
330 .hw_type = HOSTAP_HW_PLX,
334 static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
335 unsigned int *cor_offset,
336 unsigned int *cor_index)
338 #define CISTPL_CONFIG 0x1A
339 #define CISTPL_MANFID 0x20
340 #define CISTPL_END 0xFF
341 #define CIS_MAX_LEN 256
344 unsigned int rmsz, rasz, manfid1, manfid2;
345 struct prism2_plx_manfid *manfid;
347 cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
351 /* read CIS; it is in even offsets in the beginning of attr_mem */
352 for (i = 0; i < CIS_MAX_LEN; i++)
353 cis[i] = readb(attr_mem + 2 * i);
354 printk(KERN_DEBUG "%s: CIS: %6ph ...\n", dev_info, cis);
356 /* set reasonable defaults for Prism2 cards just in case CIS parsing
360 manfid1 = manfid2 = 0;
363 while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
364 if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN)
369 if (cis[pos + 1] < 2)
371 rmsz = (cis[pos + 2] & 0x3c) >> 2;
372 rasz = cis[pos + 2] & 0x03;
373 if (4 + rasz + rmsz > cis[pos + 1])
375 *cor_index = cis[pos + 3] & 0x3F;
377 for (i = 0; i <= rasz; i++)
378 *cor_offset += cis[pos + 4 + i] << (8 * i);
379 printk(KERN_DEBUG "%s: cor_index=0x%x "
380 "cor_offset=0x%x\n", dev_info,
381 *cor_index, *cor_offset);
382 if (*cor_offset > attr_len) {
383 printk(KERN_ERR "%s: COR offset not within "
384 "attr_mem\n", dev_info);
391 if (cis[pos + 1] < 4)
393 manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
394 manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
395 printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
396 dev_info, manfid1, manfid2);
400 pos += cis[pos + 1] + 2;
403 if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
406 for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
407 if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
412 printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
413 " not supported card\n", dev_info, manfid1, manfid2);
417 printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
422 printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
423 "errors during CIS verification\n", dev_info);
430 static int prism2_plx_probe(struct pci_dev *pdev,
431 const struct pci_device_id *id)
433 unsigned int pccard_ioaddr, plx_ioaddr;
434 unsigned long pccard_attr_mem;
435 unsigned int pccard_attr_len;
436 void __iomem *attr_mem = NULL;
437 unsigned int cor_offset = 0, cor_index = 0;
439 local_info_t *local = NULL;
440 struct net_device *dev = NULL;
441 struct hostap_interface *iface;
442 static int cards_found /* = 0 */;
443 int irq_registered = 0;
445 struct hostap_plx_priv *hw_priv;
447 hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
451 if (pci_enable_device(pdev))
454 /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
455 tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
457 plx_ioaddr = pci_resource_start(pdev, 1);
458 pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
462 attr_mem = NULL; /* no access to PC Card attribute memory */
464 printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
465 "irq=%d, pccard_io=0x%x\n",
466 plx_ioaddr, pdev->irq, pccard_ioaddr);
468 cor_offset = plx_ioaddr;
471 outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
473 reg = inb(plx_ioaddr);
474 if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
475 printk(KERN_ERR "%s: Error setting COR (expected="
476 "0x%02x, was=0x%02x)\n", dev_info,
477 cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
482 pccard_attr_mem = pci_resource_start(pdev, 2);
483 pccard_attr_len = pci_resource_len(pdev, 2);
484 if (pccard_attr_len < PLX_MIN_ATTR_LEN)
488 attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
489 if (attr_mem == NULL) {
490 printk(KERN_ERR "%s: cannot remap attr_mem\n",
495 printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
496 "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
497 pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
499 if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
500 &cor_offset, &cor_index)) {
501 printk(KERN_INFO "Unknown PC Card CIS - not a "
502 "Prism2/2.5 card?\n");
506 printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
509 /* Write COR to enable PC Card */
510 writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
511 attr_mem + cor_offset);
513 /* Enable PCI interrupts if they are not already enabled */
514 reg = inl(plx_ioaddr + PLX_INTCSR);
515 printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
516 if (!(reg & PLX_INTCSR_PCI_INTEN)) {
517 outl(reg | PLX_INTCSR_PCI_INTEN,
518 plx_ioaddr + PLX_INTCSR);
519 if (!(inl(plx_ioaddr + PLX_INTCSR) &
520 PLX_INTCSR_PCI_INTEN)) {
521 printk(KERN_WARNING "%s: Could not enable "
522 "Local Interrupts\n", dev_info);
527 reg = inl(plx_ioaddr + PLX_CNTRL);
528 printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
530 reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
531 /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
532 * not present; but are there really such cards in use(?) */
535 dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
539 iface = netdev_priv(dev);
540 local = iface->local;
541 local->hw_priv = hw_priv;
544 dev->irq = pdev->irq;
545 dev->base_addr = pccard_ioaddr;
546 hw_priv->attr_mem = attr_mem;
547 hw_priv->cor_offset = cor_offset;
549 pci_set_drvdata(pdev, dev);
551 if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
553 printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
558 if (prism2_hw_config(dev, 1)) {
559 printk(KERN_DEBUG "%s: hardware initialization failed\n",
564 return hostap_hw_ready(dev);
567 if (irq_registered && dev)
568 free_irq(dev->irq, dev);
573 pci_disable_device(pdev);
574 prism2_free_local_data(dev);
583 static void prism2_plx_remove(struct pci_dev *pdev)
585 struct net_device *dev;
586 struct hostap_interface *iface;
587 struct hostap_plx_priv *hw_priv;
589 dev = pci_get_drvdata(pdev);
590 iface = netdev_priv(dev);
591 hw_priv = iface->local->hw_priv;
593 /* Reset the hardware, and ensure interrupts are disabled. */
594 prism2_plx_cor_sreset(iface->local);
595 hfa384x_disable_interrupts(dev);
597 if (hw_priv->attr_mem)
598 iounmap(hw_priv->attr_mem);
600 free_irq(dev->irq, dev);
602 prism2_free_local_data(dev);
604 pci_disable_device(pdev);
608 MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
610 static struct pci_driver prism2_plx_driver = {
611 .name = "hostap_plx",
612 .id_table = prism2_plx_id_table,
613 .probe = prism2_plx_probe,
614 .remove = prism2_plx_remove,
617 module_pci_driver(prism2_plx_driver);