Commit | Line | Data |
---|---|---|
68c0bdff HG |
1 | /******************************************************************************* |
2 | * Agere Systems Inc. | |
3 | * Wireless device driver for Linux (wlags49). | |
4 | * | |
5 | * Copyright (c) 1998-2003 Agere Systems Inc. | |
6 | * All rights reserved. | |
7 | * http://www.agere.com | |
8 | * | |
9 | * Initially developed by TriplePoint, Inc. | |
10 | * http://www.triplepoint.com | |
11 | * | |
12 | *------------------------------------------------------------------------------ | |
13 | * | |
14 | * This file contains processing and initialization specific to Card Services | |
15 | * devices (PCMCIA, CF). | |
16 | * | |
17 | *------------------------------------------------------------------------------ | |
18 | * | |
19 | * SOFTWARE LICENSE | |
20 | * | |
21 | * This software is provided subject to the following terms and conditions, | |
22 | * which you should read carefully before using the software. Using this | |
23 | * software indicates your acceptance of these terms and conditions. If you do | |
24 | * not agree with these terms and conditions, do not use the software. | |
25 | * | |
8cd5778b | 26 | * Copyright (c) 2003 Agere Systems Inc. |
68c0bdff HG |
27 | * All rights reserved. |
28 | * | |
29 | * Redistribution and use in source or binary forms, with or without | |
30 | * modifications, are permitted provided that the following conditions are met: | |
31 | * | |
32 | * . Redistributions of source code must retain the above copyright notice, this | |
33 | * list of conditions and the following Disclaimer as comments in the code as | |
34 | * well as in the documentation and/or other materials provided with the | |
35 | * distribution. | |
36 | * | |
37 | * . Redistributions in binary form must reproduce the above copyright notice, | |
38 | * this list of conditions and the following Disclaimer in the documentation | |
39 | * and/or other materials provided with the distribution. | |
40 | * | |
41 | * . Neither the name of Agere Systems Inc. nor the names of the contributors | |
42 | * may be used to endorse or promote products derived from this software | |
43 | * without specific prior written permission. | |
44 | * | |
45 | * Disclaimer | |
46 | * | |
8cd5778b | 47 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
68c0bdff HG |
48 | * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF |
49 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY | |
50 | * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN | |
51 | * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY | |
52 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
53 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
54 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
55 | * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT | |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
57 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
58 | * DAMAGE. | |
59 | * | |
60 | ******************************************************************************/ | |
61 | ||
68c0bdff HG |
62 | /******************************************************************************* |
63 | * include files | |
64 | ******************************************************************************/ | |
65 | #include <wl_version.h> | |
66 | ||
67 | #include <linux/kernel.h> | |
68 | #include <linux/sched.h> | |
69 | #include <linux/ptrace.h> | |
68c0bdff HG |
70 | #include <linux/ctype.h> |
71 | #include <linux/string.h> | |
72 | #include <linux/timer.h> | |
73 | #include <linux/interrupt.h> | |
74 | #include <linux/in.h> | |
75 | #include <linux/delay.h> | |
76 | #include <asm/io.h> | |
68c0bdff HG |
77 | #include <asm/bitops.h> |
78 | ||
79 | #include <linux/netdevice.h> | |
80 | #include <linux/etherdevice.h> | |
81 | #include <linux/skbuff.h> | |
82 | #include <linux/if_arp.h> | |
83 | #include <linux/ioport.h> | |
45296236 | 84 | #include <linux/module.h> |
68c0bdff | 85 | |
68c0bdff HG |
86 | #include <pcmcia/cistpl.h> |
87 | #include <pcmcia/cisreg.h> | |
88 | #include <pcmcia/ciscode.h> | |
89 | #include <pcmcia/ds.h> | |
90 | #include <debug.h> | |
91 | ||
92 | #include <hcf.h> | |
93 | #include <dhf.h> | |
94 | #include <hcfdef.h> | |
95 | ||
96 | #include <wl_if.h> | |
97 | #include <wl_internal.h> | |
98 | #include <wl_util.h> | |
99 | #include <wl_main.h> | |
100 | #include <wl_netdev.h> | |
101 | #include <wl_cs.h> | |
102 | #include <wl_sysfs.h> | |
103 | ||
104 | ||
68c0bdff HG |
105 | /******************************************************************************* |
106 | * global definitions | |
107 | ******************************************************************************/ | |
108 | #if DBG | |
109 | extern dbg_info_t *DbgInfo; | |
110 | #endif /* DBG */ | |
111 | ||
112 | ||
113 | /******************************************************************************* | |
114 | * wl_adapter_attach() | |
115 | ******************************************************************************* | |
116 | * | |
117 | * DESCRIPTION: | |
118 | * | |
119 | * Creates an instance of the driver, allocating local data structures for | |
120 | * one device. The device is registered with Card Services. | |
121 | * | |
122 | * PARAMETERS: | |
123 | * | |
124 | * none | |
125 | * | |
126 | * RETURNS: | |
127 | * | |
128 | * pointer to an allocated dev_link_t structure | |
129 | * NULL on failure | |
130 | * | |
131 | ******************************************************************************/ | |
132 | static int wl_adapter_attach(struct pcmcia_device *link) | |
133 | { | |
6d98be39 PS |
134 | struct net_device *dev; |
135 | struct wl_private *lp; | |
194a636d | 136 | /*--------------------------------------------------------------------*/ |
6d98be39 PS |
137 | |
138 | DBG_FUNC("wl_adapter_attach"); | |
139 | DBG_ENTER(DbgInfo); | |
140 | ||
141 | dev = wl_device_alloc(); | |
142 | if (dev == NULL) { | |
143 | DBG_ERROR(DbgInfo, "wl_device_alloc returned NULL\n"); | |
144 | return -ENOMEM; | |
145 | } | |
146 | ||
1685e633 LT |
147 | link->resource[0]->end = HCF_NUM_IO_PORTS; |
148 | link->resource[0]->flags= IO_DATA_PATH_WIDTH_16; | |
1ac71e5a | 149 | link->config_flags |= CONF_ENABLE_IRQ; |
7feabb64 DB |
150 | link->config_index = 5; |
151 | link->config_regs = PRESENT_OPTION; | |
6d98be39 PS |
152 | |
153 | link->priv = dev; | |
154 | lp = wl_priv(dev); | |
155 | lp->link = link; | |
156 | ||
157 | wl_adapter_insert(link); | |
158 | ||
159 | DBG_LEAVE(DbgInfo); | |
160 | return 0; | |
194a636d | 161 | } /* wl_adapter_attach */ |
68c0bdff HG |
162 | /*============================================================================*/ |
163 | ||
164 | ||
165 | ||
68c0bdff HG |
166 | static void wl_adapter_detach(struct pcmcia_device *link) |
167 | { | |
6d98be39 | 168 | struct net_device *dev = link->priv; |
194a636d | 169 | /*--------------------------------------------------------------------*/ |
68c0bdff | 170 | |
6d98be39 PS |
171 | DBG_FUNC("wl_adapter_detach"); |
172 | DBG_ENTER(DbgInfo); | |
173 | DBG_PARAM(DbgInfo, "link", "0x%p", link); | |
68c0bdff | 174 | |
6d98be39 | 175 | wl_adapter_release(link); |
68c0bdff | 176 | |
6d98be39 PS |
177 | if (dev) { |
178 | unregister_wlags_sysfs(dev); | |
179 | unregister_netdev(dev); | |
bed861ba | 180 | wl_device_dealloc(dev); |
6d98be39 | 181 | } |
68c0bdff | 182 | |
6d98be39 | 183 | DBG_LEAVE(DbgInfo); |
194a636d | 184 | } /* wl_adapter_detach */ |
68c0bdff HG |
185 | /*============================================================================*/ |
186 | ||
187 | ||
aa605fa4 | 188 | void wl_adapter_release(struct pcmcia_device *link) |
68c0bdff | 189 | { |
6d98be39 PS |
190 | DBG_FUNC("wl_adapter_release"); |
191 | DBG_ENTER(DbgInfo); | |
192 | DBG_PARAM(DbgInfo, "link", "0x%p", link); | |
68c0bdff | 193 | |
6d98be39 PS |
194 | /* Stop hardware */ |
195 | wl_remove(link->priv); | |
68c0bdff | 196 | |
6d98be39 | 197 | pcmcia_disable_device(link); |
68c0bdff | 198 | |
6d98be39 | 199 | DBG_LEAVE(DbgInfo); |
194a636d | 200 | } /* wl_adapter_release */ |
68c0bdff HG |
201 | /*============================================================================*/ |
202 | ||
203 | static int wl_adapter_suspend(struct pcmcia_device *link) | |
204 | { | |
6d98be39 | 205 | struct net_device *dev = link->priv; |
68c0bdff | 206 | |
194a636d | 207 | /* if (link->open) { */ |
68c0bdff HG |
208 | netif_device_detach(dev); |
209 | wl_suspend(dev); | |
194a636d PS |
210 | /* CHECK! pcmcia_release_configuration(link->handle); */ |
211 | /* } */ | |
68c0bdff | 212 | |
6d98be39 | 213 | return 0; |
194a636d | 214 | } /* wl_adapter_suspend */ |
68c0bdff HG |
215 | |
216 | static int wl_adapter_resume(struct pcmcia_device *link) | |
217 | { | |
218 | struct net_device *dev = link->priv; | |
219 | ||
220 | wl_resume(dev); | |
221 | ||
aa605fa4 | 222 | netif_device_attach(dev); |
68c0bdff HG |
223 | |
224 | return 0; | |
194a636d | 225 | } /* wl_adapter_resume */ |
68c0bdff | 226 | |
aa605fa4 | 227 | void wl_adapter_insert(struct pcmcia_device *link) |
68c0bdff | 228 | { |
6d98be39 | 229 | struct net_device *dev; |
6d98be39 | 230 | int ret; |
194a636d | 231 | /*--------------------------------------------------------------------*/ |
68c0bdff | 232 | |
6d98be39 PS |
233 | DBG_FUNC("wl_adapter_insert"); |
234 | DBG_ENTER(DbgInfo); | |
235 | DBG_PARAM(DbgInfo, "link", "0x%p", link); | |
68c0bdff | 236 | |
6d98be39 | 237 | dev = link->priv; |
68c0bdff | 238 | |
6d98be39 | 239 | /* Do we need to allocate an interrupt? */ |
1ac71e5a | 240 | link->config_flags |= CONF_ENABLE_IRQ; |
1685e633 | 241 | link->io_lines = 6; |
68c0bdff | 242 | |
1685e633 | 243 | ret = pcmcia_request_io(link); |
6d98be39 PS |
244 | if (ret != 0) |
245 | goto failed; | |
93822ad1 | 246 | |
6d98be39 PS |
247 | ret = pcmcia_request_irq(link, (void *) wl_isr); |
248 | if (ret != 0) | |
249 | goto failed; | |
68c0bdff | 250 | |
1ac71e5a | 251 | ret = pcmcia_enable_device(link); |
6d98be39 PS |
252 | if (ret != 0) |
253 | goto failed; | |
68c0bdff | 254 | |
6d98be39 | 255 | dev->irq = link->irq; |
1685e633 | 256 | dev->base_addr = link->resource[0]->start; |
68c0bdff | 257 | |
6d98be39 PS |
258 | SET_NETDEV_DEV(dev, &link->dev); |
259 | if (register_netdev(dev) != 0) { | |
260 | printk("%s: register_netdev() failed\n", MODULE_NAME); | |
261 | goto failed; | |
262 | } | |
93822ad1 | 263 | |
6d98be39 | 264 | register_wlags_sysfs(dev); |
68c0bdff | 265 | |
5d74f175 DK |
266 | printk(KERN_INFO "%s: Wireless, io_addr %#03lx, irq %d, mac_address" |
267 | " %pM\n", dev->name, dev->base_addr, dev->irq, dev->dev_addr); | |
68c0bdff | 268 | |
6d98be39 PS |
269 | DBG_LEAVE(DbgInfo); |
270 | return; | |
68c0bdff | 271 | |
68c0bdff | 272 | failed: |
6d98be39 | 273 | wl_adapter_release(link); |
68c0bdff | 274 | |
6d98be39 PS |
275 | DBG_LEAVE(DbgInfo); |
276 | return; | |
194a636d | 277 | } /* wl_adapter_insert */ |
68c0bdff HG |
278 | /*============================================================================*/ |
279 | ||
280 | ||
281 | /******************************************************************************* | |
282 | * wl_adapter_open() | |
283 | ******************************************************************************* | |
284 | * | |
285 | * DESCRIPTION: | |
286 | * | |
287 | * Open the device. | |
288 | * | |
289 | * PARAMETERS: | |
290 | * | |
291 | * dev - a pointer to a net_device structure representing the network | |
292 | * device to open. | |
293 | * | |
294 | * RETURNS: | |
295 | * | |
296 | * 0 on success | |
297 | * errno value otherwise | |
298 | * | |
299 | ******************************************************************************/ | |
aa605fa4 | 300 | int wl_adapter_open(struct net_device *dev) |
68c0bdff | 301 | { |
6d98be39 PS |
302 | struct wl_private *lp = wl_priv(dev); |
303 | struct pcmcia_device *link = lp->link; | |
304 | int result = 0; | |
305 | int hcf_status = HCF_SUCCESS; | |
194a636d | 306 | /*--------------------------------------------------------------------*/ |
68c0bdff | 307 | |
6d98be39 PS |
308 | DBG_FUNC("wl_adapter_open"); |
309 | DBG_ENTER(DbgInfo); | |
aa605fa4 | 310 | DBG_PRINT("%s\n", VERSION_INFO); |
6d98be39 | 311 | DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); |
68c0bdff | 312 | |
194a636d | 313 | if (!pcmcia_dev_present(link)) { |
6d98be39 PS |
314 | DBG_LEAVE(DbgInfo); |
315 | return -ENODEV; | |
316 | } | |
68c0bdff | 317 | |
6d98be39 | 318 | link->open++; |
68c0bdff | 319 | |
6d98be39 | 320 | hcf_status = wl_open(dev); |
68c0bdff | 321 | |
6d98be39 PS |
322 | if (hcf_status != HCF_SUCCESS) { |
323 | link->open--; | |
324 | result = -ENODEV; | |
325 | } | |
68c0bdff | 326 | |
6d98be39 PS |
327 | DBG_LEAVE(DbgInfo); |
328 | return result; | |
194a636d | 329 | } /* wl_adapter_open */ |
68c0bdff HG |
330 | /*============================================================================*/ |
331 | ||
332 | ||
333 | /******************************************************************************* | |
334 | * wl_adapter_close() | |
335 | ******************************************************************************* | |
336 | * | |
337 | * DESCRIPTION: | |
338 | * | |
339 | * Close the device. | |
340 | * | |
341 | * PARAMETERS: | |
342 | * | |
343 | * dev - a pointer to a net_device structure representing the network | |
344 | * device to close. | |
345 | * | |
346 | * RETURNS: | |
347 | * | |
348 | * 0 on success | |
349 | * errno value otherwise | |
350 | * | |
351 | ******************************************************************************/ | |
aa605fa4 | 352 | int wl_adapter_close(struct net_device *dev) |
68c0bdff | 353 | { |
6d98be39 PS |
354 | struct wl_private *lp = wl_priv(dev); |
355 | struct pcmcia_device *link = lp->link; | |
194a636d | 356 | /*--------------------------------------------------------------------*/ |
68c0bdff | 357 | |
6d98be39 PS |
358 | DBG_FUNC("wl_adapter_close"); |
359 | DBG_ENTER(DbgInfo); | |
360 | DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); | |
68c0bdff | 361 | |
6d98be39 PS |
362 | if (link == NULL) { |
363 | DBG_LEAVE(DbgInfo); | |
364 | return -ENODEV; | |
365 | } | |
68c0bdff | 366 | |
6d98be39 PS |
367 | DBG_TRACE(DbgInfo, "%s: Shutting down adapter.\n", dev->name); |
368 | wl_close(dev); | |
68c0bdff | 369 | |
6d98be39 | 370 | link->open--; |
68c0bdff | 371 | |
6d98be39 PS |
372 | DBG_LEAVE(DbgInfo); |
373 | return 0; | |
194a636d | 374 | } /* wl_adapter_close */ |
68c0bdff HG |
375 | /*============================================================================*/ |
376 | ||
2202a5a7 | 377 | static const struct pcmcia_device_id wl_adapter_ids[] = { |
194a636d | 378 | #if !((HCF_TYPE) & HCF_TYPE_HII5) |
68c0bdff HG |
379 | PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0003), |
380 | PCMCIA_DEVICE_PROD_ID12("Agere Systems", "Wireless PC Card Model 0110", | |
6d98be39 | 381 | 0x33103a9b, 0xe175b0dd), |
68c0bdff HG |
382 | #else |
383 | PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0004), | |
384 | PCMCIA_DEVICE_PROD_ID12("Linksys", "WCF54G_Wireless-G_CompactFlash_Card", | |
6d98be39 | 385 | 0x0733cc81, 0x98a599e1), |
194a636d | 386 | #endif /* (HCF_TYPE) & HCF_TYPE_HII5 */ |
68c0bdff | 387 | PCMCIA_DEVICE_NULL, |
6d98be39 | 388 | }; |
68c0bdff HG |
389 | MODULE_DEVICE_TABLE(pcmcia, wl_adapter_ids); |
390 | ||
391 | static struct pcmcia_driver wlags49_driver = { | |
6d98be39 | 392 | .owner = THIS_MODULE, |
2e9b981a | 393 | .name = DRIVER_NAME, |
6d98be39 PS |
394 | .probe = wl_adapter_attach, |
395 | .remove = wl_adapter_detach, | |
396 | .id_table = wl_adapter_ids, | |
397 | .suspend = wl_adapter_suspend, | |
398 | .resume = wl_adapter_resume, | |
68c0bdff HG |
399 | }; |
400 | ||
401 | ||
402 | ||
403 | /******************************************************************************* | |
404 | * wl_adapter_init_module() | |
405 | ******************************************************************************* | |
406 | * | |
407 | * DESCRIPTION: | |
408 | * | |
409 | * Called by init_module() to perform PCMCIA driver initialization. | |
410 | * | |
411 | * PARAMETERS: | |
412 | * | |
413 | * N/A | |
414 | * | |
415 | * RETURNS: | |
416 | * | |
417 | * 0 on success | |
418 | * -1 on error | |
419 | * | |
420 | ******************************************************************************/ | |
aa605fa4 | 421 | int wl_adapter_init_module(void) |
68c0bdff | 422 | { |
6d98be39 | 423 | int ret; |
194a636d | 424 | /*--------------------------------------------------------------------*/ |
68c0bdff | 425 | |
6d98be39 PS |
426 | DBG_FUNC("wl_adapter_init_module"); |
427 | DBG_ENTER(DbgInfo); | |
428 | DBG_TRACE(DbgInfo, "wl_adapter_init_module() -- PCMCIA\n"); | |
68c0bdff | 429 | |
6d98be39 | 430 | ret = pcmcia_register_driver(&wlags49_driver); |
68c0bdff | 431 | |
6d98be39 PS |
432 | DBG_LEAVE(DbgInfo); |
433 | return ret; | |
194a636d | 434 | } /* wl_adapter_init_module */ |
68c0bdff HG |
435 | /*============================================================================*/ |
436 | ||
437 | ||
438 | /******************************************************************************* | |
439 | * wl_adapter_cleanup_module() | |
440 | ******************************************************************************* | |
441 | * | |
442 | * DESCRIPTION: | |
443 | * | |
444 | * Called by cleanup_module() to perform driver uninitialization. | |
445 | * | |
446 | * PARAMETERS: | |
447 | * | |
448 | * N/A | |
449 | * | |
450 | * RETURNS: | |
451 | * | |
452 | * N/A | |
453 | * | |
454 | ******************************************************************************/ | |
aa605fa4 | 455 | void wl_adapter_cleanup_module(void) |
68c0bdff | 456 | { |
6d98be39 PS |
457 | DBG_FUNC("wl_adapter_cleanup_module"); |
458 | DBG_ENTER(DbgInfo); | |
459 | DBG_TRACE(DbgInfo, "wl_adapter_cleanup_module() -- PCMCIA\n"); | |
68c0bdff HG |
460 | |
461 | ||
6d98be39 | 462 | pcmcia_unregister_driver(&wlags49_driver); |
68c0bdff | 463 | |
6d98be39 PS |
464 | DBG_LEAVE(DbgInfo); |
465 | return; | |
194a636d | 466 | } /* wl_adapter_cleanup_module */ |
68c0bdff HG |
467 | /*============================================================================*/ |
468 | ||
469 | ||
470 | /******************************************************************************* | |
471 | * wl_adapter_is_open() | |
472 | ******************************************************************************* | |
473 | * | |
474 | * DESCRIPTION: | |
475 | * | |
476 | * Check with Card Services to determine if this device is open. | |
477 | * | |
478 | * PARAMETERS: | |
479 | * | |
480 | * dev - a pointer to the net_device structure whose open status will be | |
481 | * checked | |
482 | * | |
483 | * RETURNS: | |
484 | * | |
485 | * nonzero if device is open | |
486 | * 0 otherwise | |
487 | * | |
488 | ******************************************************************************/ | |
aa605fa4 | 489 | int wl_adapter_is_open(struct net_device *dev) |
68c0bdff | 490 | { |
6d98be39 PS |
491 | struct wl_private *lp = wl_priv(dev); |
492 | struct pcmcia_device *link = lp->link; | |
68c0bdff | 493 | |
194a636d | 494 | if (!pcmcia_dev_present(link)) |
6d98be39 | 495 | return 0; |
68c0bdff | 496 | |
194a636d PS |
497 | return link->open; |
498 | } /* wl_adapter_is_open */ | |
68c0bdff | 499 | /*============================================================================*/ |