Merge commit 'd01d0756f75e7a5b4b43764ad45b83c4340f11d6' into next-samsung
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / wlags49_h2 / wl_cs.c
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 *
26 * Copyright © 2003 Agere Systems Inc.
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 *
47 * THIS SOFTWARE IS PROVIDED \93AS IS\94 AND ANY EXPRESS OR IMPLIED WARRANTIES,
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
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>
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>
77 #include <asm/system.h>
78 #include <asm/bitops.h>
79
80 #include <linux/netdevice.h>
81 #include <linux/etherdevice.h>
82 #include <linux/skbuff.h>
83 #include <linux/if_arp.h>
84 #include <linux/ioport.h>
85
86 #include <pcmcia/cs_types.h>
87 #include <pcmcia/cs.h>
88 #include <pcmcia/cistpl.h>
89 #include <pcmcia/cisreg.h>
90 #include <pcmcia/ciscode.h>
91 #include <pcmcia/ds.h>
92 #include <debug.h>
93
94 #include <hcf.h>
95 #include <dhf.h>
96 #include <hcfdef.h>
97
98 #include <wl_if.h>
99 #include <wl_internal.h>
100 #include <wl_util.h>
101 #include <wl_main.h>
102 #include <wl_netdev.h>
103 #include <wl_cs.h>
104 #include <wl_sysfs.h>
105
106
107 /*******************************************************************************
108 * global definitions
109 ******************************************************************************/
110 #if DBG
111 extern dbg_info_t *DbgInfo;
112 #endif /* DBG */
113
114
115 /*******************************************************************************
116 * wl_adapter_attach()
117 *******************************************************************************
118 *
119 * DESCRIPTION:
120 *
121 * Creates an instance of the driver, allocating local data structures for
122 * one device. The device is registered with Card Services.
123 *
124 * PARAMETERS:
125 *
126 * none
127 *
128 * RETURNS:
129 *
130 * pointer to an allocated dev_link_t structure
131 * NULL on failure
132 *
133 ******************************************************************************/
134 static int wl_adapter_attach(struct pcmcia_device *link)
135 {
136 struct net_device *dev;
137 struct wl_private *lp;
138 /*------------------------------------------------------------------------*/
139
140 DBG_FUNC( "wl_adapter_attach" );
141 DBG_ENTER( DbgInfo );
142
143 dev = wl_device_alloc();
144 if(dev == NULL) {
145 DBG_ERROR( DbgInfo, "wl_device_alloc returned NULL\n");
146 return -ENOMEM;
147 }
148
149 link->io.NumPorts1 = HCF_NUM_IO_PORTS;
150 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
151 link->io.IOAddrLines = 6;
152 link->conf.Attributes = CONF_ENABLE_IRQ;
153 link->conf.IntType = INT_MEMORY_AND_IO;
154 link->conf.ConfigIndex = 5;
155 link->conf.Present = PRESENT_OPTION;
156
157 link->priv = dev;
158 lp = wl_priv(dev);
159 lp->link = link;
160
161 wl_adapter_insert(link);
162
163 DBG_LEAVE( DbgInfo );
164 return 0;
165 } // wl_adapter_attach
166 /*============================================================================*/
167
168
169
170 /*******************************************************************************
171 * wl_adapter_detach()
172 *******************************************************************************
173 *
174 * DESCRIPTION:
175 *
176 * This deletes a driver "instance". The device is de-registered with Card
177 * Services. If it has been released, then the net device is unregistered, and
178 * all local data structures are freed. Otherwise, the structures will be
179 * freed when the device is released.
180 *
181 * PARAMETERS:
182 *
183 * link - pointer to the dev_link_t structure representing the device to
184 * detach
185 *
186 * RETURNS:
187 *
188 * N/A
189 *
190 ******************************************************************************/
191 static void wl_adapter_detach(struct pcmcia_device *link)
192 {
193 struct net_device *dev = link->priv;
194 /*------------------------------------------------------------------------*/
195
196
197 DBG_FUNC( "wl_adapter_detach" );
198 DBG_ENTER( DbgInfo );
199 DBG_PARAM( DbgInfo, "link", "0x%p", link );
200
201 wl_adapter_release(link);
202
203 if (dev) {
204 unregister_wlags_sysfs(dev);
205 unregister_netdev(dev);
206 }
207
208 wl_device_dealloc(dev);
209
210 DBG_LEAVE( DbgInfo );
211 } // wl_adapter_detach
212 /*============================================================================*/
213
214
215 /*******************************************************************************
216 * wl_adapter_release()
217 *******************************************************************************
218 *
219 * DESCRIPTION:
220 *
221 * After a card is removed, this routine will release the PCMCIA
222 * configuration. If the device is still open, this will be postponed until it
223 * is closed.
224 *
225 * PARAMETERS:
226 *
227 * arg - a u_long representing a pointer to a dev_link_t structure for the
228 * device to be released.
229 *
230 * RETURNS:
231 *
232 * N/A
233 *
234 ******************************************************************************/
235 void wl_adapter_release( struct pcmcia_device *link )
236 {
237 DBG_FUNC( "wl_adapter_release" );
238 DBG_ENTER( DbgInfo );
239 DBG_PARAM( DbgInfo, "link", "0x%p", link);
240
241 /* Stop hardware */
242 wl_remove(link->priv);
243
244 pcmcia_disable_device(link);
245
246 DBG_LEAVE( DbgInfo );
247 } // wl_adapter_release
248 /*============================================================================*/
249
250 static int wl_adapter_suspend(struct pcmcia_device *link)
251 {
252 struct net_device *dev = link->priv;
253
254 //if (link->open) {
255 netif_device_detach(dev);
256 wl_suspend(dev);
257 //// CHECK! pcmcia_release_configuration(link->handle);
258 //}
259
260 return 0;
261 } // wl_adapter_suspend
262
263 static int wl_adapter_resume(struct pcmcia_device *link)
264 {
265 struct net_device *dev = link->priv;
266
267 wl_resume(dev);
268
269 netif_device_attach( dev );
270
271 return 0;
272 } // wl_adapter_resume
273
274 /*******************************************************************************
275 * wl_adapter_insert()
276 *******************************************************************************
277 *
278 * DESCRIPTION:
279 *
280 * wl_adapter_insert() is scheduled to run after a CARD_INSERTION event is
281 * received, to configure the PCMCIA socket, and to make the ethernet device
282 * available to the system.
283 *
284 * PARAMETERS:
285 *
286 * link - pointer to the dev_link_t structure representing the device to
287 * insert
288 *
289 * RETURNS:
290 *
291 * N/A
292 *
293 ******************************************************************************/
294 void wl_adapter_insert( struct pcmcia_device *link )
295 {
296 struct net_device *dev;
297 int i;
298 int ret;
299 /*------------------------------------------------------------------------*/
300
301 DBG_FUNC( "wl_adapter_insert" );
302 DBG_ENTER( DbgInfo );
303 DBG_PARAM( DbgInfo, "link", "0x%p", link );
304
305 dev = link->priv;
306
307 /* Do we need to allocate an interrupt? */
308 link->conf.Attributes |= CONF_ENABLE_IRQ;
309
310 ret = pcmcia_request_io(link, &link->io);
311 if (ret != 0)
312 goto failed;
313
314 ret = pcmcia_request_irq(link, (void *) wl_isr);
315 if (ret != 0)
316 goto failed;
317
318 ret = pcmcia_request_configuration(link, &link->conf);
319 if (ret != 0)
320 goto failed;
321
322 dev->irq = link->irq;
323 dev->base_addr = link->io.BasePort1;
324
325 SET_NETDEV_DEV(dev, &link->dev);
326 if (register_netdev(dev) != 0) {
327 printk("%s: register_netdev() failed\n", MODULE_NAME);
328 goto failed;
329 }
330
331 register_wlags_sysfs(dev);
332
333 printk(KERN_INFO "%s: Wireless, io_addr %#03lx, irq %d, ""mac_address ",
334 dev->name, dev->base_addr, dev->irq);
335 for( i = 0; i < ETH_ALEN; i++ ) {
336 printk("%02X%c", dev->dev_addr[i], ((i < (ETH_ALEN-1)) ? ':' : '\n'));
337 }
338
339 DBG_LEAVE( DbgInfo );
340 return;
341
342 failed:
343 wl_adapter_release( link );
344
345 DBG_LEAVE(DbgInfo);
346 return;
347 } // wl_adapter_insert
348 /*============================================================================*/
349
350
351 /*******************************************************************************
352 * wl_adapter_open()
353 *******************************************************************************
354 *
355 * DESCRIPTION:
356 *
357 * Open the device.
358 *
359 * PARAMETERS:
360 *
361 * dev - a pointer to a net_device structure representing the network
362 * device to open.
363 *
364 * RETURNS:
365 *
366 * 0 on success
367 * errno value otherwise
368 *
369 ******************************************************************************/
370 int wl_adapter_open( struct net_device *dev )
371 {
372 struct wl_private *lp = wl_priv(dev);
373 struct pcmcia_device *link = lp->link;
374 int result = 0;
375 int hcf_status = HCF_SUCCESS;
376 /*------------------------------------------------------------------------*/
377
378
379 DBG_FUNC( "wl_adapter_open" );
380 DBG_ENTER( DbgInfo );
381 DBG_PRINT( "%s\n", VERSION_INFO );
382 DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
383
384 if(!pcmcia_dev_present(link))
385 {
386 DBG_LEAVE( DbgInfo );
387 return -ENODEV;
388 }
389
390 link->open++;
391
392 hcf_status = wl_open( dev );
393
394 if( hcf_status != HCF_SUCCESS ) {
395 link->open--;
396 result = -ENODEV;
397 }
398
399 DBG_LEAVE( DbgInfo );
400 return result;
401 } // wl_adapter_open
402 /*============================================================================*/
403
404
405 /*******************************************************************************
406 * wl_adapter_close()
407 *******************************************************************************
408 *
409 * DESCRIPTION:
410 *
411 * Close the device.
412 *
413 * PARAMETERS:
414 *
415 * dev - a pointer to a net_device structure representing the network
416 * device to close.
417 *
418 * RETURNS:
419 *
420 * 0 on success
421 * errno value otherwise
422 *
423 ******************************************************************************/
424 int wl_adapter_close( struct net_device *dev )
425 {
426 struct wl_private *lp = wl_priv(dev);
427 struct pcmcia_device *link = lp->link;
428 /*------------------------------------------------------------------------*/
429
430
431 DBG_FUNC( "wl_adapter_close" );
432 DBG_ENTER( DbgInfo );
433 DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
434
435 if( link == NULL ) {
436 DBG_LEAVE( DbgInfo );
437 return -ENODEV;
438 }
439
440 DBG_TRACE( DbgInfo, "%s: Shutting down adapter.\n", dev->name );
441 wl_close( dev );
442
443 link->open--;
444
445 DBG_LEAVE( DbgInfo );
446 return 0;
447 } // wl_adapter_close
448 /*============================================================================*/
449
450 static struct pcmcia_device_id wl_adapter_ids[] = {
451 #if ! ((HCF_TYPE) & HCF_TYPE_HII5)
452 PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0003),
453 PCMCIA_DEVICE_PROD_ID12("Agere Systems", "Wireless PC Card Model 0110",
454 0x33103a9b, 0xe175b0dd),
455 #else
456 PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0004),
457 PCMCIA_DEVICE_PROD_ID12("Linksys", "WCF54G_Wireless-G_CompactFlash_Card",
458 0x0733cc81, 0x98a599e1),
459 #endif // (HCF_TYPE) & HCF_TYPE_HII5
460 PCMCIA_DEVICE_NULL,
461 };
462 MODULE_DEVICE_TABLE(pcmcia, wl_adapter_ids);
463
464 static struct pcmcia_driver wlags49_driver = {
465 .owner = THIS_MODULE,
466 .drv = {
467 .name = DRIVER_NAME,
468 },
469 .probe = wl_adapter_attach,
470 .remove = wl_adapter_detach,
471 .id_table = wl_adapter_ids,
472 .suspend = wl_adapter_suspend,
473 .resume = wl_adapter_resume,
474 };
475
476
477
478 /*******************************************************************************
479 * wl_adapter_init_module()
480 *******************************************************************************
481 *
482 * DESCRIPTION:
483 *
484 * Called by init_module() to perform PCMCIA driver initialization.
485 *
486 * PARAMETERS:
487 *
488 * N/A
489 *
490 * RETURNS:
491 *
492 * 0 on success
493 * -1 on error
494 *
495 ******************************************************************************/
496 int wl_adapter_init_module( void )
497 {
498 int ret;
499 /*------------------------------------------------------------------------*/
500
501
502 DBG_FUNC( "wl_adapter_init_module" );
503 DBG_ENTER( DbgInfo );
504 DBG_TRACE( DbgInfo, "wl_adapter_init_module() -- PCMCIA\n" );
505
506 ret = pcmcia_register_driver(&wlags49_driver);
507
508 DBG_LEAVE( DbgInfo );
509 return ret;
510 } // wl_adapter_init_module
511 /*============================================================================*/
512
513
514 /*******************************************************************************
515 * wl_adapter_cleanup_module()
516 *******************************************************************************
517 *
518 * DESCRIPTION:
519 *
520 * Called by cleanup_module() to perform driver uninitialization.
521 *
522 * PARAMETERS:
523 *
524 * N/A
525 *
526 * RETURNS:
527 *
528 * N/A
529 *
530 ******************************************************************************/
531 void wl_adapter_cleanup_module( void )
532 {
533 DBG_FUNC( "wl_adapter_cleanup_module" );
534 DBG_ENTER( DbgInfo );
535 DBG_TRACE( DbgInfo, "wl_adapter_cleanup_module() -- PCMCIA\n" );
536
537
538 pcmcia_unregister_driver(&wlags49_driver);
539
540 DBG_LEAVE( DbgInfo );
541 return;
542 } // wl_adapter_cleanup_module
543 /*============================================================================*/
544
545
546 /*******************************************************************************
547 * wl_adapter_is_open()
548 *******************************************************************************
549 *
550 * DESCRIPTION:
551 *
552 * Check with Card Services to determine if this device is open.
553 *
554 * PARAMETERS:
555 *
556 * dev - a pointer to the net_device structure whose open status will be
557 * checked
558 *
559 * RETURNS:
560 *
561 * nonzero if device is open
562 * 0 otherwise
563 *
564 ******************************************************************************/
565 int wl_adapter_is_open( struct net_device *dev )
566 {
567 struct wl_private *lp = wl_priv(dev);
568 struct pcmcia_device *link = lp->link;
569
570 if(!pcmcia_dev_present(link)) {
571 return 0;
572 }
573
574 return( link->open );
575 } // wl_adapter_is_open
576 /*============================================================================*/
577
578
579 #if DBG
580
581 /*******************************************************************************
582 * DbgEvent()
583 *******************************************************************************
584 *
585 * DESCRIPTION:
586 *
587 * Converts the card serivces events to text for debugging.
588 *
589 * PARAMETERS:
590 *
591 * mask - a integer representing the error(s) being reported by Card
592 * Services.
593 *
594 * RETURNS:
595 *
596 * a pointer to a string describing the error(s)
597 *
598 ******************************************************************************/
599 const char* DbgEvent( int mask )
600 {
601 static char DbgBuffer[256];
602 char *pBuf;
603 /*------------------------------------------------------------------------*/
604
605
606 pBuf = DbgBuffer;
607 *pBuf = '\0';
608
609
610 if( mask & CS_EVENT_WRITE_PROTECT )
611 strcat( pBuf, "WRITE_PROTECT " );
612
613 if(mask & CS_EVENT_CARD_LOCK)
614 strcat( pBuf, "CARD_LOCK " );
615
616 if(mask & CS_EVENT_CARD_INSERTION)
617 strcat( pBuf, "CARD_INSERTION " );
618
619 if(mask & CS_EVENT_CARD_REMOVAL)
620 strcat( pBuf, "CARD_REMOVAL " );
621
622 if(mask & CS_EVENT_BATTERY_DEAD)
623 strcat( pBuf, "BATTERY_DEAD " );
624
625 if(mask & CS_EVENT_BATTERY_LOW)
626 strcat( pBuf, "BATTERY_LOW " );
627
628 if(mask & CS_EVENT_READY_CHANGE)
629 strcat( pBuf, "READY_CHANGE " );
630
631 if(mask & CS_EVENT_CARD_DETECT)
632 strcat( pBuf, "CARD_DETECT " );
633
634 if(mask & CS_EVENT_RESET_REQUEST)
635 strcat( pBuf, "RESET_REQUEST " );
636
637 if(mask & CS_EVENT_RESET_PHYSICAL)
638 strcat( pBuf, "RESET_PHYSICAL " );
639
640 if(mask & CS_EVENT_CARD_RESET)
641 strcat( pBuf, "CARD_RESET " );
642
643 if(mask & CS_EVENT_REGISTRATION_COMPLETE)
644 strcat( pBuf, "REGISTRATION_COMPLETE " );
645
646 // if(mask & CS_EVENT_RESET_COMPLETE)
647 // strcat( pBuf, "RESET_COMPLETE " );
648
649 if(mask & CS_EVENT_PM_SUSPEND)
650 strcat( pBuf, "PM_SUSPEND " );
651
652 if(mask & CS_EVENT_PM_RESUME)
653 strcat( pBuf, "PM_RESUME " );
654
655 if(mask & CS_EVENT_INSERTION_REQUEST)
656 strcat( pBuf, "INSERTION_REQUEST " );
657
658 if(mask & CS_EVENT_EJECTION_REQUEST)
659 strcat( pBuf, "EJECTION_REQUEST " );
660
661 if(mask & CS_EVENT_MTD_REQUEST)
662 strcat( pBuf, "MTD_REQUEST " );
663
664 if(mask & CS_EVENT_ERASE_COMPLETE)
665 strcat( pBuf, "ERASE_COMPLETE " );
666
667 if(mask & CS_EVENT_REQUEST_ATTENTION)
668 strcat( pBuf, "REQUEST_ATTENTION " );
669
670 if(mask & CS_EVENT_CB_DETECT)
671 strcat( pBuf, "CB_DETECT " );
672
673 if(mask & CS_EVENT_3VCARD)
674 strcat( pBuf, "3VCARD " );
675
676 if(mask & CS_EVENT_XVCARD)
677 strcat( pBuf, "XVCARD " );
678
679
680 if( *pBuf ) {
681 pBuf[strlen(pBuf) - 1] = '\0';
682 } else {
683 if( mask != 0x0 ) {
684 sprintf( pBuf, "<<0x%08x>>", mask );
685 }
686 }
687
688 return pBuf;
689 } // DbgEvent
690 /*============================================================================*/
691
692 #endif /* DBG */