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