0001
0002 #define PRISM2_PLX
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/if.h>
0013 #include <linux/skbuff.h>
0014 #include <linux/netdevice.h>
0015 #include <linux/slab.h>
0016 #include <linux/workqueue.h>
0017 #include <linux/wireless.h>
0018 #include <net/iw_handler.h>
0019
0020 #include <linux/ioport.h>
0021 #include <linux/pci.h>
0022 #include <asm/io.h>
0023
0024 #include "hostap_wlan.h"
0025
0026
0027 static char *dev_info = "hostap_plx";
0028
0029
0030 MODULE_AUTHOR("Jouni Malinen");
0031 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
0032 "cards (PLX).");
0033 MODULE_LICENSE("GPL");
0034
0035
0036 static int ignore_cis;
0037 module_param(ignore_cis, int, 0444);
0038 MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
0039
0040
0041
0042 struct hostap_plx_priv {
0043 void __iomem *attr_mem;
0044 unsigned int cor_offset;
0045 };
0046
0047
0048 #define PLX_MIN_ATTR_LEN 512
0049 #define COR_SRESET 0x80
0050 #define COR_LEVLREQ 0x40
0051 #define COR_ENABLE_FUNC 0x01
0052
0053 #define PLX_PCIIPR 0x3d
0054
0055 #define PLX_INTCSR 0x4c
0056 #define PLX_INTCSR_PCI_INTEN BIT(6)
0057 #define PLX_CNTRL 0x50
0058 #define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
0059
0060
0061 #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
0062
0063 static const struct pci_device_id prism2_plx_id_table[] = {
0064 PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
0065 PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
0066 PLXDEV(0x126c, 0x8030, "Nortel emobility"),
0067 PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
0068 PLXDEV(0x1385, 0x4100, "Netgear MA301"),
0069 PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
0070 PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
0071 PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
0072 PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
0073 PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
0074 PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
0075 PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
0076 PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
0077 PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
0078 { 0 }
0079 };
0080
0081
0082
0083
0084
0085 static struct prism2_plx_manfid {
0086 u16 manfid1, manfid2;
0087 } prism2_plx_known_manfids[] = {
0088 { 0x000b, 0x7110 } ,
0089 { 0x000b, 0x7300 } ,
0090 { 0x0101, 0x0777 } ,
0091 { 0x0126, 0x8000 } ,
0092 { 0x0138, 0x0002 } ,
0093 { 0x0156, 0x0002 } ,
0094 { 0x026f, 0x030b } ,
0095 { 0x0274, 0x1612 } ,
0096 { 0x0274, 0x1613 } ,
0097 { 0x028a, 0x0002 } ,
0098 { 0x0250, 0x0002 } ,
0099 { 0xc250, 0x0002 } ,
0100 { 0xd601, 0x0002 } ,
0101 { 0xd601, 0x0005 } ,
0102 { 0, 0}
0103 };
0104
0105
0106 #ifdef PRISM2_IO_DEBUG
0107
0108 static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
0109 {
0110 struct hostap_interface *iface;
0111 local_info_t *local;
0112 unsigned long flags;
0113
0114 iface = netdev_priv(dev);
0115 local = iface->local;
0116
0117 spin_lock_irqsave(&local->lock, flags);
0118 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
0119 outb(v, dev->base_addr + a);
0120 spin_unlock_irqrestore(&local->lock, flags);
0121 }
0122
0123 static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
0124 {
0125 struct hostap_interface *iface;
0126 local_info_t *local;
0127 unsigned long flags;
0128 u8 v;
0129
0130 iface = netdev_priv(dev);
0131 local = iface->local;
0132
0133 spin_lock_irqsave(&local->lock, flags);
0134 v = inb(dev->base_addr + a);
0135 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
0136 spin_unlock_irqrestore(&local->lock, flags);
0137 return v;
0138 }
0139
0140 static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
0141 {
0142 struct hostap_interface *iface;
0143 local_info_t *local;
0144 unsigned long flags;
0145
0146 iface = netdev_priv(dev);
0147 local = iface->local;
0148
0149 spin_lock_irqsave(&local->lock, flags);
0150 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
0151 outw(v, dev->base_addr + a);
0152 spin_unlock_irqrestore(&local->lock, flags);
0153 }
0154
0155 static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
0156 {
0157 struct hostap_interface *iface;
0158 local_info_t *local;
0159 unsigned long flags;
0160 u16 v;
0161
0162 iface = netdev_priv(dev);
0163 local = iface->local;
0164
0165 spin_lock_irqsave(&local->lock, flags);
0166 v = inw(dev->base_addr + a);
0167 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
0168 spin_unlock_irqrestore(&local->lock, flags);
0169 return v;
0170 }
0171
0172 static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
0173 u8 *buf, int wc)
0174 {
0175 struct hostap_interface *iface;
0176 local_info_t *local;
0177 unsigned long flags;
0178
0179 iface = netdev_priv(dev);
0180 local = iface->local;
0181
0182 spin_lock_irqsave(&local->lock, flags);
0183 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
0184 outsw(dev->base_addr + a, buf, wc);
0185 spin_unlock_irqrestore(&local->lock, flags);
0186 }
0187
0188 static inline void hfa384x_insw_debug(struct net_device *dev, int a,
0189 u8 *buf, int wc)
0190 {
0191 struct hostap_interface *iface;
0192 local_info_t *local;
0193 unsigned long flags;
0194
0195 iface = netdev_priv(dev);
0196 local = iface->local;
0197
0198 spin_lock_irqsave(&local->lock, flags);
0199 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
0200 insw(dev->base_addr + a, buf, wc);
0201 spin_unlock_irqrestore(&local->lock, flags);
0202 }
0203
0204 #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
0205 #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
0206 #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
0207 #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
0208 #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
0209 #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
0210
0211 #else
0212
0213 #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
0214 #define HFA384X_INB(a) inb(dev->base_addr + (a))
0215 #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
0216 #define HFA384X_INW(a) inw(dev->base_addr + (a))
0217 #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
0218 #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
0219
0220 #endif
0221
0222
0223 static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
0224 int len)
0225 {
0226 u16 d_off;
0227 u16 *pos;
0228
0229 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
0230 pos = (u16 *) buf;
0231
0232 if (len / 2)
0233 HFA384X_INSW(d_off, buf, len / 2);
0234 pos += len / 2;
0235
0236 if (len & 1)
0237 *((char *) pos) = HFA384X_INB(d_off);
0238
0239 return 0;
0240 }
0241
0242
0243 static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
0244 {
0245 u16 d_off;
0246 u16 *pos;
0247
0248 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
0249 pos = (u16 *) buf;
0250
0251 if (len / 2)
0252 HFA384X_OUTSW(d_off, buf, len / 2);
0253 pos += len / 2;
0254
0255 if (len & 1)
0256 HFA384X_OUTB(*((char *) pos), d_off);
0257
0258 return 0;
0259 }
0260
0261
0262
0263 #include "hostap_hw.c"
0264
0265
0266 static void prism2_plx_cor_sreset(local_info_t *local)
0267 {
0268 unsigned char corsave;
0269 struct hostap_plx_priv *hw_priv = local->hw_priv;
0270
0271 printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
0272 dev_info);
0273
0274
0275
0276 if (hw_priv->attr_mem == NULL) {
0277
0278 corsave = inb(hw_priv->cor_offset);
0279 outb(corsave | COR_SRESET, hw_priv->cor_offset);
0280 mdelay(2);
0281 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
0282 mdelay(2);
0283 } else {
0284
0285 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
0286 writeb(corsave | COR_SRESET,
0287 hw_priv->attr_mem + hw_priv->cor_offset);
0288 mdelay(2);
0289 writeb(corsave & ~COR_SRESET,
0290 hw_priv->attr_mem + hw_priv->cor_offset);
0291 mdelay(2);
0292 }
0293 }
0294
0295
0296 static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
0297 {
0298 unsigned char corsave;
0299 struct hostap_plx_priv *hw_priv = local->hw_priv;
0300
0301 if (hw_priv->attr_mem == NULL) {
0302
0303 corsave = inb(hw_priv->cor_offset);
0304 outb(corsave | COR_SRESET, hw_priv->cor_offset);
0305 mdelay(10);
0306 outb(hcr, hw_priv->cor_offset + 2);
0307 mdelay(10);
0308 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
0309 mdelay(10);
0310 } else {
0311
0312 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
0313 writeb(corsave | COR_SRESET,
0314 hw_priv->attr_mem + hw_priv->cor_offset);
0315 mdelay(10);
0316 writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
0317 mdelay(10);
0318 writeb(corsave & ~COR_SRESET,
0319 hw_priv->attr_mem + hw_priv->cor_offset);
0320 mdelay(10);
0321 }
0322 }
0323
0324
0325 static struct prism2_helper_functions prism2_plx_funcs =
0326 {
0327 .card_present = NULL,
0328 .cor_sreset = prism2_plx_cor_sreset,
0329 .genesis_reset = prism2_plx_genesis_reset,
0330 .hw_type = HOSTAP_HW_PLX,
0331 };
0332
0333
0334 static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
0335 unsigned int *cor_offset,
0336 unsigned int *cor_index)
0337 {
0338 #define CISTPL_CONFIG 0x1A
0339 #define CISTPL_MANFID 0x20
0340 #define CISTPL_END 0xFF
0341 #define CIS_MAX_LEN 256
0342 u8 *cis;
0343 int i, pos;
0344 unsigned int rmsz, rasz, manfid1, manfid2;
0345 struct prism2_plx_manfid *manfid;
0346
0347 cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
0348 if (cis == NULL)
0349 return -ENOMEM;
0350
0351
0352 for (i = 0; i < CIS_MAX_LEN; i++)
0353 cis[i] = readb(attr_mem + 2 * i);
0354 printk(KERN_DEBUG "%s: CIS: %6ph ...\n", dev_info, cis);
0355
0356
0357
0358 *cor_offset = 0x3e0;
0359 *cor_index = 0x01;
0360 manfid1 = manfid2 = 0;
0361
0362 pos = 0;
0363 while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
0364 if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN)
0365 goto cis_error;
0366
0367 switch (cis[pos]) {
0368 case CISTPL_CONFIG:
0369 if (cis[pos + 1] < 2)
0370 goto cis_error;
0371 rmsz = (cis[pos + 2] & 0x3c) >> 2;
0372 rasz = cis[pos + 2] & 0x03;
0373 if (4 + rasz + rmsz > cis[pos + 1])
0374 goto cis_error;
0375 *cor_index = cis[pos + 3] & 0x3F;
0376 *cor_offset = 0;
0377 for (i = 0; i <= rasz; i++)
0378 *cor_offset += cis[pos + 4 + i] << (8 * i);
0379 printk(KERN_DEBUG "%s: cor_index=0x%x "
0380 "cor_offset=0x%x\n", dev_info,
0381 *cor_index, *cor_offset);
0382 if (*cor_offset > attr_len) {
0383 printk(KERN_ERR "%s: COR offset not within "
0384 "attr_mem\n", dev_info);
0385 kfree(cis);
0386 return -1;
0387 }
0388 break;
0389
0390 case CISTPL_MANFID:
0391 if (cis[pos + 1] < 4)
0392 goto cis_error;
0393 manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
0394 manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
0395 printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
0396 dev_info, manfid1, manfid2);
0397 break;
0398 }
0399
0400 pos += cis[pos + 1] + 2;
0401 }
0402
0403 if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
0404 goto cis_error;
0405
0406 for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
0407 if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
0408 kfree(cis);
0409 return 0;
0410 }
0411
0412 printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
0413 " not supported card\n", dev_info, manfid1, manfid2);
0414 goto fail;
0415
0416 cis_error:
0417 printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
0418
0419 fail:
0420 kfree(cis);
0421 if (ignore_cis) {
0422 printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
0423 "errors during CIS verification\n", dev_info);
0424 return 0;
0425 }
0426 return -1;
0427 }
0428
0429
0430 static int prism2_plx_probe(struct pci_dev *pdev,
0431 const struct pci_device_id *id)
0432 {
0433 unsigned int pccard_ioaddr, plx_ioaddr;
0434 unsigned long pccard_attr_mem;
0435 unsigned int pccard_attr_len;
0436 void __iomem *attr_mem = NULL;
0437 unsigned int cor_offset = 0, cor_index = 0;
0438 u32 reg;
0439 local_info_t *local = NULL;
0440 struct net_device *dev = NULL;
0441 struct hostap_interface *iface;
0442 static int cards_found ;
0443 int irq_registered = 0;
0444 int tmd7160;
0445 struct hostap_plx_priv *hw_priv;
0446
0447 hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
0448 if (hw_priv == NULL)
0449 return -ENOMEM;
0450
0451 if (pci_enable_device(pdev))
0452 goto err_out_free;
0453
0454
0455 tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
0456
0457 plx_ioaddr = pci_resource_start(pdev, 1);
0458 pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
0459
0460 if (tmd7160) {
0461
0462 attr_mem = NULL;
0463
0464 printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
0465 "irq=%d, pccard_io=0x%x\n",
0466 plx_ioaddr, pdev->irq, pccard_ioaddr);
0467
0468 cor_offset = plx_ioaddr;
0469 cor_index = 0x04;
0470
0471 outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
0472 mdelay(1);
0473 reg = inb(plx_ioaddr);
0474 if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
0475 printk(KERN_ERR "%s: Error setting COR (expected="
0476 "0x%02x, was=0x%02x)\n", dev_info,
0477 cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
0478 goto fail;
0479 }
0480 } else {
0481
0482 pccard_attr_mem = pci_resource_start(pdev, 2);
0483 pccard_attr_len = pci_resource_len(pdev, 2);
0484 if (pccard_attr_len < PLX_MIN_ATTR_LEN)
0485 goto fail;
0486
0487
0488 attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
0489 if (attr_mem == NULL) {
0490 printk(KERN_ERR "%s: cannot remap attr_mem\n",
0491 dev_info);
0492 goto fail;
0493 }
0494
0495 printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
0496 "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
0497 pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
0498
0499 if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
0500 &cor_offset, &cor_index)) {
0501 printk(KERN_INFO "Unknown PC Card CIS - not a "
0502 "Prism2/2.5 card?\n");
0503 goto fail;
0504 }
0505
0506 printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
0507 "adapter\n");
0508
0509
0510 writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
0511 attr_mem + cor_offset);
0512
0513
0514 reg = inl(plx_ioaddr + PLX_INTCSR);
0515 printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
0516 if (!(reg & PLX_INTCSR_PCI_INTEN)) {
0517 outl(reg | PLX_INTCSR_PCI_INTEN,
0518 plx_ioaddr + PLX_INTCSR);
0519 if (!(inl(plx_ioaddr + PLX_INTCSR) &
0520 PLX_INTCSR_PCI_INTEN)) {
0521 printk(KERN_WARNING "%s: Could not enable "
0522 "Local Interrupts\n", dev_info);
0523 goto fail;
0524 }
0525 }
0526
0527 reg = inl(plx_ioaddr + PLX_CNTRL);
0528 printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
0529 "present=%d)\n",
0530 reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
0531
0532
0533 }
0534
0535 dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
0536 &pdev->dev);
0537 if (dev == NULL)
0538 goto fail;
0539 iface = netdev_priv(dev);
0540 local = iface->local;
0541 local->hw_priv = hw_priv;
0542 cards_found++;
0543
0544 dev->irq = pdev->irq;
0545 dev->base_addr = pccard_ioaddr;
0546 hw_priv->attr_mem = attr_mem;
0547 hw_priv->cor_offset = cor_offset;
0548
0549 pci_set_drvdata(pdev, dev);
0550
0551 if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
0552 dev)) {
0553 printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
0554 goto fail;
0555 } else
0556 irq_registered = 1;
0557
0558 if (prism2_hw_config(dev, 1)) {
0559 printk(KERN_DEBUG "%s: hardware initialization failed\n",
0560 dev_info);
0561 goto fail;
0562 }
0563
0564 return hostap_hw_ready(dev);
0565
0566 fail:
0567 if (irq_registered && dev)
0568 free_irq(dev->irq, dev);
0569
0570 if (attr_mem)
0571 iounmap(attr_mem);
0572
0573 pci_disable_device(pdev);
0574 prism2_free_local_data(dev);
0575
0576 err_out_free:
0577 kfree(hw_priv);
0578
0579 return -ENODEV;
0580 }
0581
0582
0583 static void prism2_plx_remove(struct pci_dev *pdev)
0584 {
0585 struct net_device *dev;
0586 struct hostap_interface *iface;
0587 struct hostap_plx_priv *hw_priv;
0588
0589 dev = pci_get_drvdata(pdev);
0590 iface = netdev_priv(dev);
0591 hw_priv = iface->local->hw_priv;
0592
0593
0594 prism2_plx_cor_sreset(iface->local);
0595 hfa384x_disable_interrupts(dev);
0596
0597 if (hw_priv->attr_mem)
0598 iounmap(hw_priv->attr_mem);
0599 if (dev->irq)
0600 free_irq(dev->irq, dev);
0601
0602 prism2_free_local_data(dev);
0603 kfree(hw_priv);
0604 pci_disable_device(pdev);
0605 }
0606
0607
0608 MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
0609
0610 static struct pci_driver prism2_plx_driver = {
0611 .name = "hostap_plx",
0612 .id_table = prism2_plx_id_table,
0613 .probe = prism2_plx_probe,
0614 .remove = prism2_plx_remove,
0615 };
0616
0617 module_pci_driver(prism2_plx_driver);