2005-05-12 22:54:16 -04:00
# define PRISM2_PCCARD
# include <linux/module.h>
# include <linux/init.h>
# include <linux/if.h>
# include <linux/wait.h>
# include <linux/timer.h>
# include <linux/skbuff.h>
# include <linux/netdevice.h>
# include <linux/workqueue.h>
# include <linux/wireless.h>
# include <net/iw_handler.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 "hostap_wlan.h"
static dev_info_t dev_info = " hostap_cs " ;
MODULE_AUTHOR ( " Jouni Malinen " ) ;
MODULE_DESCRIPTION ( " Support for Intersil Prism2-based 802.11 wireless LAN "
" cards (PC Card). " ) ;
MODULE_SUPPORTED_DEVICE ( " Intersil Prism2-based WLAN cards (PC Card) " ) ;
MODULE_LICENSE ( " GPL " ) ;
static int ignore_cis_vcc ;
module_param ( ignore_cis_vcc , int , 0444 ) ;
MODULE_PARM_DESC ( ignore_cis_vcc , " Ignore broken CIS VCC entry " ) ;
2005-08-14 19:08:41 -07:00
/* struct local_info::hw_priv */
struct hostap_cs_priv {
dev_node_t node ;
2006-03-31 17:21:06 +02:00
struct pcmcia_device * link ;
2005-08-14 19:08:41 -07:00
int sandisk_connectplus ;
} ;
2005-05-12 22:54:16 -04:00
# ifdef PRISM2_IO_DEBUG
static inline void hfa384x_outb_debug ( struct net_device * dev , int a , u8 v )
{
struct hostap_interface * iface ;
local_info_t * local ;
unsigned long flags ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
spin_lock_irqsave ( & local - > lock , flags ) ;
prism2_io_debug_add ( dev , PRISM2_IO_DEBUG_CMD_OUTB , a , v ) ;
outb ( v , dev - > base_addr + a ) ;
spin_unlock_irqrestore ( & local - > lock , flags ) ;
}
static inline u8 hfa384x_inb_debug ( struct net_device * dev , int a )
{
struct hostap_interface * iface ;
local_info_t * local ;
unsigned long flags ;
u8 v ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
spin_lock_irqsave ( & local - > lock , flags ) ;
v = inb ( dev - > base_addr + a ) ;
prism2_io_debug_add ( dev , PRISM2_IO_DEBUG_CMD_INB , a , v ) ;
spin_unlock_irqrestore ( & local - > lock , flags ) ;
return v ;
}
static inline void hfa384x_outw_debug ( struct net_device * dev , int a , u16 v )
{
struct hostap_interface * iface ;
local_info_t * local ;
unsigned long flags ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
spin_lock_irqsave ( & local - > lock , flags ) ;
prism2_io_debug_add ( dev , PRISM2_IO_DEBUG_CMD_OUTW , a , v ) ;
outw ( v , dev - > base_addr + a ) ;
spin_unlock_irqrestore ( & local - > lock , flags ) ;
}
static inline u16 hfa384x_inw_debug ( struct net_device * dev , int a )
{
struct hostap_interface * iface ;
local_info_t * local ;
unsigned long flags ;
u16 v ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
spin_lock_irqsave ( & local - > lock , flags ) ;
v = inw ( dev - > base_addr + a ) ;
prism2_io_debug_add ( dev , PRISM2_IO_DEBUG_CMD_INW , a , v ) ;
spin_unlock_irqrestore ( & local - > lock , flags ) ;
return v ;
}
static inline void hfa384x_outsw_debug ( struct net_device * dev , int a ,
u8 * buf , int wc )
{
struct hostap_interface * iface ;
local_info_t * local ;
unsigned long flags ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
spin_lock_irqsave ( & local - > lock , flags ) ;
prism2_io_debug_add ( dev , PRISM2_IO_DEBUG_CMD_OUTSW , a , wc ) ;
outsw ( dev - > base_addr + a , buf , wc ) ;
spin_unlock_irqrestore ( & local - > lock , flags ) ;
}
static inline void hfa384x_insw_debug ( struct net_device * dev , int a ,
u8 * buf , int wc )
{
struct hostap_interface * iface ;
local_info_t * local ;
unsigned long flags ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
spin_lock_irqsave ( & local - > lock , flags ) ;
prism2_io_debug_add ( dev , PRISM2_IO_DEBUG_CMD_INSW , a , wc ) ;
insw ( dev - > base_addr + a , buf , wc ) ;
spin_unlock_irqrestore ( & local - > lock , flags ) ;
}
# define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
# define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
# define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
# define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
# define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
# define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
# else /* PRISM2_IO_DEBUG */
# define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
# define HFA384X_INB(a) inb(dev->base_addr + (a))
# define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
# define HFA384X_INW(a) inw(dev->base_addr + (a))
# define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
# define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
# endif /* PRISM2_IO_DEBUG */
static int hfa384x_from_bap ( struct net_device * dev , u16 bap , void * buf ,
int len )
{
u16 d_off ;
u16 * pos ;
d_off = ( bap = = 1 ) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF ;
pos = ( u16 * ) buf ;
if ( len / 2 )
HFA384X_INSW ( d_off , buf , len / 2 ) ;
pos + = len / 2 ;
if ( len & 1 )
* ( ( char * ) pos ) = HFA384X_INB ( d_off ) ;
return 0 ;
}
static int hfa384x_to_bap ( struct net_device * dev , u16 bap , void * buf , int len )
{
u16 d_off ;
u16 * pos ;
d_off = ( bap = = 1 ) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF ;
pos = ( u16 * ) buf ;
if ( len / 2 )
HFA384X_OUTSW ( d_off , buf , len / 2 ) ;
pos + = len / 2 ;
if ( len & 1 )
HFA384X_OUTB ( * ( ( char * ) pos ) , d_off ) ;
return 0 ;
}
/* FIX: This might change at some point.. */
# include "hostap_hw.c"
2005-11-14 21:23:14 +01:00
static void prism2_detach ( struct pcmcia_device * p_dev ) ;
2005-05-12 22:54:16 -04:00
static void prism2_release ( u_long arg ) ;
2006-03-31 17:21:06 +02:00
static int prism2_config ( struct pcmcia_device * link ) ;
2005-05-12 22:54:16 -04:00
static int prism2_pccard_card_present ( local_info_t * local )
{
2005-08-14 19:08:41 -07:00
struct hostap_cs_priv * hw_priv = local - > hw_priv ;
2006-03-05 11:04:33 +01:00
if ( hw_priv ! = NULL & & hw_priv - > link ! = NULL & & pcmcia_dev_present ( hw_priv - > link ) )
2005-05-12 22:54:16 -04:00
return 1 ;
return 0 ;
}
/*
* SanDisk CompactFlash WLAN Flashcard - Product Manual v1 .0
* Document No . 20 - 10 - 0005 8 , January 2004
* http : //www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf
*/
# define SANDISK_WLAN_ACTIVATION_OFF 0x40
# define SANDISK_HCR_OFF 0x42
static void sandisk_set_iobase ( local_info_t * local )
{
int res ;
conf_reg_t reg ;
2005-08-14 19:08:41 -07:00
struct hostap_cs_priv * hw_priv = local - > hw_priv ;
2005-05-12 22:54:16 -04:00
reg . Function = 0 ;
reg . Action = CS_WRITE ;
reg . Offset = 0x10 ; /* 0x3f0 IO base 1 */
2005-08-14 19:08:41 -07:00
reg . Value = hw_priv - > link - > io . BasePort1 & 0x00ff ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " Prism3 SanDisk - failed to set I/O base 0 - "
" res=%d \n " , res ) ;
}
udelay ( 10 ) ;
reg . Function = 0 ;
reg . Action = CS_WRITE ;
reg . Offset = 0x12 ; /* 0x3f2 IO base 2 */
2005-08-14 19:08:41 -07:00
reg . Value = ( hw_priv - > link - > io . BasePort1 & 0xff00 ) > > 8 ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " Prism3 SanDisk - failed to set I/O base 1 - "
" res=%d \n " , res ) ;
}
}
static void sandisk_write_hcr ( local_info_t * local , int hcr )
{
struct net_device * dev = local - > dev ;
int i ;
HFA384X_OUTB ( 0x80 , SANDISK_WLAN_ACTIVATION_OFF ) ;
udelay ( 50 ) ;
for ( i = 0 ; i < 10 ; i + + ) {
HFA384X_OUTB ( hcr , SANDISK_HCR_OFF ) ;
}
udelay ( 55 ) ;
HFA384X_OUTB ( 0x45 , SANDISK_WLAN_ACTIVATION_OFF ) ;
}
static int sandisk_enable_wireless ( struct net_device * dev )
{
int res , ret = 0 ;
conf_reg_t reg ;
2007-08-03 19:37:16 +02:00
struct hostap_interface * iface = netdev_priv ( dev ) ;
2005-05-12 22:54:16 -04:00
local_info_t * local = iface - > local ;
2005-08-14 19:08:41 -07:00
struct hostap_cs_priv * hw_priv = local - > hw_priv ;
2005-05-12 22:54:16 -04:00
2005-08-14 19:08:41 -07:00
if ( hw_priv - > link - > io . NumPorts1 < 0x42 ) {
2005-05-12 22:54:16 -04:00
/* Not enough ports to be SanDisk multi-function card */
ret = - ENODEV ;
goto done ;
}
2006-10-25 21:28:53 -04:00
if ( hw_priv - > link - > manf_id ! = 0xd601 | | hw_priv - > link - > card_id ! = 0x0101 ) {
2005-05-12 22:54:16 -04:00
/* No SanDisk manfid found */
ret = - ENODEV ;
goto done ;
}
2009-10-18 18:22:32 +02:00
if ( hw_priv - > link - > socket - > functions < 2 ) {
2005-05-12 22:54:16 -04:00
/* No multi-function links found */
ret = - ENODEV ;
goto done ;
}
printk ( KERN_DEBUG " %s: Multi-function SanDisk ConnectPlus detected "
" - using vendor-specific initialization \n " , dev - > name ) ;
2005-08-14 19:08:41 -07:00
hw_priv - > sandisk_connectplus = 1 ;
2005-05-12 22:54:16 -04:00
reg . Function = 0 ;
reg . Action = CS_WRITE ;
reg . Offset = CISREG_COR ;
reg . Value = COR_SOFT_RESET ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " %s: SanDisk - COR sreset failed (%d) \n " ,
dev - > name , res ) ;
goto done ;
}
mdelay ( 5 ) ;
reg . Function = 0 ;
reg . Action = CS_WRITE ;
reg . Offset = CISREG_COR ;
/*
* Do not enable interrupts here to avoid some bogus events . Interrupts
* will be enabled during the first cor_sreset call .
*/
reg . Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " %s: SanDisk - COR sreset failed (%d) \n " ,
dev - > name , res ) ;
goto done ;
}
mdelay ( 5 ) ;
sandisk_set_iobase ( local ) ;
HFA384X_OUTB ( 0xc5 , SANDISK_WLAN_ACTIVATION_OFF ) ;
udelay ( 10 ) ;
HFA384X_OUTB ( 0x4b , SANDISK_WLAN_ACTIVATION_OFF ) ;
udelay ( 10 ) ;
done :
return ret ;
}
static void prism2_pccard_cor_sreset ( local_info_t * local )
{
int res ;
conf_reg_t reg ;
2005-08-14 19:08:41 -07:00
struct hostap_cs_priv * hw_priv = local - > hw_priv ;
2005-05-12 22:54:16 -04:00
if ( ! prism2_pccard_card_present ( local ) )
return ;
reg . Function = 0 ;
reg . Action = CS_READ ;
reg . Offset = CISREG_COR ;
reg . Value = 0 ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " prism2_pccard_cor_sreset failed 1 (%d) \n " ,
res ) ;
return ;
}
printk ( KERN_DEBUG " prism2_pccard_cor_sreset: original COR %02x \n " ,
reg . Value ) ;
reg . Action = CS_WRITE ;
reg . Value | = COR_SOFT_RESET ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " prism2_pccard_cor_sreset failed 2 (%d) \n " ,
res ) ;
return ;
}
2005-08-14 19:08:41 -07:00
mdelay ( hw_priv - > sandisk_connectplus ? 5 : 2 ) ;
2005-05-12 22:54:16 -04:00
reg . Value & = ~ COR_SOFT_RESET ;
2005-08-14 19:08:41 -07:00
if ( hw_priv - > sandisk_connectplus )
2005-05-12 22:54:16 -04:00
reg . Value | = COR_IREQ_ENA ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " prism2_pccard_cor_sreset failed 3 (%d) \n " ,
res ) ;
return ;
}
2005-08-14 19:08:41 -07:00
mdelay ( hw_priv - > sandisk_connectplus ? 5 : 2 ) ;
2005-05-12 22:54:16 -04:00
2005-08-14 19:08:41 -07:00
if ( hw_priv - > sandisk_connectplus )
2005-05-12 22:54:16 -04:00
sandisk_set_iobase ( local ) ;
}
static void prism2_pccard_genesis_reset ( local_info_t * local , int hcr )
{
int res ;
conf_reg_t reg ;
int old_cor ;
2005-08-14 19:08:41 -07:00
struct hostap_cs_priv * hw_priv = local - > hw_priv ;
2005-05-12 22:54:16 -04:00
if ( ! prism2_pccard_card_present ( local ) )
return ;
2005-08-14 19:08:41 -07:00
if ( hw_priv - > sandisk_connectplus ) {
2005-05-12 22:54:16 -04:00
sandisk_write_hcr ( local , hcr ) ;
return ;
}
reg . Function = 0 ;
reg . Action = CS_READ ;
reg . Offset = CISREG_COR ;
reg . Value = 0 ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " prism2_pccard_genesis_sreset failed 1 "
" (%d) \n " , res ) ;
return ;
}
printk ( KERN_DEBUG " prism2_pccard_genesis_sreset: original COR %02x \n " ,
reg . Value ) ;
old_cor = reg . Value ;
reg . Action = CS_WRITE ;
reg . Value | = COR_SOFT_RESET ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " prism2_pccard_genesis_sreset failed 2 "
" (%d) \n " , res ) ;
return ;
}
mdelay ( 10 ) ;
/* Setup Genesis mode */
reg . Action = CS_WRITE ;
reg . Value = hcr ;
reg . Offset = CISREG_CCSR ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " prism2_pccard_genesis_sreset failed 3 "
" (%d) \n " , res ) ;
return ;
}
mdelay ( 10 ) ;
reg . Action = CS_WRITE ;
reg . Offset = CISREG_COR ;
reg . Value = old_cor & ~ COR_SOFT_RESET ;
2006-03-31 17:21:06 +02:00
res = pcmcia_access_configuration_register ( hw_priv - > link ,
2005-08-14 19:08:41 -07:00
& reg ) ;
2008-08-03 10:07:45 +02:00
if ( res ! = 0 ) {
2005-05-12 22:54:16 -04:00
printk ( KERN_DEBUG " prism2_pccard_genesis_sreset failed 4 "
" (%d) \n " , res ) ;
return ;
}
mdelay ( 10 ) ;
}
static struct prism2_helper_functions prism2_pccard_funcs =
{
. card_present = prism2_pccard_card_present ,
. cor_sreset = prism2_pccard_cor_sreset ,
. genesis_reset = prism2_pccard_genesis_reset ,
. hw_type = HOSTAP_HW_PCCARD ,
} ;
/* allocate local data and register with CardServices
* initialize dev_link structure , but do not configure the card yet */
2006-03-31 17:26:06 +02:00
static int hostap_cs_probe ( struct pcmcia_device * p_dev )
2005-05-12 22:54:16 -04:00
{
2006-03-31 17:26:06 +02:00
int ret ;
2005-05-12 22:54:16 -04:00
PDEBUG ( DEBUG_HW , " %s: setting Vcc=33 (constant) \n " , dev_info ) ;
2006-03-05 10:45:09 +01:00
p_dev - > conf . IntType = INT_MEMORY_AND_IO ;
2005-11-14 21:25:51 +01:00
2006-03-31 17:26:06 +02:00
ret = prism2_config ( p_dev ) ;
if ( ret ) {
2005-11-14 21:25:51 +01:00
PDEBUG ( DEBUG_EXTRA , " prism2_config() failed \n " ) ;
2006-03-31 17:26:06 +02:00
}
2005-11-14 21:25:51 +01:00
2006-03-31 17:26:06 +02:00
return ret ;
2005-05-12 22:54:16 -04:00
}
2006-03-31 17:21:06 +02:00
static void prism2_detach ( struct pcmcia_device * link )
2005-05-12 22:54:16 -04:00
{
PDEBUG ( DEBUG_FLOW , " prism2_detach \n " ) ;
2006-03-02 00:09:29 +01:00
prism2_release ( ( u_long ) link ) ;
2005-05-12 22:54:16 -04:00
/* release net devices */
if ( link - > priv ) {
2005-10-02 17:19:00 -07:00
struct hostap_cs_priv * hw_priv ;
2005-08-14 19:08:41 -07:00
struct net_device * dev ;
struct hostap_interface * iface ;
dev = link - > priv ;
iface = netdev_priv ( dev ) ;
2005-10-02 17:19:00 -07:00
hw_priv = iface - > local - > hw_priv ;
2005-08-14 19:08:41 -07:00
prism2_free_local_data ( dev ) ;
2005-10-02 17:19:00 -07:00
kfree ( hw_priv ) ;
2005-05-12 22:54:16 -04:00
}
}
/* run after a CARD_INSERTION event is received to configure the PCMCIA
* socket and make the device available to the system */
2008-08-02 14:28:43 +02:00
static int prism2_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 )
{
if ( cfg - > index = = 0 )
return - ENODEV ;
PDEBUG ( DEBUG_EXTRA , " Checking CFTABLE_ENTRY 0x%02X "
2008-08-02 15:30:31 +02:00
" (default 0x%02X) \n " , cfg - > index , dflt - > index ) ;
2008-08-02 14:28:43 +02:00
/* 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 - > vcc . present & ( 1 < < CISTPL_POWER_VNOM ) ) {
2008-08-02 16:12:00 +02:00
if ( vcc ! = cfg - > vcc . param [ CISTPL_POWER_VNOM ] /
2008-08-02 14:28:43 +02:00
10000 & & ! ignore_cis_vcc ) {
PDEBUG ( DEBUG_EXTRA , " Vcc mismatch - skipping "
" this entry \n " ) ;
return - ENODEV ;
}
2008-08-02 15:30:31 +02:00
} else if ( dflt - > vcc . present & ( 1 < < CISTPL_POWER_VNOM ) ) {
2008-08-02 16:12:00 +02:00
if ( vcc ! = dflt - > vcc . param [ CISTPL_POWER_VNOM ] /
2008-08-02 14:28:43 +02:00
10000 & & ! ignore_cis_vcc ) {
PDEBUG ( DEBUG_EXTRA , " Vcc (default) mismatch "
" - skipping this entry \n " ) ;
return - ENODEV ;
}
}
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 ;
else if ( ! ( p_dev - > conf . Attributes & CONF_ENABLE_IRQ ) ) {
/* At least Compaq WL200 does not have IRQInfo1 set,
* but it does not work without interrupts . . */
printk ( KERN_WARNING " Config has no IRQ info, but trying to "
" enable IRQ anyway.. \n " ) ;
p_dev - > conf . Attributes | = CONF_ENABLE_IRQ ;
}
/* IO window settings */
PDEBUG ( DEBUG_EXTRA , " IO window settings: cfg->io.nwin=%d "
2008-08-02 15:30:31 +02:00
" dflt->io.nwin=%d \n " ,
cfg - > io . nwin , dflt - > io . nwin ) ;
2008-08-02 14:28:43 +02:00
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 ;
PDEBUG ( DEBUG_EXTRA , " io->flags = 0x%04X, "
" io.base=0x%04x, len=%d \n " , io - > flags ,
io - > win [ 0 ] . base , io - > win [ 0 ] . len ) ;
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 . IOAddrLines = io - > flags &
CISTPL_IO_LINES_MASK ;
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 */
return pcmcia_request_io ( p_dev , & p_dev - > io ) ;
}
2006-03-31 17:21:06 +02:00
static int prism2_config ( struct pcmcia_device * link )
2005-05-12 22:54:16 -04:00
{
struct net_device * dev ;
struct hostap_interface * iface ;
local_info_t * local ;
int ret = 1 ;
2005-08-14 19:08:41 -07:00
struct hostap_cs_priv * hw_priv ;
2005-05-12 22:54:16 -04:00
PDEBUG ( DEBUG_FLOW , " prism2_config() \n " ) ;
2006-12-02 13:33:40 +02:00
hw_priv = kzalloc ( sizeof ( * hw_priv ) , GFP_KERNEL ) ;
2008-08-02 14:28:43 +02:00
if ( hw_priv = = NULL ) {
2005-05-12 22:54:16 -04:00
ret = - ENOMEM ;
goto failed ;
}
/* Look for an appropriate configuration table entry in the CIS */
2009-10-24 15:53:36 +02:00
ret = pcmcia_loop_config ( link , prism2_config_check , NULL ) ;
if ( ret ) {
2008-08-02 14:28:43 +02:00
if ( ! ignore_cis_vcc )
printk ( KERN_ERR " GetNextTuple(): No matching "
" CIS configuration. Maybe you need the "
" ignore_cis_vcc=1 parameter. \n " ) ;
goto failed ;
2005-05-12 22:54:16 -04:00
}
/* Need to allocate net_device before requesting IRQ handler */
2005-07-30 12:49:58 -07:00
dev = prism2_init_local_data ( & prism2_pccard_funcs , 0 ,
2009-11-03 10:27:34 +01:00
& link - > dev ) ;
2005-05-12 22:54:16 -04:00
if ( dev = = NULL )
goto failed ;
link - > priv = dev ;
2005-08-28 17:53:32 -07:00
iface = netdev_priv ( dev ) ;
local = iface - > local ;
local - > hw_priv = hw_priv ;
hw_priv - > link = link ;
strcpy ( hw_priv - > node . dev_name , dev - > name ) ;
2006-03-05 10:45:09 +01:00
link - > dev_node = & hw_priv - > node ;
2005-08-28 17:53:32 -07:00
2005-05-12 22:54:16 -04: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 .
*/
if ( link - > conf . Attributes & CONF_ENABLE_IRQ ) {
2009-11-08 17:24:46 +01:00
link - > irq . Attributes = IRQ_TYPE_DYNAMIC_SHARING ;
2005-05-12 22:54:16 -04:00
link - > irq . Handler = prism2_interrupt ;
2009-10-24 15:53:36 +02:00
ret = pcmcia_request_irq ( link , & link - > irq ) ;
if ( ret )
goto failed ;
2005-05-12 22:54:16 -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 .
*/
2009-10-24 15:53:36 +02:00
ret = pcmcia_request_configuration ( link , & link - > conf ) ;
if ( ret )
goto failed ;
2005-05-12 22:54:16 -04:00
dev - > irq = link - > irq . AssignedIRQ ;
dev - > base_addr = link - > io . BasePort1 ;
/* Finally, report what we've done */
2006-01-15 12:43:16 +01:00
printk ( KERN_INFO " %s: index 0x%02x: " ,
dev_info , link - > conf . ConfigIndex ) ;
if ( link - > conf . Vpp )
printk ( " , Vpp %d.%d " , link - > conf . Vpp / 10 ,
link - > conf . Vpp % 10 ) ;
2005-05-12 22:54:16 -04: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 ) ;
printk ( " \n " ) ;
local - > shutdown = 0 ;
sandisk_enable_wireless ( dev ) ;
ret = prism2_hw_config ( dev , 1 ) ;
if ( ! ret ) {
ret = hostap_hw_ready ( dev ) ;
if ( ret = = 0 & & local - > ddev )
2005-08-14 19:08:41 -07:00
strcpy ( hw_priv - > node . dev_name , local - > ddev - > name ) ;
2005-05-12 22:54:16 -04:00
}
return ret ;
failed :
2005-08-14 19:08:41 -07:00
kfree ( hw_priv ) ;
2005-05-12 22:54:16 -04:00
prism2_release ( ( u_long ) link ) ;
return ret ;
}
static void prism2_release ( u_long arg )
{
2006-03-31 17:21:06 +02:00
struct pcmcia_device * link = ( struct pcmcia_device * ) arg ;
2005-05-12 22:54:16 -04:00
PDEBUG ( DEBUG_FLOW , " prism2_release \n " ) ;
if ( link - > priv ) {
struct net_device * dev = link - > priv ;
struct hostap_interface * iface ;
iface = netdev_priv ( dev ) ;
2006-03-02 00:09:29 +01:00
prism2_hw_shutdown ( dev , 0 ) ;
2005-05-12 22:54:16 -04:00
iface - > local - > shutdown = 1 ;
}
2006-03-31 17:21:06 +02:00
pcmcia_disable_device ( link ) ;
2005-05-12 22:54:16 -04:00
PDEBUG ( DEBUG_FLOW , " release - done \n " ) ;
}
2006-03-31 17:21:06 +02:00
static int hostap_cs_suspend ( struct pcmcia_device * link )
2005-11-14 21:21:18 +01:00
{
struct net_device * dev = ( struct net_device * ) link - > priv ;
int dev_open = 0 ;
2006-03-02 00:09:29 +01:00
struct hostap_interface * iface = NULL ;
2005-05-12 22:54:16 -04:00
2008-07-02 11:04:24 -04:00
if ( ! dev )
return - ENODEV ;
iface = netdev_priv ( dev ) ;
2005-11-14 21:21:18 +01:00
2006-03-02 00:09:29 +01:00
PDEBUG ( DEBUG_EXTRA , " %s: CS_EVENT_PM_SUSPEND \n " , dev_info ) ;
if ( iface & & iface - > local )
dev_open = iface - > local - > num_dev_open > 0 ;
if ( dev_open ) {
netif_stop_queue ( dev ) ;
netif_device_detach ( dev ) ;
2005-11-14 21:21:18 +01:00
}
2006-03-02 00:09:29 +01:00
prism2_suspend ( dev ) ;
2005-11-14 21:21:18 +01:00
return 0 ;
}
2006-03-31 17:21:06 +02:00
static int hostap_cs_resume ( struct pcmcia_device * link )
2005-05-12 22:54:16 -04:00
{
struct net_device * dev = ( struct net_device * ) link - > priv ;
2005-10-02 17:18:58 -07:00
int dev_open = 0 ;
2006-03-02 00:09:29 +01:00
struct hostap_interface * iface = NULL ;
2008-07-02 11:04:24 -04:00
if ( ! dev )
return - ENODEV ;
iface = netdev_priv ( dev ) ;
2005-10-02 17:18:58 -07:00
2005-11-14 21:21:18 +01:00
PDEBUG ( DEBUG_EXTRA , " %s: CS_EVENT_PM_RESUME \n " , dev_info ) ;
2006-03-02 00:09:29 +01:00
if ( iface & & iface - > local )
dev_open = iface - > local - > num_dev_open > 0 ;
2005-11-14 21:21:18 +01:00
2006-03-02 00:09:29 +01:00
prism2_hw_shutdown ( dev , 1 ) ;
prism2_hw_config ( dev , dev_open ? 0 : 1 ) ;
if ( dev_open ) {
netif_device_attach ( dev ) ;
netif_start_queue ( dev ) ;
2005-10-02 17:18:58 -07:00
}
2005-05-12 22:54:16 -04:00
2005-11-14 21:21:18 +01:00
return 0 ;
}
2005-07-30 12:49:59 -07:00
static struct pcmcia_device_id hostap_cs_ids [ ] = {
PCMCIA_DEVICE_MANF_CARD ( 0x000b , 0x7100 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x000b , 0x7300 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x0101 , 0x0777 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x0126 , 0x8000 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x0138 , 0x0002 ) ,
2007-10-05 23:42:51 +02:00
PCMCIA_DEVICE_MANF_CARD ( 0x01bf , 0x3301 ) ,
2005-07-30 12:49:59 -07:00
PCMCIA_DEVICE_MANF_CARD ( 0x0250 , 0x0002 ) ,
2005-08-04 00:16:27 +01:00
PCMCIA_DEVICE_MANF_CARD ( 0x026f , 0x030b ) ,
2005-07-30 12:49:59 -07:00
PCMCIA_DEVICE_MANF_CARD ( 0x0274 , 0x1612 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x0274 , 0x1613 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x028a , 0x0002 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x02aa , 0x0002 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x02d2 , 0x0001 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x50c2 , 0x0001 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0x50c2 , 0x7300 ) ,
2006-04-17 21:41:21 +09:00
/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */
2008-05-16 17:52:57 -04:00
PCMCIA_DEVICE_MANF_CARD ( 0xc250 , 0x0002 ) ,
2005-07-30 12:49:59 -07:00
PCMCIA_DEVICE_MANF_CARD ( 0xd601 , 0x0002 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0xd601 , 0x0005 ) ,
PCMCIA_DEVICE_MANF_CARD ( 0xd601 , 0x0010 ) ,
2006-09-08 23:51:34 +02:00
PCMCIA_DEVICE_MANF_CARD ( 0x0126 , 0x0002 ) ,
2007-03-30 15:34:14 +02:00
PCMCIA_DEVICE_MANF_CARD_PROD_ID1 ( 0xd601 , 0x0005 , " ADLINK 345 CF " ,
0x2d858104 ) ,
2006-02-28 01:18:31 -05:00
PCMCIA_DEVICE_MANF_CARD_PROD_ID1 ( 0x0156 , 0x0002 , " INTERSIL " ,
0x74c5e40d ) ,
PCMCIA_DEVICE_MANF_CARD_PROD_ID1 ( 0x0156 , 0x0002 , " Intersil " ,
0x4b801a17 ) ,
2005-07-30 12:49:59 -07:00
PCMCIA_MFC_DEVICE_PROD_ID12 ( 0 , " SanDisk " , " ConnectPlus " ,
0x7a954bd9 , 0x74be00c6 ) ,
2008-01-09 22:16:58 -05:00
PCMCIA_DEVICE_PROD_ID123 (
2005-07-30 12:49:59 -07:00
" Intersil " , " PRISM 2_5 PCMCIA ADAPTER " , " ISL37300P " ,
2008-01-09 22:16:58 -05:00
0x4b801a17 , 0x6345a0bf , 0xc9049a39 ) ,
2007-02-27 19:46:46 -08:00
/* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */
2008-01-09 22:16:58 -05:00
PCMCIA_DEVICE_PROD_ID123 (
2007-02-27 19:46:46 -08:00
" D-Link " , " DWL-650 Wireless PC Card RevP " , " ISL37101P-10 " ,
2008-01-09 22:16:58 -05:00
0x1a424a1c , 0x6ea57632 , 0xdd97a26b ) ,
2005-07-30 12:49:59 -07:00
PCMCIA_DEVICE_PROD_ID123 (
" Addtron " , " AWP-100 Wireless PCMCIA " , " Version 01.02 " ,
0xe6ec52ce , 0x08649af2 , 0x4b74baa0 ) ,
PCMCIA_DEVICE_PROD_ID123 (
" D " , " Link DWL-650 11Mbps WLAN Card " , " Version 01.02 " ,
0x71b18589 , 0xb6f1b0ab , 0x4b74baa0 ) ,
PCMCIA_DEVICE_PROD_ID123 (
" Instant Wireless " , " Network PC CARD " , " Version 01.02 " ,
0x11d901af , 0x6e9bd926 , 0x4b74baa0 ) ,
PCMCIA_DEVICE_PROD_ID123 (
" SMC " , " SMC2632W " , " Version 01.02 " ,
0xc4f8b18b , 0x474a1f2a , 0x4b74baa0 ) ,
2005-08-04 00:16:27 +01:00
PCMCIA_DEVICE_PROD_ID12 ( " BUFFALO " , " WLI-CF-S11G " ,
2005-08-28 10:51:36 -07:00
0x2decece3 , 0x82067c18 ) ,
2005-07-30 12:49:59 -07:00
PCMCIA_DEVICE_PROD_ID12 ( " Compaq " , " WL200_11Mbps_Wireless_PCI_Card " ,
0x54f7c49c , 0x15a75e5b ) ,
PCMCIA_DEVICE_PROD_ID12 ( " INTERSIL " , " HFA384x/IEEE " ,
0x74c5e40d , 0xdb472a18 ) ,
PCMCIA_DEVICE_PROD_ID12 ( " Linksys " , " Wireless CompactFlash Card " ,
0x0733cc81 , 0x0c52f395 ) ,
PCMCIA_DEVICE_PROD_ID12 (
" ZoomAir 11Mbps High " , " Rate wireless Networking " ,
0x273fe3db , 0x32a1eaee ) ,
2006-05-22 10:56:55 +02:00
PCMCIA_DEVICE_PROD_ID123 (
" Pretec " , " CompactWLAN Card 802.11b " , " 2.5 " ,
0x1cadd3e5 , 0xe697636c , 0x7a5bfcf1 ) ,
PCMCIA_DEVICE_PROD_ID123 (
" U.S. Robotics " , " IEEE 802.11b PC-CARD " , " Version 01.02 " ,
0xc7b8df9d , 0x1700d087 , 0x4b74baa0 ) ,
2006-07-02 21:21:51 +02:00
PCMCIA_DEVICE_PROD_ID123 (
" Allied Telesyn " , " AT-WCL452 Wireless PCMCIA Radio " ,
" Ver. 1.00 " ,
0x5cd01705 , 0x4271660f , 0x9d08ee12 ) ,
PCMCIA_DEVICE_PROD_ID123 (
" corega " , " WL PCCL-11 " , " ISL37300P " ,
0xa21501a , 0x59868926 , 0xc9049a39 ) ,
2008-01-09 22:16:58 -05:00
PCMCIA_DEVICE_PROD_ID123 (
2007-10-07 20:51:08 +02:00
" The Linksys Group, Inc. " , " Wireless Network CF Card " , " ISL37300P " ,
2008-01-09 22:16:58 -05:00
0xa5f472c2 , 0x9c05598d , 0xc9049a39 ) ,
2008-01-29 09:42:53 +01:00
PCMCIA_DEVICE_PROD_ID123 (
" Wireless LAN " , " 11Mbps PC Card " , " Version 01.02 " ,
0x4b8870ff , 0x70e946d1 , 0x4b74baa0 ) ,
2005-07-30 12:49:59 -07:00
PCMCIA_DEVICE_NULL
} ;
MODULE_DEVICE_TABLE ( pcmcia , hostap_cs_ids ) ;
2005-05-12 22:54:16 -04:00
static struct pcmcia_driver hostap_driver = {
. drv = {
. name = " hostap_cs " ,
} ,
2006-03-31 17:26:06 +02:00
. probe = hostap_cs_probe ,
2005-11-14 21:23:14 +01:00
. remove = prism2_detach ,
2005-05-12 22:54:16 -04:00
. owner = THIS_MODULE ,
2005-07-30 12:49:59 -07:00
. id_table = hostap_cs_ids ,
2005-11-14 21:21:18 +01:00
. suspend = hostap_cs_suspend ,
. resume = hostap_cs_resume ,
2005-05-12 22:54:16 -04:00
} ;
static int __init init_prism2_pccard ( void )
{
return pcmcia_register_driver ( & hostap_driver ) ;
}
static void __exit exit_prism2_pccard ( void )
{
pcmcia_unregister_driver ( & hostap_driver ) ;
}
module_init ( init_prism2_pccard ) ;
module_exit ( exit_prism2_pccard ) ;