2005-04-17 02:20:36 +04:00
/*** -*- linux-c -*- **********************************************************
Driver for Atmel at76c502 at76c504 and at76c506 wireless cards .
Copyright 2000 - 2001 ATMEL Corporation .
Copyright 2003 Simon Kelley .
2006-10-08 08:14:30 +04:00
This code was developed from version 2.1 .1 of the Atmel drivers ,
released by Atmel corp . under the GPL in December 2002. It also
includes code from the Linux aironet drivers ( C ) Benjamin Reed ,
and the Linux PCMCIA package , ( C ) David Hinds .
2005-04-17 02:20:36 +04:00
2006-10-08 08:14:30 +04:00
For all queries about this code , please contact the current author ,
2005-04-17 02:20:36 +04:00
Simon Kelley < simon @ thekelleys . org . uk > and not Atmel Corporation .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This software is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Atmel wireless lan drivers ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef __IN_PCMCIA_PACKAGE__
# include <pcmcia/k_compat.h>
# endif
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/ptrace.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/netdevice.h>
# include <linux/moduleparam.h>
# include <linux/device.h>
# include <pcmcia/cistpl.h>
# include <pcmcia/cisreg.h>
# include <pcmcia/ds.h>
# include <pcmcia/ciscode.h>
# include <asm/io.h>
# include <asm/system.h>
# include <linux/wireless.h>
# include "atmel.h"
/*====================================================================*/
MODULE_AUTHOR ( " Simon Kelley " ) ;
MODULE_DESCRIPTION ( " Support for Atmel at76c50x 802.11 wireless ethernet cards. " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_SUPPORTED_DEVICE ( " Atmel at76c50x PCMCIA cards " ) ;
/*====================================================================*/
/*
The event ( ) function is this driver ' s Card Services event handler .
It will be called by Card Services when an appropriate card status
event is received . The config ( ) and release ( ) entry points are
used to configure or release a socket , in response to card
insertion and ejection events . They are invoked from the atmel_cs
2006-10-08 08:14:30 +04:00
event handler .
2005-04-17 02:20:36 +04:00
*/
2006-03-31 19:26:06 +04:00
static int atmel_config ( struct pcmcia_device * link ) ;
2006-03-31 19:21:06 +04:00
static void atmel_release ( struct pcmcia_device * link ) ;
2005-04-17 02:20:36 +04:00
/*
The attach ( ) and detach ( ) entry points are used to create and destroy
" instances " of the driver , where each instance represents everything
needed to manage one actual PCMCIA card .
*/
2005-11-14 23:23:14 +03:00
static void atmel_detach ( struct pcmcia_device * p_dev ) ;
2005-04-17 02:20:36 +04:00
typedef struct local_info_t {
struct net_device * eth_dev ;
} local_info_t ;
/*======================================================================
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
atmel_attach ( ) creates an " instance " of the driver , allocating
local data structures for one device . The device is registered
with Card Services .
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
The dev_link structure is initialized , but we don ' t actually
configure the card at this point - - we wait until we receive a
card insertion event .
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2006-03-31 19:26:06 +04:00
static int atmel_probe ( struct pcmcia_device * p_dev )
2005-04-17 02:20:36 +04:00
{
local_info_t * local ;
2005-11-14 23:25:51 +03:00
2009-10-24 17:53:36 +04:00
dev_dbg ( & p_dev - > dev , " atmel_attach() \n " ) ;
2005-04-17 02:20:36 +04:00
/* Allocate space for private device-specific data */
2005-11-08 02:03:15 +03:00
local = kzalloc ( sizeof ( local_info_t ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! local ) {
printk ( KERN_ERR " atmel_cs: no memory for new device \n " ) ;
2005-11-14 23:25:51 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2006-03-05 12:45:09 +03:00
p_dev - > priv = local ;
2005-11-14 23:25:51 +03:00
2006-03-31 19:26:06 +04:00
return atmel_config ( p_dev ) ;
2005-04-17 02:20:36 +04:00
} /* atmel_attach */
/*======================================================================
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
This deletes a driver " instance " . The device is de - registered
with Card Services . If it has been released , all local data
structures are freed . Otherwise , the structures will be freed
when the device is released .
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2006-03-31 19:21:06 +04:00
static void atmel_detach ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2009-10-24 17:53:36 +04:00
dev_dbg ( & link - > dev , " atmel_detach \n " ) ;
2005-04-17 02:20:36 +04:00
2006-03-02 02:09:29 +03:00
atmel_release ( link ) ;
2005-11-14 23:25:35 +03:00
2005-10-29 00:53:13 +04:00
kfree ( link - > priv ) ;
2005-04-17 02:20:36 +04:00
}
/*======================================================================
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
atmel_config ( ) is scheduled to run after a CARD_INSERTION event
is received , to configure the PCMCIA socket , and to make the
device available to the system .
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* Call-back function to interrogate PCMCIA-specific information
about the current existance of the card */
static int card_present ( void * arg )
2006-03-05 13:04:33 +03:00
{
2006-03-31 19:21:06 +04:00
struct pcmcia_device * link = ( struct pcmcia_device * ) arg ;
2006-03-05 13:04:33 +03:00
if ( pcmcia_dev_present ( link ) )
2005-04-17 02:20:36 +04:00
return 1 ;
2006-03-05 13:04:33 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-07-30 15:13:46 +04:00
static int atmel_config_check ( struct pcmcia_device * p_dev , void * priv_data )
2008-08-02 16:28:43 +04:00
{
2010-07-30 15:13:46 +04:00
if ( p_dev - > config_index = = 0 )
return - EINVAL ;
2008-08-02 16:28:43 +04:00
2010-07-24 19:23:51 +04:00
return pcmcia_request_io ( p_dev ) ;
2008-08-02 16:28:43 +04:00
}
2006-03-31 19:26:06 +04:00
static int atmel_config ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
local_info_t * dev ;
2009-10-24 17:53:36 +04:00
int ret ;
2005-10-30 18:50:15 +03:00
struct pcmcia_device_id * did ;
2005-04-17 02:20:36 +04:00
dev = link - > priv ;
2009-11-03 12:27:34 +03:00
did = dev_get_drvdata ( & link - > dev ) ;
2005-04-17 02:20:36 +04:00
2009-10-24 17:53:36 +04:00
dev_dbg ( & link - > dev , " atmel_config \n " ) ;
2006-10-08 08:14:30 +04:00
2010-07-30 11:51:52 +04:00
link - > config_flags | = CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
2010-07-30 15:13:46 +04:00
CONF_AUTO_AUDIO | CONF_AUTO_SET_IO ;
2010-07-30 11:51:52 +04:00
2005-04-17 02:20:36 +04:00
/*
In this loop , we scan the CIS for configuration table entries ,
each of which describes a valid card configuration , including
voltage , IO window , memory window , and interrupt settings .
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
We make no assumptions about the card to be configured : we use
just the information available in the CIS . In an ideal world ,
this would work for any PCMCIA card , but it requires a complete
and accurate CIS . In practice , a driver usually " knows " most of
these things without consulting the CIS , and most client drivers
will only use the CIS to fill in implementation - defined details .
*/
2008-08-02 17:30:31 +04:00
if ( pcmcia_loop_config ( link , atmel_config_check , NULL ) )
2008-08-02 16:28:43 +04:00
goto failed ;
2006-10-08 08:14:30 +04:00
2010-03-07 14:21:16 +03:00
if ( ! link - > irq ) {
dev_err ( & link - > dev , " atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config. " ) ;
goto failed ;
2009-10-24 17:53:36 +04:00
}
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
/*
This actually configures the PCMCIA socket - - setting up
the I / O windows and the interrupt mapping , and putting the
card and host interface into " Memory and IO " mode .
*/
2010-07-29 21:27:09 +04:00
ret = pcmcia_enable_device ( link ) ;
2009-10-24 17:53:36 +04:00
if ( ret )
goto failed ;
2006-10-08 08:14:30 +04:00
( ( local_info_t * ) link - > priv ) - > eth_dev =
2010-03-07 14:21:16 +03:00
init_atmel_card ( link - > irq ,
2010-07-24 17:58:54 +04:00
link - > resource [ 0 ] - > start ,
2005-10-30 18:50:15 +03:00
did ? did - > driver_info : ATMEL_FW_TYPE_NONE ,
2009-11-03 12:27:34 +03:00
& link - > dev ,
2006-10-08 08:14:30 +04:00
card_present ,
2005-04-17 02:20:36 +04:00
link ) ;
2006-10-08 08:14:30 +04:00
if ( ! ( ( local_info_t * ) link - > priv ) - > eth_dev )
2009-10-24 17:53:36 +04:00
goto failed ;
2006-10-08 08:14:30 +04:00
2006-03-31 19:26:06 +04:00
return 0 ;
2006-03-02 02:09:29 +03:00
2008-08-02 16:28:43 +04:00
failed :
2005-04-17 02:20:36 +04:00
atmel_release ( link ) ;
2006-03-31 19:26:06 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
/*======================================================================
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
After a card is removed , atmel_release ( ) will unregister the
device , and release the PCMCIA configuration . If the device is
still open , this will be postponed until it is closed .
2006-10-08 08:14:30 +04:00
2005-04-17 02:20:36 +04:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2006-03-31 19:21:06 +04:00
static void atmel_release ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev = ( ( local_info_t * ) link - > priv ) - > eth_dev ;
2006-01-15 11:32:39 +03:00
2009-10-24 17:53:36 +04:00
dev_dbg ( & link - > dev , " atmel_release \n " ) ;
2006-01-15 11:32:39 +03:00
if ( dev )
2005-10-30 18:50:15 +03:00
stop_atmel_card ( dev ) ;
2006-01-15 11:32:39 +03:00
( ( local_info_t * ) link - > priv ) - > eth_dev = NULL ;
2006-03-31 19:21:06 +04:00
pcmcia_disable_device ( link ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-31 19:21:06 +04:00
static int atmel_suspend ( struct pcmcia_device * link )
2005-11-14 23:21:18 +03:00
{
local_info_t * local = link - > priv ;
2006-03-02 02:09:29 +03:00
netif_device_detach ( local - > eth_dev ) ;
2005-11-14 23:21:18 +03:00
return 0 ;
}
2006-03-31 19:21:06 +04:00
static int atmel_resume ( struct pcmcia_device * link )
2005-11-14 23:21:18 +03:00
{
local_info_t * local = link - > priv ;
2006-03-02 02:09:29 +03:00
atmel_open ( local - > eth_dev ) ;
netif_device_attach ( local - > eth_dev ) ;
2005-11-14 23:21:18 +03:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
/*====================================================================*/
2005-10-30 18:50:15 +03:00
/* We use the driver_info field to store the correct firmware type for a card. */
# define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \
. match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID | \
PCMCIA_DEV_ID_MATCH_CARD_ID , \
. manf_id = ( manf ) , \
. card_id = ( card ) , \
. driver_info = ( kernel_ulong_t ) ( info ) , }
# define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \
. match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1 | \
PCMCIA_DEV_ID_MATCH_PROD_ID2 , \
. prod_id = { ( v1 ) , ( v2 ) , NULL , NULL } , \
. prod_id_hash = { ( vh1 ) , ( vh2 ) , 0 , 0 } , \
. driver_info = ( kernel_ulong_t ) ( info ) , }
2005-06-28 03:28:34 +04:00
static struct pcmcia_device_id atmel_ids [ ] = {
2005-10-30 18:50:15 +03:00
PCMCIA_DEVICE_MANF_CARD_INFO ( 0x0101 , 0x0620 , ATMEL_FW_TYPE_502_3COM ) ,
PCMCIA_DEVICE_MANF_CARD_INFO ( 0x0101 , 0x0696 , ATMEL_FW_TYPE_502_3COM ) ,
PCMCIA_DEVICE_MANF_CARD_INFO ( 0x01bf , 0x3302 , ATMEL_FW_TYPE_502E ) ,
PCMCIA_DEVICE_MANF_CARD_INFO ( 0xd601 , 0x0007 , ATMEL_FW_TYPE_502 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " 11WAVE " , " 11WP611AL-E " , 0x9eb2da1f , 0xc9a0d3f9 , ATMEL_FW_TYPE_502E ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " ATMEL " , " AT76C502AR " , 0xabda4164 , 0x41b37e1f , ATMEL_FW_TYPE_502 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " ATMEL " , " AT76C502AR_D " , 0xabda4164 , 0x3675d704 , ATMEL_FW_TYPE_502D ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " ATMEL " , " AT76C502AR_E " , 0xabda4164 , 0x4172e792 , ATMEL_FW_TYPE_502E ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " ATMEL " , " AT76C504_R " , 0xabda4164 , 0x917f3d72 , ATMEL_FW_TYPE_504_2958 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " ATMEL " , " AT76C504 " , 0xabda4164 , 0x5040670a , ATMEL_FW_TYPE_504 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " ATMEL " , " AT76C504A " , 0xabda4164 , 0xe15ed87f , ATMEL_FW_TYPE_504A_2958 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " BT " , " Voyager 1020 Laptop Adapter " , 0xae49b86a , 0x1e957cd5 , ATMEL_FW_TYPE_502 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " CNet " , " CNWLC 11Mbps Wireless PC Card V-5 " , 0xbc477dde , 0x502fae6b , ATMEL_FW_TYPE_502E ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " IEEE 802.11b " , " Wireless LAN PC Card " , 0x5b878724 , 0x122f1df6 , ATMEL_FW_TYPE_502 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " IEEE 802.11b " , " Wireless LAN Card S " , 0x5b878724 , 0x5fba533a , ATMEL_FW_TYPE_504_2958 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " OEM " , " 11Mbps Wireless LAN PC Card V-3 " , 0xfea54c90 , 0x1c5b0f68 , ATMEL_FW_TYPE_502 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " SMC " , " 2632W " , 0xc4f8b18b , 0x30f38774 , ATMEL_FW_TYPE_502D ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " SMC " , " 2632W-V2 " , 0xc4f8b18b , 0x172d1377 , ATMEL_FW_TYPE_502 ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " Wireless " , " PC_CARD " , 0xa407ecdd , 0x119f6314 , ATMEL_FW_TYPE_502D ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " WLAN " , " 802.11b PC CARD " , 0x575c516c , 0xb1f6dbc4 , ATMEL_FW_TYPE_502D ) ,
PCMCIA_DEVICE_PROD_ID12_INFO ( " LG " , " LW2100N " , 0xb474d43a , 0x6b1fec94 , ATMEL_FW_TYPE_502E ) ,
2005-06-28 03:28:34 +04:00
PCMCIA_DEVICE_NULL
} ;
2005-10-30 18:50:15 +03:00
2005-06-28 03:28:34 +04:00
MODULE_DEVICE_TABLE ( pcmcia , atmel_ids ) ;
2005-04-17 02:20:36 +04:00
static struct pcmcia_driver atmel_driver = {
2005-07-08 04:59:00 +04:00
. owner = THIS_MODULE ,
. drv = {
. name = " atmel_cs " ,
2005-04-17 02:20:36 +04:00
} ,
2006-03-31 19:26:06 +04:00
. probe = atmel_probe ,
2005-11-14 23:23:14 +03:00
. remove = atmel_detach ,
2005-06-28 03:28:34 +04:00
. id_table = atmel_ids ,
2005-11-14 23:21:18 +03:00
. suspend = atmel_suspend ,
. resume = atmel_resume ,
2005-04-17 02:20:36 +04:00
} ;
static int atmel_cs_init ( void )
{
return pcmcia_register_driver ( & atmel_driver ) ;
}
static void atmel_cs_cleanup ( void )
{
pcmcia_unregister_driver ( & atmel_driver ) ;
}
/*
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
In addition :
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written
permission .
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT ,
INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT ,
STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
2006-10-08 08:14:30 +04:00
POSSIBILITY OF SUCH DAMAGE .
2005-04-17 02:20:36 +04:00
*/
module_init ( atmel_cs_init ) ;
module_exit ( atmel_cs_cleanup ) ;