2005-04-16 15:20:36 -07:00
/*======================================================================
Aironet driver for 4500 and 4800 series cards
This code is released under both the GPL version 2 and BSD licenses .
Either license may be used . The respective licenses are found at
the end of this file .
This code was developed by Benjamin Reed < breed @ users . sourceforge . net >
including portions of which come from the Aironet PC4500
Developer ' s Reference Manual and used with permission . Copyright
( C ) 1999 Benjamin Reed . All Rights Reserved . Permission to use
code in the Developer ' s manual was granted for this driver by
Aironet .
In addition this module was derived from dummy_cs .
The initial developer of dummy_cs is David A . Hinds
< dahinds @ users . sourceforge . net > . Portions created by David A . Hinds
are Copyright ( C ) 1999 David A . Hinds . All Rights Reserved .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# 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/timer.h>
# include <linux/netdevice.h>
# include <pcmcia/cs_types.h>
# include <pcmcia/cs.h>
# include <pcmcia/cistpl.h>
# include <pcmcia/cisreg.h>
# include <pcmcia/ds.h>
# include <asm/io.h>
# include <asm/system.h>
2005-11-05 17:42:27 +01:00
# include "airo.h"
2005-04-16 15:20:36 -07:00
/*
All the PCMCIA modules use PCMCIA_DEBUG to control debugging . If
you do not define PCMCIA_DEBUG at all , all the debug code will be
left out . If you compile with PCMCIA_DEBUG = 0 , the debug code will
be present but disabled - - but it can then be enabled for specific
modules at load time with a ' pc_debug = # ' option to insmod .
*/
# ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG ;
module_param ( pc_debug , int , 0 ) ;
static char * version = " $Revision: 1.2 $ " ;
# define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
# else
# define DEBUG(n, args...)
# endif
/*====================================================================*/
MODULE_AUTHOR ( " Benjamin Reed " ) ;
MODULE_DESCRIPTION ( " Support for Cisco/Aironet 802.11 wireless ethernet \
cards . This is the module that links the PCMCIA card \
with the airo module . " );
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
MODULE_SUPPORTED_DEVICE ( " Aironet 4500, 4800 and Cisco 340 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 airo_cs
event handler .
*/
2006-03-31 17:26:06 +02:00
static int airo_config ( struct pcmcia_device * link ) ;
2006-03-31 17:21:06 +02:00
static void airo_release ( struct pcmcia_device * link ) ;
2005-04-16 15:20:36 -07: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 21:23:14 +01:00
static void airo_detach ( struct pcmcia_device * p_dev ) ;
2005-04-16 15:20:36 -07:00
/*
You ' ll also need to prototype all the functions that will actually
be used to talk to your device . See ' pcmem_cs ' for a good example
of a fully self - sufficient driver ; the other drivers rely more or
less on other parts of the kernel .
*/
/*
A linked list of " instances " of the aironet device . Each actual
PCMCIA card corresponds to one device instance , and is described
2006-03-31 17:21:06 +02:00
by one struct pcmcia_device structure ( defined in ds . h ) .
2005-04-16 15:20:36 -07:00
You may not want to use a linked list for this - - for example , the
2006-03-31 17:21:06 +02:00
memory card driver uses an array of struct pcmcia_device pointers , where minor
2005-04-16 15:20:36 -07:00
device numbers are used to derive the corresponding array index .
*/
/*
A driver needs to provide a dev_node_t structure for each device
on a card . In some cases , there is only one device per card ( for
example , ethernet cards , modems ) . In other cases , there may be
many actual or logical devices ( SCSI adapters , memory cards with
multiple partitions ) . The dev_node_t structures need to be kept
2006-03-31 17:21:06 +02:00
in a linked list starting at the ' dev ' field of a struct pcmcia_device
2005-04-16 15:20:36 -07:00
structure . We allocate them in the card ' s private data structure ,
because they generally shouldn ' t be allocated dynamically .
In this case , we also provide a flag to indicate if a device is
" stopped " due to a power management event , or card ejection . The
device IO routines can use a flag like this to throttle IO to a
card that is not ready to accept it .
*/
typedef struct local_info_t {
dev_node_t node ;
struct net_device * eth_dev ;
} local_info_t ;
/*======================================================================
airo_attach ( ) creates an " instance " of the driver , allocating
local data structures for one device . The device is registered
with Card Services .
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-03-31 17:26:06 +02:00
static int airo_probe ( struct pcmcia_device * p_dev )
2005-04-16 15:20:36 -07:00
{
local_info_t * local ;
2005-11-14 21:25:51 +01:00
2005-04-16 15:20:36 -07:00
DEBUG ( 0 , " airo_attach() \n " ) ;
/* Interrupt setup */
2008-09-23 13:53:09 +01:00
p_dev - > irq . Attributes = IRQ_TYPE_DYNAMIC_SHARING ;
2006-03-05 10:45:09 +01:00
p_dev - > irq . IRQInfo1 = IRQ_LEVEL_ID ;
p_dev - > irq . Handler = NULL ;
2005-04-16 15:20:36 -07:00
/*
General socket configuration defaults can go here . In this
client , we assume very little , and rely on the CIS for almost
everything . In most clients , many details ( i . e . , number , sizes ,
and attributes of IO windows ) are fixed by the nature of the
device , and can be hard - wired here .
*/
2006-03-05 10:45:09 +01:00
p_dev - > conf . Attributes = 0 ;
p_dev - > conf . IntType = INT_MEMORY_AND_IO ;
2005-04-16 15:20:36 -07:00
/* Allocate space for private device-specific data */
2005-11-08 00:03:15 +01:00
local = kzalloc ( sizeof ( local_info_t ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! local ) {
printk ( KERN_ERR " airo_cs: no memory for new device \n " ) ;
2005-11-14 21:25:51 +01:00
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
}
2006-03-05 10:45:09 +01:00
p_dev - > priv = local ;
2005-11-14 21:25:51 +01:00
2006-03-31 17:26:06 +02:00
return airo_config ( p_dev ) ;
2005-04-16 15:20:36 -07:00
} /* airo_attach */
/*======================================================================
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-03-31 17:21:06 +02:00
static void airo_detach ( struct pcmcia_device * link )
2005-04-16 15:20:36 -07:00
{
DEBUG ( 0 , " airo_detach(0x%p) \n " , link ) ;
2005-11-14 21:25:35 +01:00
2006-03-02 00:09:29 +01:00
airo_release ( link ) ;
2005-11-14 21:25:35 +01:00
2005-04-16 15:20:36 -07:00
if ( ( ( local_info_t * ) link - > priv ) - > eth_dev ) {
stop_airo_card ( ( ( local_info_t * ) link - > priv ) - > eth_dev , 0 ) ;
}
2005-11-14 21:23:14 +01:00
( ( local_info_t * ) link - > priv ) - > eth_dev = NULL ;
2005-10-28 16:53:13 -04:00
kfree ( link - > priv ) ;
2005-04-16 15:20:36 -07:00
} /* airo_detach */
/*======================================================================
airo_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 .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# define CS_CHECK(fn, ret) \
do { last_fn = ( fn ) ; if ( ( last_ret = ( ret ) ) ! = 0 ) goto cs_failed ; } while ( 0 )
2008-08-02 14:28:43 +02:00
static int airo_cs_config_check ( struct pcmcia_device * p_dev ,
cistpl_cftable_entry_t * cfg ,
2008-08-02 15:30:31 +02:00
cistpl_cftable_entry_t * dflt ,
2008-08-02 16:12:00 +02:00
unsigned int vcc ,
2008-08-02 14:28:43 +02:00
void * priv_data )
{
2008-08-02 15:30:31 +02:00
win_req_t * req = priv_data ;
2008-08-02 14:28:43 +02:00
if ( cfg - > index = = 0 )
return - ENODEV ;
/* Does this card need audio output? */
if ( cfg - > flags & CISTPL_CFTABLE_AUDIO ) {
p_dev - > conf . Attributes | = CONF_ENABLE_SPKR ;
p_dev - > conf . Status = CCSR_AUDIO_ENA ;
}
/* Use power settings for Vcc and Vpp if present */
/* Note that the CIS values need to be rescaled */
if ( cfg - > vpp1 . present & ( 1 < < CISTPL_POWER_VNOM ) )
p_dev - > conf . Vpp = cfg - > vpp1 . param [ CISTPL_POWER_VNOM ] / 10000 ;
2008-08-02 15:30:31 +02:00
else if ( dflt - > vpp1 . present & ( 1 < < CISTPL_POWER_VNOM ) )
p_dev - > conf . Vpp = dflt - > vpp1 . param [ CISTPL_POWER_VNOM ] / 10000 ;
2008-08-02 14:28:43 +02:00
/* Do we need to allocate an interrupt? */
2008-08-02 15:30:31 +02:00
if ( cfg - > irq . IRQInfo1 | | dflt - > irq . IRQInfo1 )
2008-08-02 14:28:43 +02:00
p_dev - > conf . Attributes | = CONF_ENABLE_IRQ ;
/* IO window settings */
p_dev - > io . NumPorts1 = p_dev - > io . NumPorts2 = 0 ;
2008-08-02 15:30:31 +02:00
if ( ( cfg - > io . nwin > 0 ) | | ( dflt - > io . nwin > 0 ) ) {
cistpl_io_t * io = ( cfg - > io . nwin ) ? & cfg - > io : & dflt - > io ;
2008-08-02 14:28:43 +02:00
p_dev - > io . Attributes1 = IO_DATA_PATH_WIDTH_AUTO ;
if ( ! ( io - > flags & CISTPL_IO_8BIT ) )
p_dev - > io . Attributes1 = IO_DATA_PATH_WIDTH_16 ;
if ( ! ( io - > flags & CISTPL_IO_16BIT ) )
p_dev - > io . Attributes1 = IO_DATA_PATH_WIDTH_8 ;
p_dev - > io . BasePort1 = io - > win [ 0 ] . base ;
p_dev - > io . NumPorts1 = io - > win [ 0 ] . len ;
if ( io - > nwin > 1 ) {
p_dev - > io . Attributes2 = p_dev - > io . Attributes1 ;
p_dev - > io . BasePort2 = io - > win [ 1 ] . base ;
p_dev - > io . NumPorts2 = io - > win [ 1 ] . len ;
}
}
/* This reserves IO space but doesn't actually enable it */
if ( pcmcia_request_io ( p_dev , & p_dev - > io ) ! = 0 )
return - ENODEV ;
/*
Now set up a common memory window , if needed . There is room
in the struct pcmcia_device structure for one memory window handle ,
but if the base addresses need to be saved , or if multiple
windows are needed , the info should go in the private data
structure for this device .
Note that the memory window base is a physical address , and
needs to be mapped to virtual space with ioremap ( ) before it
is used .
*/
2008-08-02 15:30:31 +02:00
if ( ( cfg - > mem . nwin > 0 ) | | ( dflt - > mem . nwin > 0 ) ) {
cistpl_mem_t * mem = ( cfg - > mem . nwin ) ? & cfg - > mem : & dflt - > mem ;
2008-08-02 14:28:43 +02:00
memreq_t map ;
2008-08-02 15:30:31 +02:00
req - > Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM ;
req - > Base = mem - > win [ 0 ] . host_addr ;
req - > Size = mem - > win [ 0 ] . len ;
req - > AccessSpeed = 0 ;
if ( pcmcia_request_window ( & p_dev , req , & p_dev - > win ) ! = 0 )
2008-08-02 14:28:43 +02:00
return - ENODEV ;
map . Page = 0 ;
map . CardOffset = mem - > win [ 0 ] . card_addr ;
if ( pcmcia_map_mem_page ( p_dev - > win , & map ) ! = 0 )
return - ENODEV ;
}
/* If we got this far, we're cool! */
return 0 ;
}
2006-03-31 17:26:06 +02:00
static int airo_config ( struct pcmcia_device * link )
2005-04-16 15:20:36 -07:00
{
local_info_t * dev ;
2008-08-02 15:30:31 +02:00
win_req_t * req ;
2005-04-16 15:20:36 -07:00
int last_fn , last_ret ;
2006-03-31 17:21:06 +02:00
2005-04-16 15:20:36 -07:00
dev = link - > priv ;
DEBUG ( 0 , " airo_config(0x%p) \n " , link ) ;
2006-03-02 00:09:29 +01:00
2008-08-02 15:30:31 +02:00
req = kzalloc ( sizeof ( win_req_t ) , GFP_KERNEL ) ;
if ( ! req )
2008-08-02 14:28:43 +02:00
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
/*
2008-08-02 14:28:43 +02: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 .
*
* 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 15:30:31 +02:00
last_ret = pcmcia_loop_config ( link , airo_cs_config_check , req ) ;
2008-08-02 14:28:43 +02:00
if ( last_ret )
goto failed ;
2005-04-16 15:20:36 -07:00
/*
2008-08-02 14:28:43 +02:00
Allocate an interrupt line . Note that this does not assign a
handler to the interrupt , unless the ' Handler ' member of the
irq structure is initialized .
2005-04-16 15:20:36 -07:00
*/
if ( link - > conf . Attributes & CONF_ENABLE_IRQ )
2006-03-31 17:21:06 +02:00
CS_CHECK ( RequestIRQ , pcmcia_request_irq ( link , & link - > irq ) ) ;
2005-04-16 15:20:36 -07: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 .
*/
2006-03-31 17:21:06 +02:00
CS_CHECK ( RequestConfiguration , pcmcia_request_configuration ( link , & link - > conf ) ) ;
2005-04-16 15:20:36 -07:00
( ( local_info_t * ) link - > priv ) - > eth_dev =
init_airo_card ( link - > irq . AssignedIRQ ,
2006-03-31 17:21:06 +02:00
link - > io . BasePort1 , 1 , & handle_to_dev ( link ) ) ;
2005-04-16 15:20:36 -07:00
if ( ! ( ( local_info_t * ) link - > priv ) - > eth_dev ) goto cs_failed ;
/*
At this point , the dev_node_t structure ( s ) need to be
2006-03-05 10:45:09 +01:00
initialized and arranged in a linked list at link - > dev_node .
2005-04-16 15:20:36 -07:00
*/
strcpy ( dev - > node . dev_name , ( ( local_info_t * ) link - > priv ) - > eth_dev - > name ) ;
dev - > node . major = dev - > node . minor = 0 ;
2006-03-05 10:45:09 +01:00
link - > dev_node = & dev - > node ;
2005-04-16 15:20:36 -07:00
/* Finally, report what we've done */
2006-01-15 12:43:16 +01:00
printk ( KERN_INFO " %s: index 0x%02x: " ,
dev - > node . dev_name , link - > conf . ConfigIndex ) ;
if ( link - > conf . Vpp )
printk ( " , Vpp %d.%d " , link - > conf . Vpp / 10 , link - > conf . Vpp % 10 ) ;
2005-04-16 15:20:36 -07:00
if ( link - > conf . Attributes & CONF_ENABLE_IRQ )
printk ( " , irq %d " , link - > irq . AssignedIRQ ) ;
if ( link - > io . NumPorts1 )
printk ( " , io 0x%04x-0x%04x " , link - > io . BasePort1 ,
link - > io . BasePort1 + link - > io . NumPorts1 - 1 ) ;
if ( link - > io . NumPorts2 )
printk ( " & 0x%04x-0x%04x " , link - > io . BasePort2 ,
link - > io . BasePort2 + link - > io . NumPorts2 - 1 ) ;
if ( link - > win )
2008-08-02 15:30:31 +02:00
printk ( " , mem 0x%06lx-0x%06lx " , req - > Base ,
req - > Base + req - > Size - 1 ) ;
2005-04-16 15:20:36 -07:00
printk ( " \n " ) ;
2008-08-02 15:30:31 +02:00
kfree ( req ) ;
2006-03-31 17:26:06 +02:00
return 0 ;
2005-04-16 15:20:36 -07:00
cs_failed :
2006-03-31 17:21:06 +02:00
cs_error ( link , last_fn , last_ret ) ;
2008-08-02 14:28:43 +02:00
failed :
2005-04-16 15:20:36 -07:00
airo_release ( link ) ;
2008-08-02 15:30:31 +02:00
kfree ( req ) ;
2006-03-31 17:26:06 +02:00
return - ENODEV ;
2005-04-16 15:20:36 -07:00
} /* airo_config */
/*======================================================================
After a card is removed , airo_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-03-31 17:21:06 +02:00
static void airo_release ( struct pcmcia_device * link )
2005-04-16 15:20:36 -07:00
{
DEBUG ( 0 , " airo_release(0x%p) \n " , link ) ;
2006-03-31 17:21:06 +02:00
pcmcia_disable_device ( link ) ;
2005-04-16 15:20:36 -07:00
}
2006-03-31 17:21:06 +02:00
static int airo_suspend ( struct pcmcia_device * link )
2005-11-14 21:21:18 +01:00
{
local_info_t * local = link - > priv ;
2006-03-02 00:09:29 +01:00
netif_device_detach ( local - > eth_dev ) ;
2005-11-14 21:21:18 +01:00
return 0 ;
}
2006-03-31 17:21:06 +02:00
static int airo_resume ( struct pcmcia_device * link )
2005-11-14 21:21:18 +01:00
{
local_info_t * local = link - > priv ;
2006-03-02 00:09:29 +01:00
if ( link - > open ) {
2005-11-14 21:21:18 +01:00
reset_airo_card ( local - > eth_dev ) ;
netif_device_attach ( local - > eth_dev ) ;
}
return 0 ;
}
2005-06-27 16:28:20 -07:00
static struct pcmcia_device_id airo_ids [ ] = {
PCMCIA_DEVICE_MANF_CARD ( 0x015f , 0x000a ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x015f , 0x0005 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x015f , 0x0007 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x0105 , 0x0007 ) ,
PCMCIA_DEVICE_NULL ,
} ;
MODULE_DEVICE_TABLE ( pcmcia , airo_ids ) ;
2005-04-16 15:20:36 -07:00
static struct pcmcia_driver airo_driver = {
. owner = THIS_MODULE ,
. drv = {
. name = " airo_cs " ,
} ,
2006-03-31 17:26:06 +02:00
. probe = airo_probe ,
2005-11-14 21:23:14 +01:00
. remove = airo_detach ,
2005-06-27 16:28:20 -07:00
. id_table = airo_ids ,
2005-11-14 21:21:18 +01:00
. suspend = airo_suspend ,
. resume = airo_resume ,
2005-04-16 15:20:36 -07:00
} ;
static int airo_cs_init ( void )
{
return pcmcia_register_driver ( & airo_driver ) ;
}
static void airo_cs_cleanup ( void )
{
pcmcia_unregister_driver ( & airo_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
POSSIBILITY OF SUCH DAMAGE .
*/
module_init ( airo_cs_init ) ;
module_exit ( airo_cs_cleanup ) ;