1#define PRISM2_PLX
2
3
4
5
6
7
8
9
10#include <linux/module.h>
11#include <linux/if.h>
12#include <linux/skbuff.h>
13#include <linux/netdevice.h>
14#include <linux/slab.h>
15#include <linux/workqueue.h>
16#include <linux/wireless.h>
17#include <net/iw_handler.h>
18
19#include <linux/ioport.h>
20#include <linux/pci.h>
21#include <asm/io.h>
22
23#include "hostap_wlan.h"
24
25
26static char *dev_info = "hostap_plx";
27
28
29MODULE_AUTHOR("Jouni Malinen");
30MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
31 "cards (PLX).");
32MODULE_LICENSE("GPL");
33
34
35static int ignore_cis;
36module_param(ignore_cis, int, 0444);
37MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
38
39
40
41struct hostap_plx_priv {
42 void __iomem *attr_mem;
43 unsigned int cor_offset;
44};
45
46
47#define PLX_MIN_ATTR_LEN 512
48#define COR_SRESET 0x80
49#define COR_LEVLREQ 0x40
50#define COR_ENABLE_FUNC 0x01
51
52#define PLX_PCIIPR 0x3d
53
54#define PLX_INTCSR 0x4c
55#define PLX_INTCSR_PCI_INTEN BIT(6)
56#define PLX_CNTRL 0x50
57#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
58
59
60#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
61
62static const struct pci_device_id prism2_plx_id_table[] = {
63 PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
64 PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
65 PLXDEV(0x126c, 0x8030, "Nortel emobility"),
66 PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
67 PLXDEV(0x1385, 0x4100, "Netgear MA301"),
68 PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
69 PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
70 PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
71 PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
72 PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
73 PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
74 PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
75 PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
76 PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
77 { 0 }
78};
79
80
81
82
83
84static struct prism2_plx_manfid {
85 u16 manfid1, manfid2;
86} prism2_plx_known_manfids[] = {
87 { 0x000b, 0x7110 } ,
88 { 0x000b, 0x7300 } ,
89 { 0x0101, 0x0777 } ,
90 { 0x0126, 0x8000 } ,
91 { 0x0138, 0x0002 } ,
92 { 0x0156, 0x0002 } ,
93 { 0x026f, 0x030b } ,
94 { 0x0274, 0x1612 } ,
95 { 0x0274, 0x1613 } ,
96 { 0x028a, 0x0002 } ,
97 { 0x0250, 0x0002 } ,
98 { 0xc250, 0x0002 } ,
99 { 0xd601, 0x0002 } ,
100 { 0xd601, 0x0005 } ,
101 { 0, 0}
102};
103
104
105#ifdef PRISM2_IO_DEBUG
106
107static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
108{
109 struct hostap_interface *iface;
110 local_info_t *local;
111 unsigned long flags;
112
113 iface = netdev_priv(dev);
114 local = iface->local;
115
116 spin_lock_irqsave(&local->lock, flags);
117 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
118 outb(v, dev->base_addr + a);
119 spin_unlock_irqrestore(&local->lock, flags);
120}
121
122static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
123{
124 struct hostap_interface *iface;
125 local_info_t *local;
126 unsigned long flags;
127 u8 v;
128
129 iface = netdev_priv(dev);
130 local = iface->local;
131
132 spin_lock_irqsave(&local->lock, flags);
133 v = inb(dev->base_addr + a);
134 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
135 spin_unlock_irqrestore(&local->lock, flags);
136 return v;
137}
138
139static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
140{
141 struct hostap_interface *iface;
142 local_info_t *local;
143 unsigned long flags;
144
145 iface = netdev_priv(dev);
146 local = iface->local;
147
148 spin_lock_irqsave(&local->lock, flags);
149 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
150 outw(v, dev->base_addr + a);
151 spin_unlock_irqrestore(&local->lock, flags);
152}
153
154static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
155{
156 struct hostap_interface *iface;
157 local_info_t *local;
158 unsigned long flags;
159 u16 v;
160
161 iface = netdev_priv(dev);
162 local = iface->local;
163
164 spin_lock_irqsave(&local->lock, flags);
165 v = inw(dev->base_addr + a);
166 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
167 spin_unlock_irqrestore(&local->lock, flags);
168 return v;
169}
170
171static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
172 u8 *buf, int wc)
173{
174 struct hostap_interface *iface;
175 local_info_t *local;
176 unsigned long flags;
177
178 iface = netdev_priv(dev);
179 local = iface->local;
180
181 spin_lock_irqsave(&local->lock, flags);
182 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
183 outsw(dev->base_addr + a, buf, wc);
184 spin_unlock_irqrestore(&local->lock, flags);
185}
186
187static inline void hfa384x_insw_debug(struct net_device *dev, int a,
188 u8 *buf, int wc)
189{
190 struct hostap_interface *iface;
191 local_info_t *local;
192 unsigned long flags;
193
194 iface = netdev_priv(dev);
195 local = iface->local;
196
197 spin_lock_irqsave(&local->lock, flags);
198 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
199 insw(dev->base_addr + a, buf, wc);
200 spin_unlock_irqrestore(&local->lock, flags);
201}
202
203#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
204#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
205#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
206#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
207#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
208#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
209
210#else
211
212#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
213#define HFA384X_INB(a) inb(dev->base_addr + (a))
214#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
215#define HFA384X_INW(a) inw(dev->base_addr + (a))
216#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
217#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
218
219#endif
220
221
222static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
223 int len)
224{
225 u16 d_off;
226 u16 *pos;
227
228 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
229 pos = (u16 *) buf;
230
231 if (len / 2)
232 HFA384X_INSW(d_off, buf, len / 2);
233 pos += len / 2;
234
235 if (len & 1)
236 *((char *) pos) = HFA384X_INB(d_off);
237
238 return 0;
239}
240
241
242static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
243{
244 u16 d_off;
245 u16 *pos;
246
247 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
248 pos = (u16 *) buf;
249
250 if (len / 2)
251 HFA384X_OUTSW(d_off, buf, len / 2);
252 pos += len / 2;
253
254 if (len & 1)
255 HFA384X_OUTB(*((char *) pos), d_off);
256
257 return 0;
258}
259
260
261
262#include "hostap_hw.c"
263
264
265static void prism2_plx_cor_sreset(local_info_t *local)
266{
267 unsigned char corsave;
268 struct hostap_plx_priv *hw_priv = local->hw_priv;
269
270 printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
271 dev_info);
272
273
274
275 if (hw_priv->attr_mem == NULL) {
276
277 corsave = inb(hw_priv->cor_offset);
278 outb(corsave | COR_SRESET, hw_priv->cor_offset);
279 mdelay(2);
280 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
281 mdelay(2);
282 } else {
283
284 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
285 writeb(corsave | COR_SRESET,
286 hw_priv->attr_mem + hw_priv->cor_offset);
287 mdelay(2);
288 writeb(corsave & ~COR_SRESET,
289 hw_priv->attr_mem + hw_priv->cor_offset);
290 mdelay(2);
291 }
292}
293
294
295static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
296{
297 unsigned char corsave;
298 struct hostap_plx_priv *hw_priv = local->hw_priv;
299
300 if (hw_priv->attr_mem == NULL) {
301
302 corsave = inb(hw_priv->cor_offset);
303 outb(corsave | COR_SRESET, hw_priv->cor_offset);
304 mdelay(10);
305 outb(hcr, hw_priv->cor_offset + 2);
306 mdelay(10);
307 outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
308 mdelay(10);
309 } else {
310
311 corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
312 writeb(corsave | COR_SRESET,
313 hw_priv->attr_mem + hw_priv->cor_offset);
314 mdelay(10);
315 writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
316 mdelay(10);
317 writeb(corsave & ~COR_SRESET,
318 hw_priv->attr_mem + hw_priv->cor_offset);
319 mdelay(10);
320 }
321}
322
323
324static struct prism2_helper_functions prism2_plx_funcs =
325{
326 .card_present = NULL,
327 .cor_sreset = prism2_plx_cor_sreset,
328 .genesis_reset = prism2_plx_genesis_reset,
329 .hw_type = HOSTAP_HW_PLX,
330};
331
332
333static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
334 unsigned int *cor_offset,
335 unsigned int *cor_index)
336{
337#define CISTPL_CONFIG 0x1A
338#define CISTPL_MANFID 0x20
339#define CISTPL_END 0xFF
340#define CIS_MAX_LEN 256
341 u8 *cis;
342 int i, pos;
343 unsigned int rmsz, rasz, manfid1, manfid2;
344 struct prism2_plx_manfid *manfid;
345
346 cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
347 if (cis == NULL)
348 return -ENOMEM;
349
350
351 for (i = 0; i < CIS_MAX_LEN; i++)
352 cis[i] = readb(attr_mem + 2 * i);
353 printk(KERN_DEBUG "%s: CIS: %6ph ...\n", dev_info, cis);
354
355
356
357 *cor_offset = 0x3e0;
358 *cor_index = 0x01;
359 manfid1 = manfid2 = 0;
360
361 pos = 0;
362 while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
363 if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN)
364 goto cis_error;
365
366 switch (cis[pos]) {
367 case CISTPL_CONFIG:
368 if (cis[pos + 1] < 2)
369 goto cis_error;
370 rmsz = (cis[pos + 2] & 0x3c) >> 2;
371 rasz = cis[pos + 2] & 0x03;
372 if (4 + rasz + rmsz > cis[pos + 1])
373 goto cis_error;
374 *cor_index = cis[pos + 3] & 0x3F;
375 *cor_offset = 0;
376 for (i = 0; i <= rasz; i++)
377 *cor_offset += cis[pos + 4 + i] << (8 * i);
378 printk(KERN_DEBUG "%s: cor_index=0x%x "
379 "cor_offset=0x%x\n", dev_info,
380 *cor_index, *cor_offset);
381 if (*cor_offset > attr_len) {
382 printk(KERN_ERR "%s: COR offset not within "
383 "attr_mem\n", dev_info);
384 kfree(cis);
385 return -1;
386 }
387 break;
388
389 case CISTPL_MANFID:
390 if (cis[pos + 1] < 4)
391 goto cis_error;
392 manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
393 manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
394 printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
395 dev_info, manfid1, manfid2);
396 break;
397 }
398
399 pos += cis[pos + 1] + 2;
400 }
401
402 if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
403 goto cis_error;
404
405 for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
406 if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
407 kfree(cis);
408 return 0;
409 }
410
411 printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
412 " not supported card\n", dev_info, manfid1, manfid2);
413 goto fail;
414
415 cis_error:
416 printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
417
418 fail:
419 kfree(cis);
420 if (ignore_cis) {
421 printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
422 "errors during CIS verification\n", dev_info);
423 return 0;
424 }
425 return -1;
426}
427
428
429static int prism2_plx_probe(struct pci_dev *pdev,
430 const struct pci_device_id *id)
431{
432 unsigned int pccard_ioaddr, plx_ioaddr;
433 unsigned long pccard_attr_mem;
434 unsigned int pccard_attr_len;
435 void __iomem *attr_mem = NULL;
436 unsigned int cor_offset = 0, cor_index = 0;
437 u32 reg;
438 local_info_t *local = NULL;
439 struct net_device *dev = NULL;
440 struct hostap_interface *iface;
441 static int cards_found ;
442 int irq_registered = 0;
443 int tmd7160;
444 struct hostap_plx_priv *hw_priv;
445
446 hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
447 if (hw_priv == NULL)
448 return -ENOMEM;
449
450 if (pci_enable_device(pdev))
451 goto err_out_free;
452
453
454 tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
455
456 plx_ioaddr = pci_resource_start(pdev, 1);
457 pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
458
459 if (tmd7160) {
460
461 attr_mem = NULL;
462
463 printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
464 "irq=%d, pccard_io=0x%x\n",
465 plx_ioaddr, pdev->irq, pccard_ioaddr);
466
467 cor_offset = plx_ioaddr;
468 cor_index = 0x04;
469
470 outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
471 mdelay(1);
472 reg = inb(plx_ioaddr);
473 if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
474 printk(KERN_ERR "%s: Error setting COR (expected="
475 "0x%02x, was=0x%02x)\n", dev_info,
476 cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
477 goto fail;
478 }
479 } else {
480
481 pccard_attr_mem = pci_resource_start(pdev, 2);
482 pccard_attr_len = pci_resource_len(pdev, 2);
483 if (pccard_attr_len < PLX_MIN_ATTR_LEN)
484 goto fail;
485
486
487 attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
488 if (attr_mem == NULL) {
489 printk(KERN_ERR "%s: cannot remap attr_mem\n",
490 dev_info);
491 goto fail;
492 }
493
494 printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
495 "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
496 pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
497
498 if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
499 &cor_offset, &cor_index)) {
500 printk(KERN_INFO "Unknown PC Card CIS - not a "
501 "Prism2/2.5 card?\n");
502 goto fail;
503 }
504
505 printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
506 "adapter\n");
507
508
509 writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
510 attr_mem + cor_offset);
511
512
513 reg = inl(plx_ioaddr + PLX_INTCSR);
514 printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
515 if (!(reg & PLX_INTCSR_PCI_INTEN)) {
516 outl(reg | PLX_INTCSR_PCI_INTEN,
517 plx_ioaddr + PLX_INTCSR);
518 if (!(inl(plx_ioaddr + PLX_INTCSR) &
519 PLX_INTCSR_PCI_INTEN)) {
520 printk(KERN_WARNING "%s: Could not enable "
521 "Local Interrupts\n", dev_info);
522 goto fail;
523 }
524 }
525
526 reg = inl(plx_ioaddr + PLX_CNTRL);
527 printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
528 "present=%d)\n",
529 reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
530
531
532 }
533
534 dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
535 &pdev->dev);
536 if (dev == NULL)
537 goto fail;
538 iface = netdev_priv(dev);
539 local = iface->local;
540 local->hw_priv = hw_priv;
541 cards_found++;
542
543 dev->irq = pdev->irq;
544 dev->base_addr = pccard_ioaddr;
545 hw_priv->attr_mem = attr_mem;
546 hw_priv->cor_offset = cor_offset;
547
548 pci_set_drvdata(pdev, dev);
549
550 if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
551 dev)) {
552 printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
553 goto fail;
554 } else
555 irq_registered = 1;
556
557 if (prism2_hw_config(dev, 1)) {
558 printk(KERN_DEBUG "%s: hardware initialization failed\n",
559 dev_info);
560 goto fail;
561 }
562
563 return hostap_hw_ready(dev);
564
565 fail:
566 if (irq_registered && dev)
567 free_irq(dev->irq, dev);
568
569 if (attr_mem)
570 iounmap(attr_mem);
571
572 pci_disable_device(pdev);
573 prism2_free_local_data(dev);
574
575 err_out_free:
576 kfree(hw_priv);
577
578 return -ENODEV;
579}
580
581
582static void prism2_plx_remove(struct pci_dev *pdev)
583{
584 struct net_device *dev;
585 struct hostap_interface *iface;
586 struct hostap_plx_priv *hw_priv;
587
588 dev = pci_get_drvdata(pdev);
589 iface = netdev_priv(dev);
590 hw_priv = iface->local->hw_priv;
591
592
593 prism2_plx_cor_sreset(iface->local);
594 hfa384x_disable_interrupts(dev);
595
596 if (hw_priv->attr_mem)
597 iounmap(hw_priv->attr_mem);
598 if (dev->irq)
599 free_irq(dev->irq, dev);
600
601 prism2_free_local_data(dev);
602 kfree(hw_priv);
603 pci_disable_device(pdev);
604}
605
606
607MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
608
609static struct pci_driver prism2_plx_driver = {
610 .name = "hostap_plx",
611 .id_table = prism2_plx_id_table,
612 .probe = prism2_plx_probe,
613 .remove = prism2_plx_remove,
614};
615
616module_pci_driver(prism2_plx_driver);
617