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> | |
68c0bdff | 102 | |
68c0bdff HG |
103 | /******************************************************************************* |
104 | * wl_adapter_attach() | |
105 | ******************************************************************************* | |
106 | * | |
107 | * DESCRIPTION: | |
108 | * | |
109 | * Creates an instance of the driver, allocating local data structures for | |
110 | * one device. The device is registered with Card Services. | |
111 | * | |
112 | * PARAMETERS: | |
113 | * | |
114 | * none | |
115 | * | |
116 | * RETURNS: | |
117 | * | |
118 | * pointer to an allocated dev_link_t structure | |
119 | * NULL on failure | |
120 | * | |
121 | ******************************************************************************/ | |
122 | static int wl_adapter_attach(struct pcmcia_device *link) | |
123 | { | |
6d98be39 PS |
124 | struct net_device *dev; |
125 | struct wl_private *lp; | |
657d4c86 | 126 | int ret; |
6d98be39 PS |
127 | |
128 | dev = wl_device_alloc(); | |
129 | if (dev == NULL) { | |
130 | DBG_ERROR(DbgInfo, "wl_device_alloc returned NULL\n"); | |
131 | return -ENOMEM; | |
132 | } | |
133 | ||
1685e633 LT |
134 | link->resource[0]->end = HCF_NUM_IO_PORTS; |
135 | link->resource[0]->flags= IO_DATA_PATH_WIDTH_16; | |
1ac71e5a | 136 | link->config_flags |= CONF_ENABLE_IRQ; |
7feabb64 DB |
137 | link->config_index = 5; |
138 | link->config_regs = PRESENT_OPTION; | |
6d98be39 PS |
139 | |
140 | link->priv = dev; | |
141 | lp = wl_priv(dev); | |
142 | lp->link = link; | |
143 | ||
657d4c86 AK |
144 | ret = wl_adapter_insert(link); |
145 | if (ret != 0) | |
146 | wl_device_dealloc(dev); | |
6d98be39 | 147 | |
657d4c86 | 148 | return ret; |
194a636d | 149 | } /* wl_adapter_attach */ |
68c0bdff HG |
150 | /*============================================================================*/ |
151 | ||
152 | ||
153 | ||
68c0bdff HG |
154 | static void wl_adapter_detach(struct pcmcia_device *link) |
155 | { | |
6d98be39 | 156 | struct net_device *dev = link->priv; |
68c0bdff | 157 | |
6d98be39 | 158 | DBG_PARAM(DbgInfo, "link", "0x%p", link); |
68c0bdff | 159 | |
6d98be39 | 160 | wl_adapter_release(link); |
68c0bdff | 161 | |
6d98be39 | 162 | if (dev) { |
6d98be39 | 163 | unregister_netdev(dev); |
bed861ba | 164 | wl_device_dealloc(dev); |
6d98be39 | 165 | } |
194a636d | 166 | } /* wl_adapter_detach */ |
68c0bdff HG |
167 | /*============================================================================*/ |
168 | ||
169 | ||
aa605fa4 | 170 | void wl_adapter_release(struct pcmcia_device *link) |
68c0bdff | 171 | { |
6d98be39 | 172 | DBG_PARAM(DbgInfo, "link", "0x%p", link); |
68c0bdff | 173 | |
6d98be39 PS |
174 | /* Stop hardware */ |
175 | wl_remove(link->priv); | |
68c0bdff | 176 | |
6d98be39 | 177 | pcmcia_disable_device(link); |
194a636d | 178 | } /* wl_adapter_release */ |
68c0bdff HG |
179 | /*============================================================================*/ |
180 | ||
181 | static int wl_adapter_suspend(struct pcmcia_device *link) | |
182 | { | |
6d98be39 | 183 | struct net_device *dev = link->priv; |
68c0bdff | 184 | |
194a636d | 185 | /* if (link->open) { */ |
68c0bdff HG |
186 | netif_device_detach(dev); |
187 | wl_suspend(dev); | |
194a636d PS |
188 | /* CHECK! pcmcia_release_configuration(link->handle); */ |
189 | /* } */ | |
68c0bdff | 190 | |
6d98be39 | 191 | return 0; |
194a636d | 192 | } /* wl_adapter_suspend */ |
68c0bdff HG |
193 | |
194 | static int wl_adapter_resume(struct pcmcia_device *link) | |
195 | { | |
196 | struct net_device *dev = link->priv; | |
197 | ||
198 | wl_resume(dev); | |
199 | ||
aa605fa4 | 200 | netif_device_attach(dev); |
68c0bdff HG |
201 | |
202 | return 0; | |
194a636d | 203 | } /* wl_adapter_resume */ |
68c0bdff | 204 | |
657d4c86 | 205 | int wl_adapter_insert(struct pcmcia_device *link) |
68c0bdff | 206 | { |
6d98be39 | 207 | struct net_device *dev; |
6d98be39 | 208 | int ret; |
68c0bdff | 209 | |
6d98be39 | 210 | DBG_PARAM(DbgInfo, "link", "0x%p", link); |
68c0bdff | 211 | |
6d98be39 | 212 | dev = link->priv; |
68c0bdff | 213 | |
6d98be39 | 214 | /* Do we need to allocate an interrupt? */ |
1ac71e5a | 215 | link->config_flags |= CONF_ENABLE_IRQ; |
1685e633 | 216 | link->io_lines = 6; |
68c0bdff | 217 | |
1685e633 | 218 | ret = pcmcia_request_io(link); |
6d98be39 PS |
219 | if (ret != 0) |
220 | goto failed; | |
93822ad1 | 221 | |
6d98be39 PS |
222 | ret = pcmcia_request_irq(link, (void *) wl_isr); |
223 | if (ret != 0) | |
224 | goto failed; | |
68c0bdff | 225 | |
1ac71e5a | 226 | ret = pcmcia_enable_device(link); |
6d98be39 PS |
227 | if (ret != 0) |
228 | goto failed; | |
68c0bdff | 229 | |
6d98be39 | 230 | dev->irq = link->irq; |
1685e633 | 231 | dev->base_addr = link->resource[0]->start; |
68c0bdff | 232 | |
6d98be39 | 233 | SET_NETDEV_DEV(dev, &link->dev); |
49c144c8 WY |
234 | ret = register_netdev(dev); |
235 | if (ret != 0) { | |
cb7482bf | 236 | printk("%s: register_netdev() failed\n", KBUILD_MODNAME); |
6d98be39 PS |
237 | goto failed; |
238 | } | |
93822ad1 | 239 | |
5d74f175 DK |
240 | printk(KERN_INFO "%s: Wireless, io_addr %#03lx, irq %d, mac_address" |
241 | " %pM\n", dev->name, dev->base_addr, dev->irq, dev->dev_addr); | |
68c0bdff | 242 | |
657d4c86 | 243 | return 0; |
68c0bdff | 244 | |
68c0bdff | 245 | failed: |
6d98be39 | 246 | wl_adapter_release(link); |
657d4c86 | 247 | return ret; |
194a636d | 248 | } /* wl_adapter_insert */ |
68c0bdff HG |
249 | /*============================================================================*/ |
250 | ||
251 | ||
252 | /******************************************************************************* | |
253 | * wl_adapter_open() | |
254 | ******************************************************************************* | |
255 | * | |
256 | * DESCRIPTION: | |
257 | * | |
258 | * Open the device. | |
259 | * | |
260 | * PARAMETERS: | |
261 | * | |
262 | * dev - a pointer to a net_device structure representing the network | |
263 | * device to open. | |
264 | * | |
265 | * RETURNS: | |
266 | * | |
267 | * 0 on success | |
268 | * errno value otherwise | |
269 | * | |
270 | ******************************************************************************/ | |
aa605fa4 | 271 | int wl_adapter_open(struct net_device *dev) |
68c0bdff | 272 | { |
6d98be39 PS |
273 | struct wl_private *lp = wl_priv(dev); |
274 | struct pcmcia_device *link = lp->link; | |
275 | int result = 0; | |
276 | int hcf_status = HCF_SUCCESS; | |
68c0bdff | 277 | |
aa605fa4 | 278 | DBG_PRINT("%s\n", VERSION_INFO); |
6d98be39 | 279 | DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); |
68c0bdff | 280 | |
3c319c96 | 281 | if (!pcmcia_dev_present(link)) |
6d98be39 | 282 | return -ENODEV; |
68c0bdff | 283 | |
6d98be39 | 284 | link->open++; |
68c0bdff | 285 | |
6d98be39 | 286 | hcf_status = wl_open(dev); |
68c0bdff | 287 | |
6d98be39 PS |
288 | if (hcf_status != HCF_SUCCESS) { |
289 | link->open--; | |
290 | result = -ENODEV; | |
291 | } | |
68c0bdff | 292 | |
6d98be39 | 293 | return result; |
194a636d | 294 | } /* wl_adapter_open */ |
68c0bdff HG |
295 | /*============================================================================*/ |
296 | ||
297 | ||
298 | /******************************************************************************* | |
299 | * wl_adapter_close() | |
300 | ******************************************************************************* | |
301 | * | |
302 | * DESCRIPTION: | |
303 | * | |
304 | * Close the device. | |
305 | * | |
306 | * PARAMETERS: | |
307 | * | |
308 | * dev - a pointer to a net_device structure representing the network | |
309 | * device to close. | |
310 | * | |
311 | * RETURNS: | |
312 | * | |
313 | * 0 on success | |
314 | * errno value otherwise | |
315 | * | |
316 | ******************************************************************************/ | |
aa605fa4 | 317 | int wl_adapter_close(struct net_device *dev) |
68c0bdff | 318 | { |
6d98be39 PS |
319 | struct wl_private *lp = wl_priv(dev); |
320 | struct pcmcia_device *link = lp->link; | |
68c0bdff | 321 | |
6d98be39 | 322 | DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); |
68c0bdff | 323 | |
3c319c96 | 324 | if (link == NULL) |
6d98be39 | 325 | return -ENODEV; |
68c0bdff | 326 | |
6d98be39 PS |
327 | DBG_TRACE(DbgInfo, "%s: Shutting down adapter.\n", dev->name); |
328 | wl_close(dev); | |
68c0bdff | 329 | |
6d98be39 | 330 | link->open--; |
68c0bdff | 331 | |
6d98be39 | 332 | return 0; |
194a636d | 333 | } /* wl_adapter_close */ |
68c0bdff HG |
334 | /*============================================================================*/ |
335 | ||
2202a5a7 | 336 | static const struct pcmcia_device_id wl_adapter_ids[] = { |
194a636d | 337 | #if !((HCF_TYPE) & HCF_TYPE_HII5) |
68c0bdff HG |
338 | PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0003), |
339 | PCMCIA_DEVICE_PROD_ID12("Agere Systems", "Wireless PC Card Model 0110", | |
6d98be39 | 340 | 0x33103a9b, 0xe175b0dd), |
68c0bdff HG |
341 | #else |
342 | PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0004), | |
343 | PCMCIA_DEVICE_PROD_ID12("Linksys", "WCF54G_Wireless-G_CompactFlash_Card", | |
6d98be39 | 344 | 0x0733cc81, 0x98a599e1), |
194a636d | 345 | #endif /* (HCF_TYPE) & HCF_TYPE_HII5 */ |
68c0bdff | 346 | PCMCIA_DEVICE_NULL, |
6d98be39 | 347 | }; |
68c0bdff HG |
348 | MODULE_DEVICE_TABLE(pcmcia, wl_adapter_ids); |
349 | ||
350 | static struct pcmcia_driver wlags49_driver = { | |
6d98be39 | 351 | .owner = THIS_MODULE, |
2e9b981a | 352 | .name = DRIVER_NAME, |
6d98be39 PS |
353 | .probe = wl_adapter_attach, |
354 | .remove = wl_adapter_detach, | |
355 | .id_table = wl_adapter_ids, | |
356 | .suspend = wl_adapter_suspend, | |
357 | .resume = wl_adapter_resume, | |
68c0bdff HG |
358 | }; |
359 | ||
360 | ||
361 | ||
362 | /******************************************************************************* | |
363 | * wl_adapter_init_module() | |
364 | ******************************************************************************* | |
365 | * | |
366 | * DESCRIPTION: | |
367 | * | |
368 | * Called by init_module() to perform PCMCIA driver initialization. | |
369 | * | |
370 | * PARAMETERS: | |
371 | * | |
372 | * N/A | |
373 | * | |
374 | * RETURNS: | |
375 | * | |
376 | * 0 on success | |
377 | * -1 on error | |
378 | * | |
379 | ******************************************************************************/ | |
aa605fa4 | 380 | int wl_adapter_init_module(void) |
68c0bdff | 381 | { |
4ecc8c02 | 382 | return pcmcia_register_driver(&wlags49_driver); |
194a636d | 383 | } /* wl_adapter_init_module */ |
68c0bdff HG |
384 | /*============================================================================*/ |
385 | ||
386 | ||
387 | /******************************************************************************* | |
388 | * wl_adapter_cleanup_module() | |
389 | ******************************************************************************* | |
390 | * | |
391 | * DESCRIPTION: | |
392 | * | |
393 | * Called by cleanup_module() to perform driver uninitialization. | |
394 | * | |
395 | * PARAMETERS: | |
396 | * | |
397 | * N/A | |
398 | * | |
399 | * RETURNS: | |
400 | * | |
401 | * N/A | |
402 | * | |
403 | ******************************************************************************/ | |
aa605fa4 | 404 | void wl_adapter_cleanup_module(void) |
68c0bdff | 405 | { |
6d98be39 | 406 | pcmcia_unregister_driver(&wlags49_driver); |
194a636d | 407 | } /* wl_adapter_cleanup_module */ |
68c0bdff HG |
408 | /*============================================================================*/ |
409 | ||
410 | ||
411 | /******************************************************************************* | |
412 | * wl_adapter_is_open() | |
413 | ******************************************************************************* | |
414 | * | |
415 | * DESCRIPTION: | |
416 | * | |
417 | * Check with Card Services to determine if this device is open. | |
418 | * | |
419 | * PARAMETERS: | |
420 | * | |
421 | * dev - a pointer to the net_device structure whose open status will be | |
422 | * checked | |
423 | * | |
424 | * RETURNS: | |
425 | * | |
426 | * nonzero if device is open | |
427 | * 0 otherwise | |
428 | * | |
429 | ******************************************************************************/ | |
aa605fa4 | 430 | int wl_adapter_is_open(struct net_device *dev) |
68c0bdff | 431 | { |
6d98be39 PS |
432 | struct wl_private *lp = wl_priv(dev); |
433 | struct pcmcia_device *link = lp->link; | |
68c0bdff | 434 | |
194a636d | 435 | if (!pcmcia_dev_present(link)) |
6d98be39 | 436 | return 0; |
68c0bdff | 437 | |
194a636d PS |
438 | return link->open; |
439 | } /* wl_adapter_is_open */ | |
68c0bdff | 440 | /*============================================================================*/ |