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