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