1 #define WLAN_HOSTIF WLAN_PLX
3 #include "prism2mgmt.c"
7 #define PLX_ATTR_SIZE 0x1000 /* Attribute memory size - 4K bytes */
8 #define COR_OFFSET 0x3e0 /* COR attribute offset of Prism2 PC card */
9 #define COR_VALUE 0x41 /* Enable PC card with irq in level trigger */
10 #define PLX_INTCSR 0x4c /* Interrupt Control and Status Register */
11 #define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */
12 #define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */
14 /* 3Com 3CRW777A (PLX) board ID */
15 #define PCIVENDOR_3COM 0x10B7
16 #define PCIDEVICE_AIRCONNECT 0x7770
18 /* Eumitcom PCI WL11000 PCI Adapter (PLX) board device+vendor ID */
19 #define PCIVENDOR_EUMITCOM 0x1638UL
20 #define PCIDEVICE_WL11000 0x1100UL
22 /* Global Sun Tech GL24110P PCI Adapter (PLX) board device+vendor ID */
23 #define PCIVENDOR_GLOBALSUN 0x16abUL
24 #define PCIDEVICE_GL24110P 0x1101UL
25 #define PCIDEVICE_GL24110P_ALT 0x1102UL
27 /* Netgear MA301 PCI Adapter (PLX) board device+vendor ID */
28 #define PCIVENDOR_NETGEAR 0x1385UL
29 #define PCIDEVICE_MA301 0x4100UL
31 /* US Robotics USR2410 PCI Adapter (PLX) board device+vendor ID */
32 #define PCIVENDOR_USROBOTICS 0x16ecUL
33 #define PCIDEVICE_USR2410 0x3685UL
35 /* Linksys WPC11 card with the WDT11 adapter (PLX) board device+vendor ID */
36 #define PCIVENDOR_Linksys 0x16abUL
37 #define PCIDEVICE_Wpc11Wdt11 0x1102UL
39 /* National Datacomm Corp SOHOware Netblaster II PCI */
40 #define PCIVENDOR_NDC 0x15e8UL
41 #define PCIDEVICE_NCP130_PLX 0x0130UL
42 #define PCIDEVICE_NCP130_ASIC 0x0131UL
44 /* NDC NCP130_PLX is also sold by Corega. Their name is CGWLPCIA11 */
45 #define PCIVENDOR_COREGA PCIVENDOR_NDC
46 #define PCIDEVICE_CGWLPCIA11 PCIDEVICE_NCP130_PLX
48 /* PCI Class & Sub-Class code, Network-'Other controller' */
49 #define PCI_CLASS_NETWORK_OTHERS 0x280
51 /*----------------------------------------------------------------
54 * Probe routine called when a PCI device w/ matching ID is found.
55 * This PLX implementation uses the following map:
58 * BAR2: PCMCIA attribute memory
59 * BAR3: PCMCIA i/o space
60 * Here's the sequence:
61 * - Allocate the PCI resources.
62 * - Read the PCMCIA attribute memory to make sure we have a WLAN card
63 * - Reset the MAC using the PCMCIA COR
64 * - Initialize the netdev and wlan data
65 * - Initialize the MAC
68 * pdev ptr to pci device structure containing info about
70 * id ptr to the device id entry that matched this device.
82 ----------------------------------------------------------------*/
86 const struct pci_device_id *id)
90 phys_t pccard_attr_mem;
91 unsigned int pccard_attr_len;
92 void __iomem *attr_mem = NULL;
94 wlandevice_t *wlandev = NULL;
99 if (pci_enable_device(pdev))
102 /* TMC7160 boards are special */
103 if ((pdev->vendor == PCIVENDOR_NDC) &&
104 (pdev->device == PCIDEVICE_NCP130_ASIC)) {
108 pccard_ioaddr = pci_resource_start(pdev, 1);
110 outb(0x45, pccard_ioaddr);
111 delay = jiffies + 1*HZ;
112 while (time_before(jiffies, delay));
114 if (inb(pccard_ioaddr) != 0x45) {
115 WLAN_LOG_ERROR("Initialize the TMC7160 failed. (0x%x)\n", inb(pccard_ioaddr));
119 pccard_ioaddr = pci_resource_start(pdev, 2);
122 WLAN_LOG_INFO("NDC NCP130 with TMC716(ASIC) PCI interface device found at io:0x%x, irq:%d\n", pccard_ioaddr, pdev->irq);
126 /* Collect the resource requirements */
127 pccard_attr_mem = pci_resource_start(pdev, 2);
128 pccard_attr_len = pci_resource_len(pdev, 2);
129 if (pccard_attr_len < PLX_MIN_ATTR_LEN)
132 pccard_ioaddr = pci_resource_start(pdev, 3);
134 /* bjoern: We need to tell the card to enable interrupts, in
135 * case the serial eprom didn't do this already. See the
136 * PLX9052 data book, p8-1 and 8-24 for reference.
137 * [MSM]: This bit of code came from the orinoco_cs driver.
139 plx_addr = pci_resource_start(pdev, 1);
142 regic = inl(plx_addr+PLX_INTCSR);
143 if(regic & PLX_INTCSR_INTEN) {
145 "%s: Local Interrupt already enabled\n", dev_info);
147 regic |= PLX_INTCSR_INTEN;
148 outl(regic, plx_addr+PLX_INTCSR);
149 regic = inl(plx_addr+PLX_INTCSR);
150 if(!(regic & PLX_INTCSR_INTEN)) {
152 "%s: Couldn't enable Local Interrupts\n",
158 /* These assignments are here in case of future mappings for
159 * io space and irq that might be similar to ioremap
161 if (!request_mem_region(pccard_attr_mem, pci_resource_len(pdev, 2), "Prism2")) {
162 WLAN_LOG_ERROR("%s: Couldn't reserve PCI memory region\n", dev_info);
166 attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
168 WLAN_LOG_INFO("A PLX PCI/PCMCIA interface device found, "
169 "phymem:0x%llx, phyio=0x%x, irq:%d, "
171 (unsigned long long)pccard_attr_mem, pccard_ioaddr, pdev->irq,
172 (unsigned long)attr_mem);
174 /* Verify whether PC card is present.
175 * [MSM] This needs improvement, the right thing to do is
176 * probably to walk the CIS looking for the vendor and product
177 * IDs. It would be nice if this could be tied in with the
178 * etc/pcmcia/wlan-ng.conf file. Any volunteers? ;-)
181 readb(attr_mem + 0) != 0x01 || readb(attr_mem + 2) != 0x03 ||
182 readb(attr_mem + 4) != 0x00 || readb(attr_mem + 6) != 0x00 ||
183 readb(attr_mem + 8) != 0xFF || readb(attr_mem + 10) != 0x17 ||
184 readb(attr_mem + 12) != 0x04 || readb(attr_mem + 14) != 0x67) {
185 WLAN_LOG_ERROR("Prism2 PC card CIS is invalid.\n");
188 WLAN_LOG_INFO("A PCMCIA WLAN adapter was found.\n");
190 /* Write COR to enable PC card */
191 writeb(COR_VALUE, attr_mem + COR_OFFSET);
192 reg = readb(attr_mem + COR_OFFSET);
197 * Now do everything the same as a PCI device
198 * [MSM] TODO: We could probably factor this out of pcmcia/pci/plx
199 * and perhaps usb. Perhaps a task for another day.......
202 if ((wlandev = create_wlan()) == NULL) {
203 WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
210 if ( wlan_setup(wlandev) != 0 ) {
211 WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
216 /* Setup netdevice's ability to report resources
217 * Note: the netdevice was allocated by wlan_setup()
219 wlandev->netdev->irq = pdev->irq;
220 wlandev->netdev->base_addr = pccard_ioaddr;
221 wlandev->netdev->mem_start = (unsigned long)attr_mem;
222 wlandev->netdev->mem_end = (unsigned long)attr_mem + pci_resource_len(pdev, 0);
224 /* Initialize the hw data */
225 hfa384x_create(hw, wlandev->netdev->irq, pccard_ioaddr, attr_mem);
226 hw->wlandev = wlandev;
228 /* Register the wlandev, this gets us a name and registers the
231 SET_MODULE_OWNER(wlandev->netdev);
232 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
233 SET_NETDEV_DEV(wlandev->netdev, &(pdev->dev));
235 if ( register_wlandev(wlandev) != 0 ) {
236 WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info);
242 /* TODO: Move this and an irq test into an hfa384x_testif() routine.
244 outw(PRISM2STA_MAGIC, HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
245 reg=inw( HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
246 if ( reg != PRISM2STA_MAGIC ) {
247 WLAN_LOG_ERROR("MAC register access test failed!\n");
253 /* Do a chip-level reset on the MAC */
254 if (prism2_doreset) {
255 result = hfa384x_corereset(hw,
256 prism2_reset_holdtime,
257 prism2_reset_settletime, 0);
259 unregister_wlandev(wlandev);
262 "%s: hfa384x_corereset() failed.\n",
269 pci_set_drvdata(pdev, wlandev);
271 /* Shouldn't actually hook up the IRQ until we
272 * _know_ things are alright. A test routine would help.
274 request_irq(wlandev->netdev->irq, hfa384x_interrupt,
275 SA_SHIRQ, wlandev->name, wlandev);
277 wlandev->msdstate = WLAN_MSD_HWPRESENT;
285 pci_set_drvdata(pdev, NULL);
286 if (wlandev) kfree(wlandev);
288 if (attr_mem) iounmap(attr_mem);
289 pci_release_regions(pdev);
290 pci_disable_device(pdev);
297 static void __devexit prism2sta_remove_plx(struct pci_dev *pdev)
299 wlandevice_t *wlandev;
302 wlandev = (wlandevice_t *) pci_get_drvdata(pdev);
305 p80211netdev_hwremoved(wlandev);
308 prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
311 free_irq(pdev->irq, wlandev);
313 unregister_wlandev(wlandev);
315 /* free local stuff */
321 iounmap((void __iomem *)wlandev->netdev->mem_start);
322 wlan_unsetup(wlandev);
324 pci_release_regions(pdev);
325 pci_disable_device(pdev);
326 pci_set_drvdata(pdev, NULL);
331 static struct pci_device_id plx_id_tbl[] = {
333 PCIVENDOR_EUMITCOM, PCIDEVICE_WL11000,
334 PCI_ANY_ID, PCI_ANY_ID,
336 /* Driver data, we just put the name here */
337 (unsigned long)"Eumitcom WL11000 PCI(PLX) card"
340 PCIVENDOR_GLOBALSUN, PCIDEVICE_GL24110P,
341 PCI_ANY_ID, PCI_ANY_ID,
343 /* Driver data, we just put the name here */
344 (unsigned long)"Global Sun Tech GL24110P PCI(PLX) card"
347 PCIVENDOR_GLOBALSUN, PCIDEVICE_GL24110P_ALT,
348 PCI_ANY_ID, PCI_ANY_ID,
350 /* Driver data, we just put the name here */
351 (unsigned long)"Global Sun Tech GL24110P PCI(PLX) card"
354 PCIVENDOR_NETGEAR, PCIDEVICE_MA301,
355 PCI_ANY_ID, PCI_ANY_ID,
357 /* Driver data, we just put the name here */
358 (unsigned long)"Global Sun Tech GL24110P PCI(PLX) card"
361 PCIVENDOR_USROBOTICS, PCIDEVICE_USR2410,
362 PCI_ANY_ID, PCI_ANY_ID,
364 /* Driver data, we just put the name here */
365 (unsigned long)"US Robotics USR2410 PCI(PLX) card"
368 PCIVENDOR_Linksys, PCIDEVICE_Wpc11Wdt11,
369 PCI_ANY_ID, PCI_ANY_ID,
371 /* Driver data, we just put the name here */
372 (unsigned long)"Linksys WPC11 with WDT11 PCI(PLX) adapter"
375 PCIVENDOR_NDC, PCIDEVICE_NCP130_PLX,
376 PCI_ANY_ID, PCI_ANY_ID,
378 /* Driver data, we just put the name here */
379 (unsigned long)"NDC Netblaster II PCI(PLX)"
382 PCIVENDOR_NDC, PCIDEVICE_NCP130_ASIC,
383 PCI_ANY_ID, PCI_ANY_ID,
385 /* Driver data, we just put the name here */
386 (unsigned long)"NDC Netblaster II PCI(TMC7160)"
389 PCIVENDOR_3COM, PCIDEVICE_AIRCONNECT,
390 PCI_ANY_ID, PCI_ANY_ID,
392 /* Driver data, we just put the name here */
393 (unsigned long)"3Com AirConnect PCI 802.11b 11Mb/s WLAN Controller"
400 MODULE_DEVICE_TABLE(pci, plx_id_tbl);
402 /* Function declared here because of ptr reference below */
403 static int __devinit prism2sta_probe_plx(struct pci_dev *pdev,
404 const struct pci_device_id *);
405 static void __devexit prism2sta_remove_plx(struct pci_dev *pdev);
407 static struct pci_driver prism2_plx_drv_id = {
408 .name = "prism2_plx",
409 .id_table = plx_id_tbl,
410 .probe = prism2sta_probe_plx,
411 .remove = prism2sta_remove_plx,
413 .suspend = prism2sta_suspend_pci,
414 .resume = prism2sta_resume_pci,
420 static int __init prism2plx_init(void)
422 WLAN_LOG_NOTICE("%s Loaded\n", version);
423 return pci_module_init(&prism2_plx_drv_id);
426 static void __exit prism2plx_cleanup(void)
428 pci_unregister_driver(&prism2_plx_drv_id);
431 module_init(prism2plx_init);
432 module_exit(prism2plx_cleanup);
437 int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis)
441 #define COR_OFFSET 0x3e0 /* COR attribute offset of Prism2 PC card */
442 #define COR_VALUE 0x41 /* Enable PC card with irq in level trigger */
444 #define HCR_OFFSET 0x3e2 /* HCR attribute offset of Prism2 PC card */
449 WLAN_LOG_DEBUG(3, "Doing reset via direct COR access.\n");
452 corsave = readb(hw->membase + COR_OFFSET);
453 /* Write reset bit (BIT7) */
454 writeb(corsave | BIT7, hw->membase + COR_OFFSET);
455 /* Hold for holdtime */
459 writeb(genesis, hw->membase + HCR_OFFSET);
460 /* Hold for holdtime */
464 /* Clear reset bit */
465 writeb(corsave & ~BIT7, hw->membase + COR_OFFSET);
466 /* Wait for settletime */
468 /* Set non-reset bits back what they were */
469 writeb(corsave, hw->membase + COR_OFFSET);