patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / net / wireless / prism54 / islpci_hotplug.c
1 /*
2  *  
3  *  Copyright (C) 2002 Intersil Americas Inc.
4  *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include <linux/version.h>
22 #include <linux/module.h>
23 #include <linux/pci.h>
24 #include <linux/delay.h>
25 #include <linux/init.h> /* For __init, __exit */
26
27 #include "islpci_dev.h"
28 #include "islpci_mgt.h"         /* for pc_debug */
29 #include "isl_oid.h"
30
31 #define DRV_NAME        "prism54"
32 #define DRV_VERSION     "1.1"
33
34 MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
35 MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
36 MODULE_LICENSE("GPL");
37
38 /* In this order: vendor, device, subvendor, subdevice, class, class_mask,
39  * driver_data 
40  * Note: for driver_data we put the device's name 
41  * If you have an update for this please contact prism54-devel@prism54.org 
42  * The latest list can be found at http://prism54.org/supported_cards.php */
43 static const struct pci_device_id prism54_id_tbl[] = {
44         {
45          PCIVENDOR_3COM, PCIDEVICE_3COM6001,
46          PCIVENDOR_3COM, PCIDEVICE_3COM6001,
47          0, 0,
48          (unsigned long) "3COM 3CRWE154G72 Wireless LAN adapter"},
49         {
50          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
51          PCIVENDOR_DLINK, 0x3202UL, 
52          0, 0,
53          (unsigned long) "D-Link Air Plus Xtreme G A1 - DWL-g650 A1"},
54         {
55          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
56          PCIVENDOR_IODATA, 0xd019UL, 
57          0, 0,
58          (unsigned long) "I-O Data WN-G54/CB - WN-G54/CB"},
59         {
60          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
61          PCIVENDOR_NETGEAR, 0x4800UL,
62          0, 0,
63          (unsigned long) "Netgear WG511"},
64         {
65          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
66          PCIVENDOR_I4, 0x0020UL,
67          0, 0,
68          (unsigned long) "PLANEX GW-DS54G"},
69         {
70          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
71          PCIVENDOR_SMC, 0x2802UL,
72          0, 0,
73          (unsigned long) "EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card - SMC2802W"},
74         {
75          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
76          PCIVENDOR_SMC, 0x2835UL,
77          0, 0,
78          (unsigned long) "EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Adapter - SMC2835W"},
79         {
80          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
81          PCIVENDOR_INTERSIL, 0x0000UL, /* This was probably a bogus reading... */
82          0, 0,
83          (unsigned long) "SparkLAN WL-850F"},
84         {
85          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
86          PCIVENDOR_I4, 0x0014UL,
87          0, 0,
88          (unsigned long) "I4 Z-Com XG-600"},
89         {
90          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
91          PCIVENDOR_I4, 0x0020UL,
92          0, 0,
93          (unsigned long) "I4 Z-Com XG-900/PLANEX GW-DS54G"},
94         {
95          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
96          PCIVENDOR_ACCTON, 0xee03UL,
97          0, 0,
98          (unsigned long) "SMC 2802Wv2"},
99         {
100          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
101          PCIVENDOR_SMC, 0xa835UL,
102          0, 0,
103          (unsigned long) "SMC 2835Wv2"},
104         {
105          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3877,
106          PCI_ANY_ID, PCI_ANY_ID,
107          0, 0,
108          (unsigned long) "Intersil PRISM Indigo Wireless LAN adapter"},
109         { /* Default */
110          PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
111          PCI_ANY_ID, PCI_ANY_ID,
112          0, 0,
113          (unsigned long) "Intersil PRISM Duette/Prism GT Wireless LAN adapter"},
114         {0,}
115 };
116
117 /* register the device with the Hotplug facilities of the kernel */
118 MODULE_DEVICE_TABLE(pci, prism54_id_tbl);
119
120 static int prism54_probe(struct pci_dev *, const struct pci_device_id *);
121 static void prism54_remove(struct pci_dev *);
122 static int prism54_suspend(struct pci_dev *, u32 state);
123 static int prism54_resume(struct pci_dev *);
124
125 static struct pci_driver prism54_driver = {
126         .name = DRV_NAME,
127         .id_table = prism54_id_tbl,
128         .probe = prism54_probe,
129         .remove = prism54_remove,
130         .suspend = prism54_suspend,
131         .resume = prism54_resume,
132         /* .enable_wake ; we don't support this yet */
133 };
134
135 static void
136 prism54_get_card_model(struct net_device *ndev)
137 {
138         islpci_private  *priv;
139         char            *modelp;
140
141         priv = netdev_priv(ndev);
142         switch (priv->pdev->subsystem_device) {
143         case PCIDEVICE_ISL3877:
144                 modelp = "PRISM Indigo";
145                 break;
146         case PCIDEVICE_3COM6001:
147                 modelp = "3COM 3CRWE154G72";
148                 break;
149         case 0x3202UL:
150                 modelp = "D-Link DWL-g650 A1";
151                 break;
152         case 0xd019UL:
153                 modelp = "WN-G54/CB";
154                 break;
155         case 0x4800UL:
156                 modelp = "Netgear WG511";
157                 break;
158         case 0x2802UL:
159                 modelp = "SMC2802W";
160                 break;
161         case 0xee03UL:
162                 modelp = "SMC2802W V2";
163                 break;
164         case 0x2835UL:
165                 modelp = "SMC2835W";
166                 break;
167         case 0xa835UL:
168                 modelp = "SMC2835W V2";
169                 break;
170         /* Let's leave this one out for now since it seems bogus/wrong 
171          * Even if the manufacturer did use 0x0000UL it may not be correct
172          * by their part, therefore deserving no name ;) */
173         /*      case 0x0000UL: 
174          *              modelp = "SparkLAN WL-850F";
175          *              break;*/
176
177         /* We have two reported for the one below :( */
178         case 0x0014UL:
179                 modelp = "XG-600";
180                 break;
181         case 0x0020UL:
182                 modelp = "XG-900/GW-DS54G";
183                 break;
184 /* Default it */
185 /*
186         case PCIDEVICE_ISL3890:
187                 modelp = "PRISM Duette/GT";
188                 break;
189 */
190         default:
191                 modelp = "PRISM Duette/GT";
192         }
193         printk(KERN_DEBUG "%s: %s driver detected card model: %s\n",
194                         ndev->name, DRV_NAME, modelp);
195         return;
196 }
197
198 /******************************************************************************
199     Module initialization functions
200 ******************************************************************************/
201
202 int
203 prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
204 {
205         struct net_device *ndev;
206         u8 latency_tmr;
207         u32 mem_addr;
208         islpci_private *priv;
209         int rvalue;
210
211         /* TRACE(DRV_NAME); */
212         
213         
214         /* Enable the pci device */
215         if (pci_enable_device(pdev)) {
216                 printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME);
217                 return -ENODEV;
218         }
219
220         /* check whether the latency timer is set correctly */
221         pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr);
222 #if VERBOSE > SHOW_ERROR_MESSAGES
223         DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr);
224 #endif
225         if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) {
226                 /* set the latency timer */
227                 pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
228                                       PCIDEVICE_LATENCY_TIMER_VAL);
229         }
230
231         /* enable PCI DMA */
232         if (pci_set_dma_mask(pdev, 0xffffffff)) {
233                 printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME);
234                 goto do_pci_disable_device;
235         }
236
237         /* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT)
238          * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT)
239          *      The RETRY_TIMEOUT is used to set the number of retries that the core, as a
240          *      Master, will perform before abandoning a cycle. The default value for
241          *      RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new
242          *      devices. A write of zero to the RETRY_TIMEOUT register disables this
243          *      function to allow use with any non-compliant legacy devices that may
244          *      execute more retries.
245          *
246          *      Writing zero to both these two registers will disable both timeouts and
247          *      *can* solve problems caused by devices that are slow to respond.
248          */
249         pci_write_config_byte(pdev, 0x40, 0);
250         pci_write_config_byte(pdev, 0x41, 0);
251
252         /* request the pci device I/O regions */
253         rvalue = pci_request_regions(pdev, DRV_NAME);
254         if (rvalue) {
255                 printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n",
256                        DRV_NAME, rvalue);
257                 goto do_pci_disable_device;
258         }
259
260         /* check if the memory window is indeed set */
261         rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr);
262         if (rvalue || !mem_addr) {
263                 printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n",
264                        DRV_NAME);
265                 goto do_pci_disable_device;
266         }
267
268         /* enable PCI bus-mastering */
269         DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME);
270         pci_set_master(pdev);
271
272         /* setup the network device interface and its structure */
273         if (!(ndev = islpci_setup(pdev))) {
274                 /* error configuring the driver as a network device */
275                 printk(KERN_ERR "%s: could not configure network device\n",
276                        DRV_NAME);
277                 goto do_pci_release_regions;
278         }
279
280         priv = netdev_priv(ndev);
281         islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */
282
283         /* card is in unknown state yet, might have some interrupts pending */
284         isl38xx_disable_interrupts(priv->device_base);
285
286         /* request for the interrupt before uploading the firmware */
287         rvalue = request_irq(pdev->irq, &islpci_interrupt,
288                              SA_SHIRQ, ndev->name, priv);
289
290         if (rvalue) {
291                 /* error, could not hook the handler to the irq */
292                 printk(KERN_ERR "%s: could not install IRQ handler\n",
293                        ndev->name);
294                 goto do_unregister_netdev;
295         }
296
297         /* firmware upload is triggered in islpci_open */
298
299         /* Pretty card model discovery output */
300         prism54_get_card_model(ndev);
301
302         return 0;
303
304       do_unregister_netdev:
305         unregister_netdev(ndev);
306         islpci_free_memory(priv);
307         pci_set_drvdata(pdev, 0);
308         free_netdev(ndev);
309         priv = 0;
310       do_pci_release_regions:
311         pci_release_regions(pdev);
312       do_pci_disable_device:
313         pci_disable_device(pdev);
314         return -EIO;
315 }
316
317 /* set by cleanup_module */
318 static volatile int __in_cleanup_module = 0;
319
320 /* this one removes one(!!) instance only */
321 void
322 prism54_remove(struct pci_dev *pdev)
323 {
324         struct net_device *ndev = pci_get_drvdata(pdev);
325         islpci_private *priv = ndev ? netdev_priv(ndev) : 0;
326         BUG_ON(!priv);
327
328         if (!__in_cleanup_module) {
329                 printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name);
330                 islpci_set_state(priv, PRV_STATE_OFF);
331         }
332
333         printk(KERN_DEBUG "%s: removing device\n", ndev->name);
334
335         unregister_netdev(ndev);
336
337         /* free the interrupt request */
338
339         if (islpci_get_state(priv) != PRV_STATE_OFF) {
340                 isl38xx_disable_interrupts(priv->device_base);
341                 islpci_set_state(priv, PRV_STATE_OFF);
342                 /* This bellow causes a lockup at rmmod time. It might be
343                  * because some interrupts still linger after rmmod time, 
344                  * see bug #17 */
345                 /* pci_set_power_state(pdev, 3);*/      /* try to power-off */
346         }
347
348         free_irq(pdev->irq, priv);
349
350         /* free the PCI memory and unmap the remapped page */
351         islpci_free_memory(priv);
352
353         pci_set_drvdata(pdev, 0);
354         free_netdev(ndev);
355         priv = 0;
356
357         pci_release_regions(pdev);
358
359         pci_disable_device(pdev);
360 }
361
362 int
363 prism54_suspend(struct pci_dev *pdev, u32 state)
364 {
365         struct net_device *ndev = pci_get_drvdata(pdev);
366         islpci_private *priv = ndev ? netdev_priv(ndev) : 0;
367         BUG_ON(!priv);
368
369         printk(KERN_NOTICE "%s: got suspend request (state %d)\n",
370                ndev->name, state);
371
372         pci_save_state(pdev, priv->pci_state);
373
374         /* tell the device not to trigger interrupts for now... */
375         isl38xx_disable_interrupts(priv->device_base);
376
377         /* from now on assume the hardware was already powered down
378            and don't touch it anymore */
379         islpci_set_state(priv, PRV_STATE_OFF);
380
381         netif_stop_queue(ndev);
382         netif_device_detach(ndev);
383
384         return 0;
385 }
386
387 int
388 prism54_resume(struct pci_dev *pdev)
389 {
390         struct net_device *ndev = pci_get_drvdata(pdev);
391         islpci_private *priv = ndev ? netdev_priv(ndev) : 0;
392         BUG_ON(!priv);
393
394         printk(KERN_NOTICE "%s: got resume request\n", ndev->name);
395
396         pci_restore_state(pdev, priv->pci_state);
397
398         /* alright let's go into the PREBOOT state */
399         islpci_reset(priv, 1);
400
401         netif_device_attach(ndev);
402         netif_start_queue(ndev);
403
404         return 0;
405 }
406
407 static int __init
408 prism54_module_init(void)
409 {
410         printk(KERN_INFO "Loaded %s driver, version %s\n",
411                DRV_NAME, DRV_VERSION);
412
413         __bug_on_wrong_struct_sizes ();
414
415         return pci_module_init(&prism54_driver);
416 }
417
418 /* by the time prism54_module_exit() terminates, as a postcondition
419  * all instances will have been destroyed by calls to
420  * prism54_remove() */
421 static void __exit
422 prism54_module_exit(void)
423 {
424         __in_cleanup_module = 1;
425
426         pci_unregister_driver(&prism54_driver);
427
428         printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME);
429
430         __in_cleanup_module = 0;
431 }
432
433 /* register entry points */
434 module_init(prism54_module_init);
435 module_exit(prism54_module_exit);
436 /* EOF */