]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/staging/wlan-ng/prism2_pci.c
Staging: add wlan-ng prism2 usb driver
[linux-2.6-omap-h63xx.git] / drivers / staging / wlan-ng / prism2_pci.c
1 #define WLAN_HOSTIF WLAN_PCI
2 #include "hfa384x.c"
3 #include "prism2mgmt.c"
4 #include "prism2mib.c"
5 #include "prism2sta.c"
6
7 #define PCI_SIZE                0x1000          /* Memory size - 4K bytes */
8
9 /* ISL3874A 11Mb/s WLAN controller */
10 #define PCIVENDOR_INTERSIL      0x1260UL
11 #define PCIDEVICE_ISL3874       0x3873UL /* [MSM] yeah I know...the ID says
12                                             3873. Trust me, it's a 3874. */
13
14 /* Samsung SWL-2210P 11Mb/s WLAN controller (uses ISL3874A) */
15 #define PCIVENDOR_SAMSUNG      0x167dUL
16 #define PCIDEVICE_SWL_2210P    0xa000UL
17
18 #define PCIVENDOR_NETGEAR      0x1385UL /* for MA311 */
19
20 /* PCI Class & Sub-Class code, Network-'Other controller' */
21 #define PCI_CLASS_NETWORK_OTHERS 0x280
22
23
24 /*----------------------------------------------------------------
25 * prism2sta_probe_pci
26 *
27 * Probe routine called when a PCI device w/ matching ID is found.
28 * The ISL3874 implementation uses the following map:
29 *   BAR0: Prism2.x registers memory mapped, size=4k
30 * Here's the sequence:
31 *   - Allocate the PCI resources.
32 *   - Read the PCMCIA attribute memory to make sure we have a WLAN card
33 *   - Reset the MAC
34 *   - Initialize the netdev and wlan data
35 *   - Initialize the MAC
36 *
37 * Arguments:
38 *       pdev            ptr to pci device structure containing info about
39 *                       pci configuration.
40 *       id              ptr to the device id entry that matched this device.
41 *
42 * Returns:
43 *       zero            - success
44 *       negative        - failed
45 *
46 * Side effects:
47 *
48 *
49 * Call context:
50 *       process thread
51 *
52 ----------------------------------------------------------------*/
53 static int __devinit
54 prism2sta_probe_pci(
55         struct pci_dev *pdev,
56         const struct pci_device_id *id)
57 {
58         int             result;
59         phys_t          phymem = 0;
60         void            __iomem *mem = NULL;
61         wlandevice_t    *wlandev = NULL;
62         hfa384x_t       *hw = NULL;
63
64         DBFENTER;
65
66         /* Enable the pci device */
67         if (pci_enable_device(pdev)) {
68                 WLAN_LOG_ERROR("%s: pci_enable_device() failed.\n", dev_info);
69                 result = -EIO;
70                 goto fail;
71         }
72
73         /* Figure out our resources */
74         phymem = pci_resource_start(pdev, 0);
75
76         if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
77                 printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
78                 result = -EIO;
79                 goto fail;
80         }
81
82         mem = ioremap(phymem, PCI_SIZE);
83         if ( mem == 0 ) {
84                 WLAN_LOG_ERROR("%s: ioremap() failed.\n", dev_info);
85                 result = -EIO;
86                 goto fail;
87         }
88
89         /* Log the device */
90         WLAN_LOG_INFO("A Prism2.5 PCI device found, "
91                 "phymem:0x%llx, irq:%d, mem:0x%p\n",
92                 (unsigned long long)phymem, pdev->irq, mem);
93
94         if ((wlandev = create_wlan()) == NULL) {
95                 WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
96                 result = -EIO;
97                 goto fail;
98         }
99         hw = wlandev->priv;
100
101         if ( wlan_setup(wlandev) != 0 ) {
102                 WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
103                 result = -EIO;
104                 goto fail;
105         }
106
107         /* Setup netdevice's ability to report resources
108          * Note: the netdevice was allocated by wlan_setup()
109          */
110         wlandev->netdev->irq = pdev->irq;
111         wlandev->netdev->mem_start = (unsigned long) mem;
112         wlandev->netdev->mem_end = wlandev->netdev->mem_start +
113                 pci_resource_len(pdev, 0);
114
115         /* Initialize the hw data */
116         hfa384x_create(hw, wlandev->netdev->irq, 0, mem);
117         hw->wlandev = wlandev;
118
119         /* Register the wlandev, this gets us a name and registers the
120          * linux netdevice.
121          */
122         SET_MODULE_OWNER(wlandev->netdev);
123 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
124        SET_NETDEV_DEV(wlandev->netdev, &(pdev->dev));
125 #endif
126         if ( register_wlandev(wlandev) != 0 ) {
127                 WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info);
128                 result = -EIO;
129                 goto fail;
130         }
131
132 #if 0
133         /* TODO: Move this and an irq test into an hfa384x_testif() routine.
134          */
135         outw(PRISM2STA_MAGIC, HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
136         reg=inw( HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
137         if ( reg != PRISM2STA_MAGIC ) {
138                 WLAN_LOG_ERROR("MAC register access test failed!\n");
139                 result = -EIO;
140                 goto fail;
141         }
142 #endif
143
144         /* Do a chip-level reset on the MAC */
145         if (prism2_doreset) {
146                 result = hfa384x_corereset(hw,
147                                 prism2_reset_holdtime,
148                                 prism2_reset_settletime, 0);
149                 if (result != 0) {
150                         WLAN_LOG_ERROR(
151                                 "%s: hfa384x_corereset() failed.\n",
152                                 dev_info);
153                         unregister_wlandev(wlandev);
154                         hfa384x_destroy(hw);
155                         result = -EIO;
156                         goto fail;
157                 }
158         }
159
160         pci_set_drvdata(pdev, wlandev);
161
162         /* Shouldn't actually hook up the IRQ until we
163          * _know_ things are alright.  A test routine would help.
164          */
165         request_irq(wlandev->netdev->irq, hfa384x_interrupt,
166                 SA_SHIRQ, wlandev->name, wlandev);
167
168         wlandev->msdstate = WLAN_MSD_HWPRESENT;
169
170         result = 0;
171         goto done;
172
173  fail:
174         pci_set_drvdata(pdev, NULL);
175         if (wlandev)    kfree(wlandev);
176         if (hw)         kfree(hw);
177         if (mem)        iounmap(mem);
178         pci_release_regions(pdev);
179         pci_disable_device(pdev);
180
181  done:
182         DBFEXIT;
183         return result;
184 }
185
186 static void __devexit prism2sta_remove_pci(struct pci_dev *pdev)
187 {
188         wlandevice_t            *wlandev;
189         hfa384x_t       *hw;
190
191         wlandev = (wlandevice_t *) pci_get_drvdata(pdev);
192         hw = wlandev->priv;
193
194         p80211netdev_hwremoved(wlandev);
195
196         /* reset hardware */
197         prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
198
199         if (pdev->irq)
200                 free_irq(pdev->irq, wlandev);
201
202         unregister_wlandev(wlandev);
203
204         /* free local stuff */
205         if (hw) {
206                 hfa384x_destroy(hw);
207                 kfree(hw);
208         }
209
210         iounmap((void __iomem *)wlandev->netdev->mem_start);
211         wlan_unsetup(wlandev);
212
213         pci_release_regions(pdev);
214         pci_disable_device(pdev);
215         pci_set_drvdata(pdev, NULL);
216
217         kfree(wlandev);
218 }
219
220
221 static struct pci_device_id pci_id_tbl[] = {
222         {
223                 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3874,
224                 PCI_ANY_ID, PCI_ANY_ID,
225                 0, 0,
226                 /* Driver data, we just put the name here */
227                 (unsigned long)"Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller"
228         },
229         {
230                 PCIVENDOR_INTERSIL, 0x3872,
231                 PCI_ANY_ID, PCI_ANY_ID,
232                 0, 0,
233                 /* Driver data, we just put the name here */
234                 (unsigned long)"Intersil Prism2.5 ISL3872 11Mb/s WLAN Controller"
235         },
236         {
237                PCIVENDOR_SAMSUNG, PCIDEVICE_SWL_2210P,
238                PCI_ANY_ID, PCI_ANY_ID,
239                0, 0,
240                /* Driver data, we just put the name here */
241                (unsigned long)"Samsung MagicLAN SWL-2210P 11Mb/s WLAN Controller"
242         },
243         { /* for NetGear MA311 */
244                 PCIVENDOR_NETGEAR, 0x3872,
245                 PCI_ANY_ID, PCI_ANY_ID,
246                 0, 0,
247                 /* Driver data, we just put the name here */
248                 (unsigned long)"Netgear MA311 WLAN Controller"
249         },
250         {
251                 0, 0, 0, 0, 0, 0, 0
252         }
253 };
254
255 MODULE_DEVICE_TABLE(pci, pci_id_tbl);
256
257 /* Function declared here because of ptr reference below */
258 static int  __devinit prism2sta_probe_pci(struct pci_dev *pdev,
259                                 const struct pci_device_id *id);
260 static void  __devexit prism2sta_remove_pci(struct pci_dev *pdev);
261
262 static struct pci_driver prism2_pci_drv_id = {
263         .name = "prism2_pci",
264         .id_table = pci_id_tbl,
265         .probe = prism2sta_probe_pci,
266         .remove = prism2sta_remove_pci,
267 #ifdef CONFIG_PM
268         .suspend = prism2sta_suspend_pci,
269         .resume = prism2sta_resume_pci,
270 #endif
271 };
272
273 #ifdef MODULE
274
275 static int __init prism2pci_init(void)
276 {
277         WLAN_LOG_NOTICE("%s Loaded\n", version);
278         return pci_module_init(&prism2_pci_drv_id);
279 };
280
281 static void __exit prism2pci_cleanup(void)
282 {
283         pci_unregister_driver(&prism2_pci_drv_id);
284 };
285
286 module_init(prism2pci_init);
287 module_exit(prism2pci_cleanup);
288
289 #endif
290
291 int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis)
292 {
293         int             result = 0;
294         unsigned long   timeout;
295         UINT16  reg;
296         DBFENTER;
297
298         /* Assert reset and wait awhile
299          * (note: these delays are _really_ long, but they appear to be
300          *        necessary.)
301          */
302         hfa384x_setreg(hw, 0xc5, HFA384x_PCICOR);
303         timeout = jiffies + HZ/4;
304         while(time_before(jiffies, timeout)) udelay(5);
305
306         if (genesis) {
307                 hfa384x_setreg(hw, genesis, HFA384x_PCIHCR);
308                 timeout = jiffies + HZ/4;
309                 while(time_before(jiffies, timeout)) udelay(5);
310         }
311
312         /* Clear the reset and wait some more
313          */
314         hfa384x_setreg(hw, 0x45, HFA384x_PCICOR);
315         timeout = jiffies + HZ/2;
316         while(time_before(jiffies, timeout)) udelay(5);
317
318         /* Wait for f/w to complete initialization (CMD:BUSY == 0)
319          */
320         timeout = jiffies + 2*HZ;
321         reg = hfa384x_getreg(hw, HFA384x_CMD);
322         while ( HFA384x_CMD_ISBUSY(reg) && time_before( jiffies, timeout) ) {
323                 reg = hfa384x_getreg(hw, HFA384x_CMD);
324                 udelay(10);
325         }
326         if (HFA384x_CMD_ISBUSY(reg)) {
327                 WLAN_LOG_WARNING("corereset: Timed out waiting for cmd register.\n");
328                 result=1;
329         }
330         DBFEXIT;
331         return result;
332 }