]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/staging/wlan-ng/prism2_plx.c
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
[linux-2.6-omap-h63xx.git] / drivers / staging / wlan-ng / prism2_plx.c
1 #define WLAN_HOSTIF WLAN_PLX
2 #include "hfa384x.c"
3 #include "prism2mgmt.c"
4 #include "prism2mib.c"
5 #include "prism2sta.c"
6
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 */
13
14 /* 3Com 3CRW777A (PLX) board ID */
15 #define PCIVENDOR_3COM       0x10B7
16 #define PCIDEVICE_AIRCONNECT 0x7770
17
18 /* Eumitcom PCI WL11000 PCI Adapter (PLX) board device+vendor ID */
19 #define PCIVENDOR_EUMITCOM      0x1638UL
20 #define PCIDEVICE_WL11000       0x1100UL
21
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
26
27 /* Netgear MA301 PCI Adapter (PLX) board device+vendor ID */
28 #define PCIVENDOR_NETGEAR       0x1385UL
29 #define PCIDEVICE_MA301         0x4100UL
30
31 /* US Robotics USR2410 PCI Adapter (PLX) board device+vendor ID */
32 #define PCIVENDOR_USROBOTICS    0x16ecUL
33 #define PCIDEVICE_USR2410       0x3685UL
34
35 /* Linksys WPC11 card with the WDT11 adapter (PLX) board device+vendor ID */
36 #define PCIVENDOR_Linksys       0x16abUL
37 #define PCIDEVICE_Wpc11Wdt11    0x1102UL
38
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
43
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
47
48 /* PCI Class & Sub-Class code, Network-'Other controller' */
49 #define PCI_CLASS_NETWORK_OTHERS 0x280
50
51 /*----------------------------------------------------------------
52 * prism2sta_probe_plx
53 *
54 * Probe routine called when a PCI device w/ matching ID is found.
55 * This PLX implementation uses the following map:
56 *   BAR0: Unused
57 *   BAR1: ????
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
66 *
67 * Arguments:
68 *       pdev            ptr to pci device structure containing info about
69 *                       pci configuration.
70 *       id              ptr to the device id entry that matched this device.
71 *
72 * Returns:
73 *       zero            - success
74 *       negative        - failed
75 *
76 * Side effects:
77 *
78 *
79 * Call context:
80 *       process thread
81 *
82 ----------------------------------------------------------------*/
83 static int __devinit
84 prism2sta_probe_plx(
85         struct pci_dev                  *pdev,
86         const struct pci_device_id      *id)
87 {
88         int             result;
89         phys_t  pccard_ioaddr;
90         phys_t  pccard_attr_mem;
91         unsigned int    pccard_attr_len;
92         void __iomem *attr_mem = NULL;
93         UINT32          plx_addr;
94         wlandevice_t    *wlandev = NULL;
95         hfa384x_t       *hw = NULL;
96         int             reg;
97         u32             regic;
98
99         if (pci_enable_device(pdev))
100                 return -EIO;
101
102         /* TMC7160 boards are special */
103         if ((pdev->vendor == PCIVENDOR_NDC) &&
104             (pdev->device == PCIDEVICE_NCP130_ASIC)) {
105                 unsigned long delay;
106
107                 pccard_attr_mem = 0;
108                 pccard_ioaddr = pci_resource_start(pdev, 1);
109
110                 outb(0x45, pccard_ioaddr);
111                 delay = jiffies + 1*HZ;
112                 while (time_before(jiffies, delay));
113
114                 if (inb(pccard_ioaddr) != 0x45) {
115                         WLAN_LOG_ERROR("Initialize the TMC7160 failed. (0x%x)\n", inb(pccard_ioaddr));
116                         return -EIO;
117                 }
118
119                 pccard_ioaddr = pci_resource_start(pdev, 2);
120                 prism2_doreset = 0;
121
122                 WLAN_LOG_INFO("NDC NCP130 with TMC716(ASIC) PCI interface device found at io:0x%x, irq:%d\n", pccard_ioaddr, pdev->irq);
123                 goto init;
124         }
125
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)
130                 return -EIO;
131
132         pccard_ioaddr = pci_resource_start(pdev, 3);
133
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.
138          */
139         plx_addr = pci_resource_start(pdev, 1);
140
141         regic = 0;
142         regic = inl(plx_addr+PLX_INTCSR);
143         if(regic & PLX_INTCSR_INTEN) {
144                 WLAN_LOG_DEBUG(1,
145                         "%s: Local Interrupt already enabled\n", dev_info);
146         } else {
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)) {
151                         WLAN_LOG_ERROR(
152                                 "%s: Couldn't enable Local Interrupts\n",
153                                 dev_info);
154                         return -EIO;
155                 }
156         }
157
158         /* These assignments are here in case of future mappings for
159          * io space and irq that might be similar to ioremap
160          */
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);
163                 return -EIO;
164         }
165
166         attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
167
168         WLAN_LOG_INFO("A PLX PCI/PCMCIA interface device found, "
169                 "phymem:0x%llx, phyio=0x%x, irq:%d, "
170                 "mem: 0x%lx\n",
171                 (unsigned long long)pccard_attr_mem, pccard_ioaddr, pdev->irq,
172                 (unsigned long)attr_mem);
173
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?  ;-)
179          */
180         if (
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");
186                 return -EIO;
187         }
188         WLAN_LOG_INFO("A PCMCIA WLAN adapter was found.\n");
189
190         /* Write COR to enable PC card */
191         writeb(COR_VALUE, attr_mem + COR_OFFSET);
192         reg = readb(attr_mem + COR_OFFSET);
193
194  init:
195
196         /*
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.......
200          */
201
202         if ((wlandev = create_wlan()) == NULL) {
203                 WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
204                 result = -EIO;
205                 goto failed;
206         }
207
208         hw = wlandev->priv;
209
210         if ( wlan_setup(wlandev) != 0 ) {
211                 WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
212                 result = -EIO;
213                 goto failed;
214         }
215
216         /* Setup netdevice's ability to report resources
217          * Note: the netdevice was allocated by wlan_setup()
218          */
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);
223
224         /* Initialize the hw data */
225         hfa384x_create(hw, wlandev->netdev->irq, pccard_ioaddr, attr_mem);
226         hw->wlandev = wlandev;
227
228         /* Register the wlandev, this gets us a name and registers the
229          * linux netdevice.
230          */
231         SET_MODULE_OWNER(wlandev->netdev);
232 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
233        SET_NETDEV_DEV(wlandev->netdev, &(pdev->dev));
234 #endif
235         if ( register_wlandev(wlandev) != 0 ) {
236                 WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info);
237                 result = -EIO;
238                 goto failed;
239         }
240
241 #if 0
242         /* TODO: Move this and an irq test into an hfa384x_testif() routine.
243          */
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");
248                 result = -EIO;
249                 goto failed;
250         }
251 #endif
252
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);
258                 if (result != 0) {
259                         unregister_wlandev(wlandev);
260                         hfa384x_destroy(hw);
261                         WLAN_LOG_ERROR(
262                                 "%s: hfa384x_corereset() failed.\n",
263                                 dev_info);
264                         result = -EIO;
265                         goto failed;
266                 }
267         }
268
269         pci_set_drvdata(pdev, wlandev);
270
271         /* Shouldn't actually hook up the IRQ until we
272          * _know_ things are alright.  A test routine would help.
273          */
274         request_irq(wlandev->netdev->irq, hfa384x_interrupt,
275                 SA_SHIRQ, wlandev->name, wlandev);
276
277         wlandev->msdstate = WLAN_MSD_HWPRESENT;
278
279         result = 0;
280
281         goto done;
282
283  failed:
284
285         pci_set_drvdata(pdev, NULL);
286         if (wlandev)    kfree(wlandev);
287         if (hw)         kfree(hw);
288         if (attr_mem)        iounmap(attr_mem);
289         pci_release_regions(pdev);
290         pci_disable_device(pdev);
291
292  done:
293         DBFEXIT;
294         return result;
295 }
296
297 static void __devexit prism2sta_remove_plx(struct pci_dev *pdev)
298 {
299         wlandevice_t            *wlandev;
300         hfa384x_t               *hw;
301
302         wlandev = (wlandevice_t *) pci_get_drvdata(pdev);
303         hw = wlandev->priv;
304
305         p80211netdev_hwremoved(wlandev);
306
307         /* reset hardware */
308         prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
309
310         if (pdev->irq)
311                 free_irq(pdev->irq, wlandev);
312
313         unregister_wlandev(wlandev);
314
315         /* free local stuff */
316         if (hw) {
317                 hfa384x_destroy(hw);
318                 kfree(hw);
319         }
320
321         iounmap((void __iomem *)wlandev->netdev->mem_start);
322         wlan_unsetup(wlandev);
323
324         pci_release_regions(pdev);
325         pci_disable_device(pdev);
326         pci_set_drvdata(pdev, NULL);
327
328         kfree(wlandev);
329 }
330
331 static struct pci_device_id plx_id_tbl[] = {
332         {
333                 PCIVENDOR_EUMITCOM, PCIDEVICE_WL11000,
334                 PCI_ANY_ID, PCI_ANY_ID,
335                 0, 0,
336                 /* Driver data, we just put the name here */
337                 (unsigned long)"Eumitcom WL11000 PCI(PLX) card"
338         },
339         {
340                 PCIVENDOR_GLOBALSUN, PCIDEVICE_GL24110P,
341                 PCI_ANY_ID, PCI_ANY_ID,
342                 0, 0,
343                 /* Driver data, we just put the name here */
344                 (unsigned long)"Global Sun Tech GL24110P PCI(PLX) card"
345         },
346         {
347                 PCIVENDOR_GLOBALSUN, PCIDEVICE_GL24110P_ALT,
348                 PCI_ANY_ID, PCI_ANY_ID,
349                 0, 0,
350                 /* Driver data, we just put the name here */
351                 (unsigned long)"Global Sun Tech GL24110P PCI(PLX) card"
352         },
353         {
354                 PCIVENDOR_NETGEAR, PCIDEVICE_MA301,
355                 PCI_ANY_ID, PCI_ANY_ID,
356                 0, 0,
357                 /* Driver data, we just put the name here */
358                 (unsigned long)"Global Sun Tech GL24110P PCI(PLX) card"
359         },
360         {
361                 PCIVENDOR_USROBOTICS, PCIDEVICE_USR2410,
362                 PCI_ANY_ID, PCI_ANY_ID,
363                 0, 0,
364                 /* Driver data, we just put the name here */
365                 (unsigned long)"US Robotics USR2410 PCI(PLX) card"
366         },
367         {
368                 PCIVENDOR_Linksys, PCIDEVICE_Wpc11Wdt11,
369                 PCI_ANY_ID, PCI_ANY_ID,
370                 0, 0,
371                 /* Driver data, we just put the name here */
372                 (unsigned long)"Linksys WPC11 with WDT11 PCI(PLX) adapter"
373         },
374         {
375                 PCIVENDOR_NDC, PCIDEVICE_NCP130_PLX,
376                 PCI_ANY_ID, PCI_ANY_ID,
377                 0, 0,
378                 /* Driver data, we just put the name here */
379                 (unsigned long)"NDC Netblaster II PCI(PLX)"
380         },
381         {
382                 PCIVENDOR_NDC, PCIDEVICE_NCP130_ASIC,
383                 PCI_ANY_ID, PCI_ANY_ID,
384                 0, 0,
385                 /* Driver data, we just put the name here */
386                 (unsigned long)"NDC Netblaster II PCI(TMC7160)"
387         },
388         {
389                 PCIVENDOR_3COM, PCIDEVICE_AIRCONNECT,
390                 PCI_ANY_ID, PCI_ANY_ID,
391                 0, 0,
392                 /* Driver data, we just put the name here */
393                 (unsigned long)"3Com AirConnect PCI 802.11b 11Mb/s WLAN Controller"
394         },
395         {
396                 0, 0, 0, 0, 0, 0, 0
397         }
398 };
399
400 MODULE_DEVICE_TABLE(pci, plx_id_tbl);
401
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);
406
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,
412 #ifdef CONFIG_PM
413         .suspend = prism2sta_suspend_pci,
414         .resume = prism2sta_resume_pci,
415 #endif
416 };
417
418 #ifdef MODULE
419
420 static int __init prism2plx_init(void)
421 {
422         WLAN_LOG_NOTICE("%s Loaded\n", version);
423         return pci_module_init(&prism2_plx_drv_id);
424 };
425
426 static void __exit prism2plx_cleanup(void)
427 {
428         pci_unregister_driver(&prism2_plx_drv_id);
429 };
430
431 module_init(prism2plx_init);
432 module_exit(prism2plx_cleanup);
433
434 #endif // MODULE
435
436
437 int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis)
438 {
439         int             result = 0;
440
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 */
443
444 #define HCR_OFFSET      0x3e2   /* HCR attribute offset of Prism2 PC card */
445
446         UINT8           corsave;
447         DBFENTER;
448
449         WLAN_LOG_DEBUG(3, "Doing reset via direct COR access.\n");
450
451         /* Collect COR */
452         corsave = readb(hw->membase + COR_OFFSET);
453         /* Write reset bit (BIT7) */
454         writeb(corsave | BIT7, hw->membase + COR_OFFSET);
455         /* Hold for holdtime */
456         mdelay(holdtime);
457
458         if (genesis) {
459                 writeb(genesis, hw->membase + HCR_OFFSET);
460                 /* Hold for holdtime */
461                 mdelay(holdtime);
462         }
463
464         /* Clear reset bit */
465         writeb(corsave & ~BIT7, hw->membase + COR_OFFSET);
466         /* Wait for settletime */
467         mdelay(settletime);
468         /* Set non-reset bits back what they were */
469         writeb(corsave, hw->membase + COR_OFFSET);
470         DBFEXIT;
471         return result;
472 }