2007-02-10 12:25:27 -02:00
/**
* This file contains the major functions in WLAN
* driver . It includes init , exit , open , close and main
* thread etc . .
*/
2007-05-25 11:32:07 -04:00
# include <linux/moduleparam.h>
2007-02-10 12:25:27 -02:00
# include <linux/delay.h>
# include <linux/etherdevice.h>
# include <linux/netdevice.h>
# include <linux/if_arp.h>
2007-08-02 11:32:25 -04:00
# include <linux/kthread.h>
2007-02-10 12:25:27 -02:00
# include <net/iw_handler.h>
2007-05-25 11:27:16 -04:00
# include <net/ieee80211.h>
2007-02-10 12:25:27 -02:00
# include "host.h"
# include "decl.h"
# include "dev.h"
# include "wext.h"
# include "debugfs.h"
# include "assoc.h"
2007-08-02 13:16:55 -04:00
# include "join.h"
2007-12-11 12:42:16 -05:00
# include "cmd.h"
2007-02-10 12:25:27 -02:00
2007-08-03 09:43:03 -04:00
# define DRIVER_RELEASE_VERSION "323.p0"
2007-11-15 18:05:47 -05:00
const char lbs_driver_version [ ] = " COMM-USB8388- " DRIVER_RELEASE_VERSION
2007-05-10 23:03:07 -04:00
# ifdef DEBUG
" -dbg "
# endif
" " ;
2007-05-25 11:32:07 -04:00
/* Module parameters */
2007-11-15 18:05:47 -05:00
unsigned int lbs_debug ;
EXPORT_SYMBOL_GPL ( lbs_debug ) ;
module_param_named ( libertas_debug , lbs_debug , int , 0644 ) ;
2007-05-25 11:32:07 -04:00
2007-11-15 18:05:47 -05:00
# define LBS_TX_PWR_DEFAULT 20 /*100mW */
# define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
# define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
# define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
# define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
2007-02-10 12:25:27 -02:00
/* Format { channel, frequency (MHz), maxtxpower } */
/* band: 'B/G', region: USA FCC/Canada IC */
static struct chan_freq_power channel_freq_power_US_BG [ ] = {
2007-11-15 18:05:47 -05:00
{ 1 , 2412 , LBS_TX_PWR_US_DEFAULT } ,
{ 2 , 2417 , LBS_TX_PWR_US_DEFAULT } ,
{ 3 , 2422 , LBS_TX_PWR_US_DEFAULT } ,
{ 4 , 2427 , LBS_TX_PWR_US_DEFAULT } ,
{ 5 , 2432 , LBS_TX_PWR_US_DEFAULT } ,
{ 6 , 2437 , LBS_TX_PWR_US_DEFAULT } ,
{ 7 , 2442 , LBS_TX_PWR_US_DEFAULT } ,
{ 8 , 2447 , LBS_TX_PWR_US_DEFAULT } ,
{ 9 , 2452 , LBS_TX_PWR_US_DEFAULT } ,
{ 10 , 2457 , LBS_TX_PWR_US_DEFAULT } ,
{ 11 , 2462 , LBS_TX_PWR_US_DEFAULT }
2007-02-10 12:25:27 -02:00
} ;
/* band: 'B/G', region: Europe ETSI */
static struct chan_freq_power channel_freq_power_EU_BG [ ] = {
2007-11-15 18:05:47 -05:00
{ 1 , 2412 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 2 , 2417 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 3 , 2422 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 4 , 2427 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 5 , 2432 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 6 , 2437 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 7 , 2442 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 8 , 2447 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 9 , 2452 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 10 , 2457 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 11 , 2462 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 12 , 2467 , LBS_TX_PWR_EMEA_DEFAULT } ,
{ 13 , 2472 , LBS_TX_PWR_EMEA_DEFAULT }
2007-02-10 12:25:27 -02:00
} ;
/* band: 'B/G', region: Spain */
static struct chan_freq_power channel_freq_power_SPN_BG [ ] = {
2007-11-15 18:05:47 -05:00
{ 10 , 2457 , LBS_TX_PWR_DEFAULT } ,
{ 11 , 2462 , LBS_TX_PWR_DEFAULT }
2007-02-10 12:25:27 -02:00
} ;
/* band: 'B/G', region: France */
static struct chan_freq_power channel_freq_power_FR_BG [ ] = {
2007-11-15 18:05:47 -05:00
{ 10 , 2457 , LBS_TX_PWR_FR_DEFAULT } ,
{ 11 , 2462 , LBS_TX_PWR_FR_DEFAULT } ,
{ 12 , 2467 , LBS_TX_PWR_FR_DEFAULT } ,
{ 13 , 2472 , LBS_TX_PWR_FR_DEFAULT }
2007-02-10 12:25:27 -02:00
} ;
/* band: 'B/G', region: Japan */
static struct chan_freq_power channel_freq_power_JPN_BG [ ] = {
2007-11-15 18:05:47 -05:00
{ 1 , 2412 , LBS_TX_PWR_JP_DEFAULT } ,
{ 2 , 2417 , LBS_TX_PWR_JP_DEFAULT } ,
{ 3 , 2422 , LBS_TX_PWR_JP_DEFAULT } ,
{ 4 , 2427 , LBS_TX_PWR_JP_DEFAULT } ,
{ 5 , 2432 , LBS_TX_PWR_JP_DEFAULT } ,
{ 6 , 2437 , LBS_TX_PWR_JP_DEFAULT } ,
{ 7 , 2442 , LBS_TX_PWR_JP_DEFAULT } ,
{ 8 , 2447 , LBS_TX_PWR_JP_DEFAULT } ,
{ 9 , 2452 , LBS_TX_PWR_JP_DEFAULT } ,
{ 10 , 2457 , LBS_TX_PWR_JP_DEFAULT } ,
{ 11 , 2462 , LBS_TX_PWR_JP_DEFAULT } ,
{ 12 , 2467 , LBS_TX_PWR_JP_DEFAULT } ,
{ 13 , 2472 , LBS_TX_PWR_JP_DEFAULT } ,
{ 14 , 2484 , LBS_TX_PWR_JP_DEFAULT }
2007-02-10 12:25:27 -02:00
} ;
/**
* the structure for channel , frequency and power
*/
struct region_cfp_table {
u8 region ;
struct chan_freq_power * cfp_BG ;
int cfp_no_BG ;
} ;
/**
* the structure for the mapping between region and CFP
*/
static struct region_cfp_table region_cfp_table [ ] = {
{ 0x10 , /*US FCC */
channel_freq_power_US_BG ,
2007-09-02 18:30:18 +08:00
ARRAY_SIZE ( channel_freq_power_US_BG ) ,
2007-02-10 12:25:27 -02:00
}
,
{ 0x20 , /*CANADA IC */
channel_freq_power_US_BG ,
2007-09-02 18:30:18 +08:00
ARRAY_SIZE ( channel_freq_power_US_BG ) ,
2007-02-10 12:25:27 -02:00
}
,
{ 0x30 , /*EU*/ channel_freq_power_EU_BG ,
2007-09-02 18:30:18 +08:00
ARRAY_SIZE ( channel_freq_power_EU_BG ) ,
2007-02-10 12:25:27 -02:00
}
,
{ 0x31 , /*SPAIN*/ channel_freq_power_SPN_BG ,
2007-09-02 18:30:18 +08:00
ARRAY_SIZE ( channel_freq_power_SPN_BG ) ,
2007-02-10 12:25:27 -02:00
}
,
{ 0x32 , /*FRANCE*/ channel_freq_power_FR_BG ,
2007-09-02 18:30:18 +08:00
ARRAY_SIZE ( channel_freq_power_FR_BG ) ,
2007-02-10 12:25:27 -02:00
}
,
{ 0x40 , /*JAPAN*/ channel_freq_power_JPN_BG ,
2007-09-02 18:30:18 +08:00
ARRAY_SIZE ( channel_freq_power_JPN_BG ) ,
2007-02-10 12:25:27 -02:00
}
,
/*Add new region here */
} ;
/**
2007-08-02 11:40:45 -04:00
* the table to keep region code
2007-02-10 12:25:27 -02:00
*/
2007-11-15 18:05:47 -05:00
u16 lbs_region_code_to_index [ MRVDRV_MAX_REGION_CODE ] =
2007-08-02 11:40:45 -04:00
{ 0x10 , 0x20 , 0x30 , 0x31 , 0x32 , 0x40 } ;
2007-02-10 12:25:27 -02:00
/**
2007-08-02 11:40:45 -04:00
* 802.11 b / g supported bitrates ( in 500 Kb / s units )
2007-02-10 12:25:27 -02:00
*/
2007-11-15 18:05:47 -05:00
u8 lbs_bg_rates [ MAX_RATES ] =
2007-08-02 11:40:45 -04:00
{ 0x02 , 0x04 , 0x0b , 0x16 , 0x0c , 0x12 , 0x18 , 0x24 , 0x30 , 0x48 , 0x60 , 0x6c ,
0x00 , 0x00 } ;
2007-02-10 12:25:27 -02:00
/**
2007-08-02 11:40:45 -04:00
* FW rate table . FW refers to rates by their index in this table , not by the
* rate value itself . Values of 0x00 are
* reserved positions .
2007-02-10 12:25:27 -02:00
*/
2007-08-02 11:40:45 -04:00
static u8 fw_data_rates [ MAX_RATES ] =
{ 0x02 , 0x04 , 0x0B , 0x16 , 0x00 , 0x0C , 0x12 ,
0x18 , 0x24 , 0x30 , 0x48 , 0x60 , 0x6C , 0x00
} ;
2007-02-10 12:25:27 -02:00
/**
2007-08-02 11:40:45 -04:00
* @ brief use index to get the data rate
*
* @ param idx The index of data rate
* @ return data rate or 0
2007-02-10 12:25:27 -02:00
*/
2007-11-15 18:05:47 -05:00
u32 lbs_fw_index_to_data_rate ( u8 idx )
2007-08-02 11:40:45 -04:00
{
if ( idx > = sizeof ( fw_data_rates ) )
idx = 0 ;
return fw_data_rates [ idx ] ;
}
/**
* @ brief use rate to get the index
*
* @ param rate data rate
* @ return index or 0
*/
2007-11-15 18:05:47 -05:00
u8 lbs_data_rate_to_fw_index ( u32 rate )
2007-08-02 11:40:45 -04:00
{
u8 i ;
if ( ! rate )
return 0 ;
for ( i = 0 ; i < sizeof ( fw_data_rates ) ; i + + ) {
if ( rate = = fw_data_rates [ i ] )
return i ;
}
return 0 ;
}
2007-02-10 12:25:27 -02:00
/**
* Attributes exported through sysfs
*/
/**
2007-06-07 16:40:59 -04:00
* @ brief Get function for sysfs attribute anycast_mask
2007-02-10 12:25:27 -02:00
*/
2007-11-15 18:05:47 -05:00
static ssize_t lbs_anycast_get ( struct device * dev ,
2007-06-18 11:50:43 -04:00
struct device_attribute * attr , char * buf )
{
2007-12-11 15:23:59 -05:00
struct lbs_private * priv = to_net_dev ( dev ) - > priv ;
2007-02-10 12:25:27 -02:00
struct cmd_ds_mesh_access mesh_access ;
2007-12-11 15:23:59 -05:00
int ret ;
2007-02-10 12:25:27 -02:00
memset ( & mesh_access , 0 , sizeof ( mesh_access ) ) ;
2007-12-11 15:23:59 -05:00
ret = lbs_mesh_access ( priv , CMD_ACT_MESH_GET_ANYCAST , & mesh_access ) ;
if ( ret )
return ret ;
2007-02-10 12:25:27 -02:00
2007-06-07 16:40:59 -04:00
return snprintf ( buf , 12 , " 0x%X \n " , le32_to_cpu ( mesh_access . data [ 0 ] ) ) ;
2007-02-10 12:25:27 -02:00
}
/**
2007-06-07 16:40:59 -04:00
* @ brief Set function for sysfs attribute anycast_mask
2007-02-10 12:25:27 -02:00
*/
2007-11-15 18:05:47 -05:00
static ssize_t lbs_anycast_set ( struct device * dev ,
2007-06-18 11:50:43 -04:00
struct device_attribute * attr , const char * buf , size_t count )
{
2007-12-11 15:23:59 -05:00
struct lbs_private * priv = to_net_dev ( dev ) - > priv ;
2007-02-10 12:25:27 -02:00
struct cmd_ds_mesh_access mesh_access ;
2007-05-25 23:36:54 -04:00
uint32_t datum ;
2007-12-11 15:23:59 -05:00
int ret ;
2007-02-10 12:25:27 -02:00
memset ( & mesh_access , 0 , sizeof ( mesh_access ) ) ;
2007-06-07 16:40:59 -04:00
sscanf ( buf , " %x " , & datum ) ;
2007-05-25 23:36:54 -04:00
mesh_access . data [ 0 ] = cpu_to_le32 ( datum ) ;
2007-12-11 15:23:59 -05:00
ret = lbs_mesh_access ( priv , CMD_ACT_MESH_SET_ANYCAST , & mesh_access ) ;
if ( ret )
return ret ;
2007-02-10 12:25:27 -02:00
return strlen ( buf ) ;
}
2007-12-11 17:44:10 -05:00
static int lbs_add_rtap ( struct lbs_private * priv ) ;
static void lbs_remove_rtap ( struct lbs_private * priv ) ;
2007-12-11 18:56:42 -05:00
static int lbs_add_mesh ( struct lbs_private * priv ) ;
static void lbs_remove_mesh ( struct lbs_private * priv ) ;
2007-12-14 22:53:41 -05:00
2007-08-02 13:16:55 -04:00
/**
* Get function for sysfs attribute rtap
*/
2007-11-15 18:05:47 -05:00
static ssize_t lbs_rtap_get ( struct device * dev ,
2007-08-02 13:16:55 -04:00
struct device_attribute * attr , char * buf )
{
2007-12-08 18:29:16 +00:00
struct lbs_private * priv = to_net_dev ( dev ) - > priv ;
2007-12-08 20:04:36 +00:00
return snprintf ( buf , 5 , " 0x%X \n " , priv - > monitormode ) ;
2007-08-02 13:16:55 -04:00
}
/**
* Set function for sysfs attribute rtap
*/
2007-11-15 18:05:47 -05:00
static ssize_t lbs_rtap_set ( struct device * dev ,
2007-08-02 13:16:55 -04:00
struct device_attribute * attr , const char * buf , size_t count )
{
int monitor_mode ;
2007-12-08 18:29:16 +00:00
struct lbs_private * priv = to_net_dev ( dev ) - > priv ;
2007-08-02 13:16:55 -04:00
sscanf ( buf , " %x " , & monitor_mode ) ;
2007-11-15 18:05:47 -05:00
if ( monitor_mode ! = LBS_MONITOR_OFF ) {
2007-12-08 20:04:36 +00:00
if ( priv - > monitormode = = monitor_mode )
2007-08-02 13:16:55 -04:00
return strlen ( buf ) ;
2007-12-08 20:04:36 +00:00
if ( priv - > monitormode = = LBS_MONITOR_OFF ) {
2007-12-10 16:38:18 -05:00
if ( priv - > infra_open | | priv - > mesh_open )
return - EBUSY ;
2007-12-08 20:04:36 +00:00
if ( priv - > mode = = IW_MODE_INFRA )
2007-11-15 18:05:47 -05:00
lbs_send_deauthentication ( priv ) ;
2007-12-08 20:04:36 +00:00
else if ( priv - > mode = = IW_MODE_ADHOC )
2007-11-15 18:05:47 -05:00
lbs_stop_adhoc_network ( priv ) ;
lbs_add_rtap ( priv ) ;
2007-08-02 13:16:55 -04:00
}
2007-12-08 20:04:36 +00:00
priv - > monitormode = monitor_mode ;
2007-08-02 13:16:55 -04:00
}
else {
2007-12-08 20:04:36 +00:00
if ( priv - > monitormode = = LBS_MONITOR_OFF )
2007-08-02 13:16:55 -04:00
return strlen ( buf ) ;
2007-12-08 20:04:36 +00:00
priv - > monitormode = LBS_MONITOR_OFF ;
2007-11-15 18:05:47 -05:00
lbs_remove_rtap ( priv ) ;
2007-12-08 19:46:19 +00:00
2007-12-08 20:04:36 +00:00
if ( priv - > currenttxskb ) {
dev_kfree_skb_any ( priv - > currenttxskb ) ;
priv - > currenttxskb = NULL ;
2007-12-08 19:46:19 +00:00
}
/* Wake queues, command thread, etc. */
lbs_host_to_card_done ( priv ) ;
2007-08-02 13:16:55 -04:00
}
2007-11-15 18:05:47 -05:00
lbs_prepare_and_send_command ( priv ,
2007-08-02 13:16:55 -04:00
CMD_802_11_MONITOR_MODE , CMD_ACT_SET ,
2007-12-08 20:04:36 +00:00
CMD_OPTION_WAITFORRSP , 0 , & priv - > monitormode ) ;
2007-08-02 13:16:55 -04:00
return strlen ( buf ) ;
}
/**
2007-12-11 18:56:42 -05:00
* lbs_rtap attribute to be exported per ethX interface
* through sysfs ( / sys / class / net / ethX / lbs_rtap )
2007-08-02 13:16:55 -04:00
*/
2007-12-11 18:56:42 -05:00
static DEVICE_ATTR ( lbs_rtap , 0644 , lbs_rtap_get , lbs_rtap_set ) ;
/**
* Get function for sysfs attribute mesh
*/
static ssize_t lbs_mesh_get ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct lbs_private * priv = to_net_dev ( dev ) - > priv ;
return snprintf ( buf , 5 , " 0x%X \n " , ! ! priv - > mesh_dev ) ;
}
/**
* Set function for sysfs attribute mesh
*/
static ssize_t lbs_mesh_set ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct lbs_private * priv = to_net_dev ( dev ) - > priv ;
int enable ;
int ret ;
sscanf ( buf , " %x " , & enable ) ;
enable = ! ! enable ;
if ( enable = = ! ! priv - > mesh_dev )
return count ;
2007-12-13 00:32:36 -05:00
ret = lbs_mesh_config ( priv , enable , priv - > curbssparams . channel ) ;
2007-12-11 18:56:42 -05:00
if ( ret )
return ret ;
2007-12-14 22:53:41 -05:00
2007-12-11 18:56:42 -05:00
if ( enable )
lbs_add_mesh ( priv ) ;
else
lbs_remove_mesh ( priv ) ;
return count ;
}
/**
* lbs_mesh attribute to be exported per ethX interface
* through sysfs ( / sys / class / net / ethX / lbs_mesh )
*/
static DEVICE_ATTR ( lbs_mesh , 0644 , lbs_mesh_get , lbs_mesh_set ) ;
2007-08-02 13:16:55 -04:00
2007-02-10 12:25:27 -02:00
/**
2007-06-07 16:40:59 -04:00
* anycast_mask attribute to be exported per mshX interface
* through sysfs ( / sys / class / net / mshX / anycast_mask )
2007-02-10 12:25:27 -02:00
*/
2007-11-15 18:05:47 -05:00
static DEVICE_ATTR ( anycast_mask , 0644 , lbs_anycast_get , lbs_anycast_set ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
static struct attribute * lbs_mesh_sysfs_entries [ ] = {
2007-08-02 11:52:29 -04:00
& dev_attr_anycast_mask . attr ,
NULL ,
} ;
2007-11-15 18:05:47 -05:00
static struct attribute_group lbs_mesh_attr_group = {
. attrs = lbs_mesh_sysfs_entries ,
2007-08-02 11:52:29 -04:00
} ;
2007-02-10 12:25:27 -02:00
/**
2007-12-10 16:38:18 -05:00
* @ brief This function opens the ethX or mshX interface
2007-02-10 12:25:27 -02:00
*
* @ param dev A pointer to net_device structure
2007-12-10 16:38:18 -05:00
* @ return 0 or - EBUSY if monitor mode active
2007-02-10 12:25:27 -02:00
*/
2007-11-15 18:05:47 -05:00
static int lbs_dev_open ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
2007-12-10 16:38:18 -05:00
struct lbs_private * priv = ( struct lbs_private * ) dev - > priv ;
int ret = 0 ;
2007-02-10 12:25:27 -02:00
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-12-10 16:38:18 -05:00
spin_lock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
2007-12-10 16:38:18 -05:00
if ( priv - > monitormode ! = LBS_MONITOR_OFF ) {
ret = - EBUSY ;
goto out ;
}
2007-11-20 17:44:14 -05:00
2007-12-10 16:38:18 -05:00
if ( dev = = priv - > mesh_dev ) {
priv - > mesh_open = 1 ;
priv - > mesh_connect_status = LBS_CONNECTED ;
netif_carrier_on ( dev ) ;
} else {
priv - > infra_open = 1 ;
2007-12-14 22:53:41 -05:00
2007-12-10 16:38:18 -05:00
if ( priv - > connect_status = = LBS_CONNECTED )
netif_carrier_on ( dev ) ;
2007-11-20 17:44:14 -05:00
else
2007-12-10 16:38:18 -05:00
netif_carrier_off ( dev ) ;
2007-05-25 12:06:56 -04:00
}
2007-02-10 12:25:27 -02:00
2007-12-10 16:38:18 -05:00
if ( ! priv - > tx_pending_len )
netif_wake_queue ( dev ) ;
out :
2007-02-10 12:25:27 -02:00
2007-12-10 16:38:18 -05:00
spin_unlock_irq ( & priv - > driver_lock ) ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave_args ( LBS_DEB_NET , " ret %d " , ret ) ;
2007-12-10 16:38:18 -05:00
return ret ;
2007-02-10 12:25:27 -02:00
}
/**
* @ brief This function closes the mshX interface
*
* @ param dev A pointer to net_device structure
* @ return 0
*/
2007-12-10 16:38:18 -05:00
static int lbs_mesh_stop ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = ( struct lbs_private * ) ( dev - > priv ) ;
2007-02-10 12:25:27 -02:00
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_MESH ) ;
2007-12-10 16:38:18 -05:00
spin_lock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
priv - > mesh_open = 0 ;
2007-12-10 16:38:18 -05:00
priv - > mesh_connect_status = LBS_DISCONNECTED ;
netif_stop_queue ( dev ) ;
netif_carrier_off ( dev ) ;
2007-12-14 22:53:41 -05:00
2007-12-10 16:38:18 -05:00
spin_unlock_irq ( & priv - > driver_lock ) ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave ( LBS_DEB_MESH ) ;
2007-12-10 16:38:18 -05:00
return 0 ;
2007-02-10 12:25:27 -02:00
}
/**
* @ brief This function closes the ethX interface
*
* @ param dev A pointer to net_device structure
* @ return 0
*/
2007-12-10 16:38:18 -05:00
static int lbs_eth_stop ( struct net_device * dev )
2007-05-25 11:49:19 -04:00
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = ( struct lbs_private * ) dev - > priv ;
2007-02-10 12:25:27 -02:00
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-12-10 16:38:18 -05:00
2008-01-16 15:59:52 +01:00
spin_lock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
priv - > infra_open = 0 ;
2007-12-10 16:38:18 -05:00
netif_stop_queue ( dev ) ;
spin_unlock_irq ( & priv - > driver_lock ) ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave ( LBS_DEB_NET ) ;
2007-12-10 16:38:18 -05:00
return 0 ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
static void lbs_tx_timeout ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = ( struct lbs_private * ) dev - > priv ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_TX ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_pr_err ( " tx watch dog timeout \n " ) ;
2007-02-10 12:25:27 -02:00
dev - > trans_start = jiffies ;
2007-12-08 20:04:36 +00:00
if ( priv - > currenttxskb ) {
2007-12-08 20:56:44 +00:00
priv - > eventcause = 0x01000000 ;
lbs_send_tx_feedback ( priv ) ;
2007-05-25 12:06:56 -04:00
}
2007-12-08 20:56:44 +00:00
/* XX: Shouldn't we also call into the hw-specific driver
to kick it somehow ? */
lbs_host_to_card_done ( priv ) ;
2007-02-10 12:25:27 -02:00
2007-12-17 19:22:40 -05:00
/* More often than not, this actually happens because the
firmware has crapped itself - - rather than just a very
busy medium . So send a harmless command , and if / when
_that_ times out , we ' ll kick it in the head . */
lbs_prepare_and_send_command ( priv , CMD_802_11_RSSI , 0 ,
0 , 0 , NULL ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_TX ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-06 14:36:11 +00:00
void lbs_host_to_card_done ( struct lbs_private * priv )
{
2007-12-08 20:56:44 +00:00
unsigned long flags ;
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_THREAD ) ;
2007-12-08 20:56:44 +00:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
2007-12-06 14:36:11 +00:00
priv - > dnld_sent = DNLD_RES_RECEIVED ;
/* Wake main thread if commands are pending */
2007-12-12 00:41:51 -05:00
if ( ! priv - > cur_cmd | | priv - > tx_pending_len > 0 )
2007-12-06 14:36:11 +00:00
wake_up_interruptible ( & priv - > waitq ) ;
2007-12-08 20:56:44 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave ( LBS_DEB_THREAD ) ;
2007-12-06 14:36:11 +00:00
}
EXPORT_SYMBOL_GPL ( lbs_host_to_card_done ) ;
2007-02-10 12:25:27 -02:00
/**
* @ brief This function returns the network statistics
*
2007-11-23 15:43:44 +01:00
* @ param dev A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
* @ return A pointer to net_device_stats structure
*/
2007-11-15 18:05:47 -05:00
static struct net_device_stats * lbs_get_stats ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = ( struct lbs_private * ) dev - > priv ;
2007-02-10 12:25:27 -02:00
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-02-10 12:25:27 -02:00
return & priv - > stats ;
}
2007-11-15 18:05:47 -05:00
static int lbs_set_mac_address ( struct net_device * dev , void * addr )
2007-02-10 12:25:27 -02:00
{
int ret = 0 ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = ( struct lbs_private * ) dev - > priv ;
2007-02-10 12:25:27 -02:00
struct sockaddr * phwaddr = addr ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 23:05:27 -04:00
/* In case it was called from the mesh device */
dev = priv - > dev ;
2007-12-08 20:04:36 +00:00
memset ( priv - > current_addr , 0 , ETH_ALEN ) ;
2007-02-10 12:25:27 -02:00
/* dev->dev_addr is 8 bytes */
2007-08-02 11:53:06 -04:00
lbs_deb_hex ( LBS_DEB_NET , " dev->dev_addr " , dev - > dev_addr , ETH_ALEN ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:53:06 -04:00
lbs_deb_hex ( LBS_DEB_NET , " addr " , phwaddr - > sa_data , ETH_ALEN ) ;
2007-12-08 20:04:36 +00:00
memcpy ( priv - > current_addr , phwaddr - > sa_data , ETH_ALEN ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
ret = lbs_prepare_and_send_command ( priv , CMD_802_11_MAC_ADDRESS ,
2007-08-02 11:31:18 -04:00
CMD_ACT_SET ,
CMD_OPTION_WAITFORRSP , 0 , NULL ) ;
2007-02-10 12:25:27 -02:00
if ( ret ) {
2007-05-25 11:27:16 -04:00
lbs_deb_net ( " set MAC address failed \n " ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
goto done ;
}
2007-12-08 20:04:36 +00:00
lbs_deb_hex ( LBS_DEB_NET , " priv->macaddr " , priv - > current_addr , ETH_ALEN ) ;
memcpy ( dev - > dev_addr , priv - > current_addr , ETH_ALEN ) ;
2007-05-25 11:49:19 -04:00
if ( priv - > mesh_dev )
2007-12-08 20:04:36 +00:00
memcpy ( priv - > mesh_dev - > dev_addr , priv - > current_addr , ETH_ALEN ) ;
2007-02-10 12:25:27 -02:00
done :
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_NET , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2007-12-08 20:04:36 +00:00
static int lbs_copy_multicast_address ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
struct net_device * dev )
{
int i = 0 ;
struct dev_mc_list * mcptr = dev - > mc_list ;
for ( i = 0 ; i < dev - > mc_count ; i + + ) {
2007-12-08 20:04:36 +00:00
memcpy ( & priv - > multicastlist [ i ] , mcptr - > dmi_addr , ETH_ALEN ) ;
2007-02-10 12:25:27 -02:00
mcptr = mcptr - > next ;
}
return i ;
}
2007-11-15 18:05:47 -05:00
static void lbs_set_multicast_list ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
2007-02-10 12:25:27 -02:00
int oldpacketfilter ;
2007-10-03 17:59:30 -07:00
DECLARE_MAC_BUF ( mac ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
oldpacketfilter = priv - > currentpacketfilter ;
2007-02-10 12:25:27 -02:00
if ( dev - > flags & IFF_PROMISC ) {
2007-05-25 11:27:16 -04:00
lbs_deb_net ( " enable promiscuous mode \n " ) ;
2007-12-08 20:04:36 +00:00
priv - > currentpacketfilter | =
2007-08-02 11:31:18 -04:00
CMD_ACT_MAC_PROMISCUOUS_ENABLE ;
2007-12-08 20:04:36 +00:00
priv - > currentpacketfilter & =
2007-08-02 11:31:18 -04:00
~ ( CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
CMD_ACT_MAC_MULTICAST_ENABLE ) ;
2007-02-10 12:25:27 -02:00
} else {
/* Multicast */
2007-12-08 20:04:36 +00:00
priv - > currentpacketfilter & =
2007-08-02 11:31:18 -04:00
~ CMD_ACT_MAC_PROMISCUOUS_ENABLE ;
2007-02-10 12:25:27 -02:00
if ( dev - > flags & IFF_ALLMULTI | | dev - > mc_count >
MRVDRV_MAX_MULTICAST_LIST_SIZE ) {
2007-05-25 11:27:16 -04:00
lbs_deb_net ( " enabling all multicast \n " ) ;
2007-12-08 20:04:36 +00:00
priv - > currentpacketfilter | =
2007-08-02 11:31:18 -04:00
CMD_ACT_MAC_ALL_MULTICAST_ENABLE ;
2007-12-08 20:04:36 +00:00
priv - > currentpacketfilter & =
2007-08-02 11:31:18 -04:00
~ CMD_ACT_MAC_MULTICAST_ENABLE ;
2007-02-10 12:25:27 -02:00
} else {
2007-12-08 20:04:36 +00:00
priv - > currentpacketfilter & =
2007-08-02 11:31:18 -04:00
~ CMD_ACT_MAC_ALL_MULTICAST_ENABLE ;
2007-02-10 12:25:27 -02:00
if ( ! dev - > mc_count ) {
2007-05-25 11:27:16 -04:00
lbs_deb_net ( " no multicast addresses, "
" disabling multicast \n " ) ;
2007-12-08 20:04:36 +00:00
priv - > currentpacketfilter & =
2007-08-02 11:31:18 -04:00
~ CMD_ACT_MAC_MULTICAST_ENABLE ;
2007-02-10 12:25:27 -02:00
} else {
int i ;
2007-12-08 20:04:36 +00:00
priv - > currentpacketfilter | =
2007-08-02 11:31:18 -04:00
CMD_ACT_MAC_MULTICAST_ENABLE ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
priv - > nr_of_multicastmacaddr =
lbs_copy_multicast_address ( priv , dev ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_net ( " multicast addresses: %d \n " ,
2007-02-10 12:25:27 -02:00
dev - > mc_count ) ;
for ( i = 0 ; i < dev - > mc_count ; i + + ) {
2008-01-16 15:59:52 +01:00
lbs_deb_net ( " Multicast address %d: %s \n " ,
2007-10-03 17:59:30 -07:00
i , print_mac ( mac ,
2007-12-08 20:04:36 +00:00
priv - > multicastlist [ i ] ) ) ;
2007-02-10 12:25:27 -02:00
}
2007-05-25 11:27:16 -04:00
/* send multicast addresses to firmware */
2007-11-15 18:05:47 -05:00
lbs_prepare_and_send_command ( priv ,
2007-08-02 11:31:18 -04:00
CMD_MAC_MULTICAST_ADR ,
CMD_ACT_SET , 0 , 0 ,
2007-02-10 12:25:27 -02:00
NULL ) ;
}
}
}
2007-12-08 20:04:36 +00:00
if ( priv - > currentpacketfilter ! = oldpacketfilter ) {
2007-11-15 18:05:47 -05:00
lbs_set_mac_packet_filter ( priv ) ;
2007-02-10 12:25:27 -02:00
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_NET ) ;
2007-02-10 12:25:27 -02:00
}
/**
2007-11-15 18:05:47 -05:00
* @ brief This function handles the major jobs in the LBS driver .
2007-05-25 11:27:16 -04:00
* It handles all events generated by firmware , RX data received
* from firmware and TX data sent from kernel .
2007-02-10 12:25:27 -02:00
*
2007-11-15 18:05:47 -05:00
* @ param data A pointer to lbs_thread structure
2007-02-10 12:25:27 -02:00
* @ return 0
*/
2007-11-15 18:05:47 -05:00
static int lbs_thread ( void * data )
2007-02-10 12:25:27 -02:00
{
2007-08-02 11:32:25 -04:00
struct net_device * dev = data ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
2007-02-10 12:25:27 -02:00
wait_queue_t wait ;
u8 ireg = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_THREAD ) ;
2007-02-10 12:25:27 -02:00
init_waitqueue_entry ( & wait , current ) ;
for ( ; ; ) {
2007-12-09 23:44:43 -05:00
int shouldsleep ;
2007-12-08 17:42:59 +00:00
lbs_deb_thread ( " main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d \n " ,
2007-12-08 20:04:36 +00:00
priv - > intcounter , priv - > currenttxskb , priv - > dnld_sent ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:32:25 -04:00
add_wait_queue ( & priv - > waitq , & wait ) ;
2007-02-10 12:25:27 -02:00
set_current_state ( TASK_INTERRUPTIBLE ) ;
2007-12-08 20:04:36 +00:00
spin_lock_irq ( & priv - > driver_lock ) ;
2007-12-08 17:42:59 +00:00
2007-12-13 21:48:00 -05:00
if ( kthread_should_stop ( ) )
2007-12-09 23:44:43 -05:00
shouldsleep = 0 ; /* Bye */
2007-12-13 21:48:00 -05:00
else if ( priv - > surpriseremoved )
shouldsleep = 1 ; /* We need to wait until we're _told_ to die */
2007-12-09 23:44:43 -05:00
else if ( priv - > psstate = = PS_STATE_SLEEP )
shouldsleep = 1 ; /* Sleep mode. Nothing we can do till it wakes */
else if ( priv - > intcounter )
shouldsleep = 0 ; /* Interrupt pending. Deal with it now */
2007-12-15 19:33:43 -05:00
else if ( priv - > cmd_timed_out )
shouldsleep = 0 ; /* Command timed out. Recover */
2007-12-11 11:55:37 -05:00
else if ( ! priv - > fw_ready )
shouldsleep = 1 ; /* Firmware not ready. We're waiting for it */
2007-12-09 23:44:43 -05:00
else if ( priv - > dnld_sent )
shouldsleep = 1 ; /* Something is en route to the device already */
2007-12-09 23:54:27 -05:00
else if ( priv - > tx_pending_len > 0 )
shouldsleep = 0 ; /* We've a packet to send */
2007-12-09 23:44:43 -05:00
else if ( priv - > cur_cmd )
shouldsleep = 1 ; /* Can't send a command; one already running */
else if ( ! list_empty ( & priv - > cmdpendingq ) )
shouldsleep = 0 ; /* We have a command to send */
else
shouldsleep = 1 ; /* No command */
if ( shouldsleep ) {
2007-12-08 17:42:59 +00:00
lbs_deb_thread ( " main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d \n " ,
2007-12-08 20:04:36 +00:00
priv - > connect_status , priv - > intcounter ,
priv - > psmode , priv - > psstate ) ;
spin_unlock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
schedule ( ) ;
} else
2007-12-08 20:04:36 +00:00
spin_unlock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 17:42:59 +00:00
lbs_deb_thread ( " main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d \n " ,
2007-12-08 20:04:36 +00:00
priv - > intcounter , priv - > currenttxskb , priv - > dnld_sent ) ;
2007-02-10 12:25:27 -02:00
set_current_state ( TASK_RUNNING ) ;
2007-08-02 11:32:25 -04:00
remove_wait_queue ( & priv - > waitq , & wait ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 17:42:59 +00:00
lbs_deb_thread ( " main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d \n " ,
2007-12-08 20:04:36 +00:00
priv - > intcounter , priv - > currenttxskb , priv - > dnld_sent ) ;
2007-02-10 12:25:27 -02:00
2007-12-13 21:48:00 -05:00
if ( kthread_should_stop ( ) ) {
lbs_deb_thread ( " main-thread: break from main thread \n " ) ;
2007-02-10 12:25:27 -02:00
break ;
}
2007-12-13 21:48:00 -05:00
if ( priv - > surpriseremoved ) {
lbs_deb_thread ( " adapter removed; waiting to die... \n " ) ;
continue ;
}
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
spin_lock_irq ( & priv - > driver_lock ) ;
2007-12-08 17:42:59 +00:00
2007-12-08 20:04:36 +00:00
if ( priv - > intcounter ) {
2007-02-10 12:25:27 -02:00
u8 int_status ;
2007-12-08 17:42:59 +00:00
2007-12-08 20:04:36 +00:00
priv - > intcounter = 0 ;
2007-05-25 12:17:06 -04:00
int_status = priv - > hw_get_int_status ( priv , & ireg ) ;
2007-02-10 12:25:27 -02:00
if ( int_status ) {
2007-12-08 17:42:59 +00:00
lbs_deb_thread ( " main-thread: reading HOST_INT_STATUS_REG failed \n " ) ;
2007-12-08 20:04:36 +00:00
spin_unlock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
continue ;
}
2007-12-08 20:04:36 +00:00
priv - > hisregcpy | = ireg ;
2007-02-10 12:25:27 -02:00
}
2007-12-08 17:42:59 +00:00
lbs_deb_thread ( " main-thread 444: intcounter=%d currenttxskb=%p dnld_sent=%d \n " ,
2007-12-08 20:04:36 +00:00
priv - > intcounter , priv - > currenttxskb , priv - > dnld_sent ) ;
2007-02-10 12:25:27 -02:00
/* command response? */
2007-12-08 20:04:36 +00:00
if ( priv - > hisregcpy & MRVDRV_CMD_UPLD_RDY ) {
2007-05-25 11:27:16 -04:00
lbs_deb_thread ( " main-thread: cmd response ready \n " ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
priv - > hisregcpy & = ~ MRVDRV_CMD_UPLD_RDY ;
spin_unlock_irq ( & priv - > driver_lock ) ;
2007-11-15 18:05:47 -05:00
lbs_process_rx_command ( priv ) ;
2007-12-08 20:04:36 +00:00
spin_lock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-15 19:33:43 -05:00
if ( priv - > cmd_timed_out & & priv - > cur_cmd ) {
struct cmd_ctrl_node * cmdnode = priv - > cur_cmd ;
if ( + + priv - > nr_retries > 10 ) {
lbs_pr_info ( " Excessive timeouts submitting command %x \n " ,
le16_to_cpu ( cmdnode - > cmdbuf - > command ) ) ;
lbs_complete_command ( priv , cmdnode , - ETIMEDOUT ) ;
priv - > nr_retries = 0 ;
} else {
priv - > cur_cmd = NULL ;
lbs_pr_info ( " requeueing command %x due to timeout (#%d) \n " ,
le16_to_cpu ( cmdnode - > cmdbuf - > command ) , priv - > nr_retries ) ;
/* Stick it back at the _top_ of the pending queue
for immediate resubmission */
list_add ( & cmdnode - > list , & priv - > cmdpendingq ) ;
}
}
priv - > cmd_timed_out = 0 ;
2007-02-10 12:25:27 -02:00
/* Any Card Event */
2007-12-08 20:04:36 +00:00
if ( priv - > hisregcpy & MRVDRV_CARDEVENT ) {
2007-05-25 11:27:16 -04:00
lbs_deb_thread ( " main-thread: Card Event Activity \n " ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
priv - > hisregcpy & = ~ MRVDRV_CARDEVENT ;
2007-02-10 12:25:27 -02:00
2007-05-25 12:17:06 -04:00
if ( priv - > hw_read_event_cause ( priv ) ) {
2007-12-08 17:42:59 +00:00
lbs_pr_alert ( " main-thread: hw_read_event_cause failed \n " ) ;
2007-12-08 20:04:36 +00:00
spin_unlock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
continue ;
}
2007-12-08 20:04:36 +00:00
spin_unlock_irq ( & priv - > driver_lock ) ;
2007-11-15 18:05:47 -05:00
lbs_process_event ( priv ) ;
2007-02-10 12:25:27 -02:00
} else
2007-12-08 20:04:36 +00:00
spin_unlock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
2007-12-11 11:55:37 -05:00
if ( ! priv - > fw_ready )
continue ;
2007-02-10 12:25:27 -02:00
/* Check if we need to confirm Sleep Request received previously */
2007-12-08 20:04:36 +00:00
if ( priv - > psstate = = PS_STATE_PRE_SLEEP & &
! priv - > dnld_sent & & ! priv - > cur_cmd ) {
if ( priv - > connect_status = = LBS_CONNECTED ) {
2007-12-08 17:42:59 +00:00
lbs_deb_thread ( " main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now \n " ,
2007-12-08 20:04:36 +00:00
priv - > intcounter , priv - > currenttxskb , priv - > dnld_sent , priv - > cur_cmd ) ;
2007-12-08 17:42:59 +00:00
2007-12-08 20:04:36 +00:00
lbs_ps_confirm_sleep ( priv , ( u16 ) priv - > psmode ) ;
2007-12-08 17:42:59 +00:00
} else {
/* workaround for firmware sending
* deauth / linkloss event immediately
* after sleep request ; remove this
* after firmware fixes it
*/
2007-12-08 20:04:36 +00:00
priv - > psstate = PS_STATE_AWAKE ;
2007-12-08 17:42:59 +00:00
lbs_pr_alert ( " main-thread: ignore PS_SleepConfirm in non-connected state \n " ) ;
2007-02-10 12:25:27 -02:00
}
}
/* The PS state is changed during processing of Sleep Request
* event above
*/
2007-12-08 20:04:36 +00:00
if ( ( priv - > psstate = = PS_STATE_SLEEP ) | |
( priv - > psstate = = PS_STATE_PRE_SLEEP ) )
2007-02-10 12:25:27 -02:00
continue ;
/* Execute the next command */
2007-12-08 20:04:36 +00:00
if ( ! priv - > dnld_sent & & ! priv - > cur_cmd )
2007-11-15 18:05:47 -05:00
lbs_execute_next_command ( priv ) ;
2007-02-10 12:25:27 -02:00
/* Wake-up command waiters which can't sleep in
2007-11-15 18:05:47 -05:00
* lbs_prepare_and_send_command
2007-02-10 12:25:27 -02:00
*/
2007-12-08 20:04:36 +00:00
if ( ! list_empty ( & priv - > cmdpendingq ) )
wake_up_all ( & priv - > cmd_pending ) ;
2007-12-09 23:54:27 -05:00
spin_lock_irq ( & priv - > driver_lock ) ;
if ( ! priv - > dnld_sent & & priv - > tx_pending_len > 0 ) {
int ret = priv - > hw_host_to_card ( priv , MVMS_DAT ,
priv - > tx_pending_buf ,
priv - > tx_pending_len ) ;
if ( ret ) {
lbs_deb_tx ( " host_to_card failed %d \n " , ret ) ;
priv - > dnld_sent = DNLD_RES_RECEIVED ;
}
priv - > tx_pending_len = 0 ;
if ( ! priv - > currenttxskb ) {
/* We can wake the queues immediately if we aren't
waiting for TX feedback */
if ( priv - > connect_status = = LBS_CONNECTED )
netif_wake_queue ( priv - > dev ) ;
if ( priv - > mesh_dev & &
priv - > mesh_connect_status = = LBS_CONNECTED )
netif_wake_queue ( priv - > mesh_dev ) ;
}
}
spin_unlock_irq ( & priv - > driver_lock ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-08 20:04:36 +00:00
del_timer ( & priv - > command_timer ) ;
wake_up_all ( & priv - > cmd_pending ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_THREAD ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-12-12 17:38:56 -05:00
static int lbs_suspend_callback ( struct lbs_private * priv , unsigned long dummy ,
struct cmd_header * cmd )
{
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_FW ) ;
2007-12-12 17:38:56 -05:00
netif_device_detach ( priv - > dev ) ;
if ( priv - > mesh_dev )
netif_device_detach ( priv - > mesh_dev ) ;
priv - > fw_ready = 0 ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave ( LBS_DEB_FW ) ;
2007-12-12 17:38:56 -05:00
return 0 ;
}
int lbs_suspend ( struct lbs_private * priv )
{
struct cmd_header cmd ;
int ret ;
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_FW ) ;
2007-12-12 20:06:06 -05:00
if ( priv - > wol_criteria = = 0xffffffff ) {
lbs_pr_info ( " Suspend attempt without configuring wake params! \n " ) ;
return - EINVAL ;
}
2007-12-12 17:38:56 -05:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
2007-12-14 22:53:41 -05:00
2007-12-12 17:38:56 -05:00
ret = __lbs_cmd ( priv , CMD_802_11_HOST_SLEEP_ACTIVATE , & cmd ,
sizeof ( cmd ) , lbs_suspend_callback , 0 ) ;
if ( ret )
lbs_pr_info ( " HOST_SLEEP_ACTIVATE failed: %d \n " , ret ) ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave_args ( LBS_DEB_FW , " ret %d " , ret ) ;
2007-12-12 17:38:56 -05:00
return ret ;
}
EXPORT_SYMBOL_GPL ( lbs_suspend ) ;
int lbs_resume ( struct lbs_private * priv )
{
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_FW ) ;
2007-12-12 17:38:56 -05:00
priv - > fw_ready = 1 ;
/* Firmware doesn't seem to give us RX packets any more
until we send it some command . Might as well update */
lbs_prepare_and_send_command ( priv , CMD_802_11_RSSI , 0 ,
0 , 0 , NULL ) ;
netif_device_attach ( priv - > dev ) ;
if ( priv - > mesh_dev )
netif_device_attach ( priv - > mesh_dev ) ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave ( LBS_DEB_FW ) ;
2007-12-12 17:38:56 -05:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( lbs_resume ) ;
2007-08-02 11:45:12 -04:00
/**
* @ brief This function downloads firmware image , gets
* HW spec from firmware and set basic parameters to
* firmware .
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to struct lbs_private structure
2007-08-02 11:45:12 -04:00
* @ return 0 or - 1
*/
2007-11-23 15:43:44 +01:00
static int lbs_setup_firmware ( struct lbs_private * priv )
2007-08-02 11:45:12 -04:00
{
int ret = - 1 ;
lbs_deb_enter ( LBS_DEB_FW ) ;
/*
* Read MAC address from HW
*/
2007-12-08 20:04:36 +00:00
memset ( priv - > current_addr , 0xff , ETH_ALEN ) ;
2007-12-11 12:42:16 -05:00
ret = lbs_update_hw_spec ( priv ) ;
2007-08-02 11:45:12 -04:00
if ( ret ) {
ret = - 1 ;
goto done ;
}
2007-11-15 18:05:47 -05:00
lbs_set_mac_packet_filter ( priv ) ;
2007-08-02 11:45:12 -04:00
2007-12-11 15:50:59 -05:00
ret = lbs_get_data_rate ( priv ) ;
if ( ret < 0 ) {
2007-08-02 11:45:12 -04:00
ret = - 1 ;
goto done ;
}
ret = 0 ;
done :
lbs_deb_leave_args ( LBS_DEB_FW , " ret %d " , ret ) ;
return ret ;
}
/**
* This function handles the timeout of command sending .
* It will re - send the same command again .
*/
static void command_timer_fn ( unsigned long data )
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = ( struct lbs_private * ) data ;
2007-08-02 11:45:12 -04:00
unsigned long flags ;
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-12-15 19:33:43 -05:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
2007-08-02 11:45:12 -04:00
2007-12-15 19:33:43 -05:00
if ( ! priv - > cur_cmd ) {
lbs_pr_info ( " Command timer expired; no pending command \n " ) ;
goto out ;
2007-08-02 11:45:12 -04:00
}
2007-12-15 19:33:43 -05:00
lbs_pr_info ( " Command %x timed out \n " , le16_to_cpu ( priv - > cur_cmd - > cmdbuf - > command ) ) ;
2007-08-02 11:45:12 -04:00
2007-12-15 19:33:43 -05:00
priv - > cmd_timed_out = 1 ;
2007-08-02 11:45:12 -04:00
wake_up_interruptible ( & priv - > waitq ) ;
2008-01-16 15:59:52 +01:00
out :
2007-12-15 19:33:43 -05:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
2007-08-02 11:45:12 -04:00
}
2007-11-23 15:43:44 +01:00
static int lbs_init_adapter ( struct lbs_private * priv )
2007-08-02 11:49:06 -04:00
{
2007-08-02 11:45:12 -04:00
size_t bufsize ;
2007-08-20 11:43:25 -04:00
int i , ret = 0 ;
2007-08-02 11:45:12 -04:00
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-08-02 11:45:12 -04:00
/* Allocate buffer to store the BSSID list */
bufsize = MAX_NETWORK_COUNT * sizeof ( struct bss_descriptor ) ;
2007-12-08 20:04:36 +00:00
priv - > networks = kzalloc ( bufsize , GFP_KERNEL ) ;
if ( ! priv - > networks ) {
2007-08-02 11:45:12 -04:00
lbs_pr_err ( " Out of memory allocating beacons \n " ) ;
2007-08-20 11:43:25 -04:00
ret = - 1 ;
goto out ;
2007-08-02 11:45:12 -04:00
}
2007-08-20 11:43:25 -04:00
/* Initialize scan result lists */
2007-12-08 20:04:36 +00:00
INIT_LIST_HEAD ( & priv - > network_free_list ) ;
INIT_LIST_HEAD ( & priv - > network_list ) ;
2007-08-20 11:43:25 -04:00
for ( i = 0 ; i < MAX_NETWORK_COUNT ; i + + ) {
2007-12-08 20:04:36 +00:00
list_add_tail ( & priv - > networks [ i ] . list ,
& priv - > network_free_list ) ;
2007-08-20 11:43:25 -04:00
}
2007-08-02 11:45:12 -04:00
2007-12-08 20:04:36 +00:00
priv - > lbs_ps_confirm_sleep . seqnum = cpu_to_le16 ( + + priv - > seqnum ) ;
priv - > lbs_ps_confirm_sleep . command =
2007-08-02 11:45:12 -04:00
cpu_to_le16 ( CMD_802_11_PS_MODE ) ;
2007-12-08 20:04:36 +00:00
priv - > lbs_ps_confirm_sleep . size =
2007-08-02 11:45:12 -04:00
cpu_to_le16 ( sizeof ( struct PS_CMD_ConfirmSleep ) ) ;
2007-12-08 20:04:36 +00:00
priv - > lbs_ps_confirm_sleep . action =
2007-08-02 11:45:12 -04:00
cpu_to_le16 ( CMD_SUBCMD_SLEEP_CONFIRMED ) ;
2007-12-08 20:04:36 +00:00
memset ( priv - > current_addr , 0xff , ETH_ALEN ) ;
2007-08-02 11:45:12 -04:00
2007-12-08 20:04:36 +00:00
priv - > connect_status = LBS_DISCONNECTED ;
priv - > mesh_connect_status = LBS_DISCONNECTED ;
priv - > secinfo . auth_mode = IW_AUTH_ALG_OPEN_SYSTEM ;
priv - > mode = IW_MODE_INFRA ;
priv - > curbssparams . channel = DEFAULT_AD_HOC_CHANNEL ;
priv - > currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON ;
priv - > radioon = RADIO_ON ;
priv - > auto_rate = 1 ;
priv - > capability = WLAN_CAPABILITY_SHORT_PREAMBLE ;
priv - > psmode = LBS802_11POWERMODECAM ;
priv - > psstate = PS_STATE_FULL_POWER ;
2007-08-02 11:45:12 -04:00
2007-12-08 20:04:36 +00:00
mutex_init ( & priv - > lock ) ;
2007-08-02 11:45:12 -04:00
2007-12-08 20:04:36 +00:00
setup_timer ( & priv - > command_timer , command_timer_fn ,
2008-01-16 15:59:52 +01:00
( unsigned long ) priv ) ;
2007-08-02 11:45:12 -04:00
2007-12-08 20:04:36 +00:00
INIT_LIST_HEAD ( & priv - > cmdfreeq ) ;
INIT_LIST_HEAD ( & priv - > cmdpendingq ) ;
2007-08-02 11:45:12 -04:00
2007-12-08 20:04:36 +00:00
spin_lock_init ( & priv - > driver_lock ) ;
init_waitqueue_head ( & priv - > cmd_pending ) ;
2007-08-02 11:45:12 -04:00
2007-08-20 11:43:25 -04:00
/* Allocate the command buffers */
2007-11-15 18:05:47 -05:00
if ( lbs_allocate_cmd_buffer ( priv ) ) {
2007-08-20 11:43:25 -04:00
lbs_pr_err ( " Out of memory allocating command buffers \n " ) ;
ret = - 1 ;
}
2007-08-02 11:45:12 -04:00
2007-08-20 11:43:25 -04:00
out :
2008-01-16 15:59:52 +01:00
lbs_deb_leave_args ( LBS_DEB_MAIN , " ret %d " , ret ) ;
2007-08-20 11:43:25 -04:00
return ret ;
}
2007-08-02 11:45:12 -04:00
2007-11-23 15:43:44 +01:00
static void lbs_free_adapter ( struct lbs_private * priv )
2007-08-20 11:43:25 -04:00
{
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-08-02 11:45:12 -04:00
2008-01-16 15:59:52 +01:00
lbs_free_cmd_buffer ( priv ) ;
2007-12-08 20:04:36 +00:00
del_timer ( & priv - > command_timer ) ;
kfree ( priv - > networks ) ;
priv - > networks = NULL ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave ( LBS_DEB_MAIN ) ;
2007-08-02 11:45:12 -04:00
}
2007-02-10 12:25:27 -02:00
/**
* @ brief This function adds the card . it will probe the
2007-11-15 18:05:47 -05:00
* card , allocate the lbs_priv and initialize the device .
2007-02-10 12:25:27 -02:00
*
* @ param card A pointer to card
2007-11-23 15:43:44 +01:00
* @ return A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
*/
2007-11-23 15:43:44 +01:00
struct lbs_private * lbs_add_card ( void * card , struct device * dmdev )
2007-02-10 12:25:27 -02:00
{
struct net_device * dev = NULL ;
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = NULL ;
2007-02-10 12:25:27 -02:00
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-02-10 12:25:27 -02:00
/* Allocate an Ethernet device and register it */
2007-11-23 15:43:44 +01:00
dev = alloc_etherdev ( sizeof ( struct lbs_private ) ) ;
if ( ! dev ) {
2007-05-25 11:27:16 -04:00
lbs_pr_err ( " init ethX device failed \n " ) ;
2007-08-20 11:43:25 -04:00
goto done ;
2007-02-10 12:25:27 -02:00
}
2007-08-20 11:45:16 -04:00
priv = dev - > priv ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
if ( lbs_init_adapter ( priv ) ) {
2007-08-20 11:43:25 -04:00
lbs_pr_err ( " failed to initialize adapter structure. \n " ) ;
goto err_init_adapter ;
}
2007-05-25 13:05:16 -04:00
priv - > dev = dev ;
priv - > card = card ;
2007-02-10 12:25:27 -02:00
priv - > mesh_open = 0 ;
priv - > infra_open = 0 ;
/* Setup the OS Interface to our functions */
2007-12-10 16:38:18 -05:00
dev - > open = lbs_dev_open ;
2007-12-09 15:04:19 -05:00
dev - > hard_start_xmit = lbs_hard_start_xmit ;
2007-12-10 16:38:18 -05:00
dev - > stop = lbs_eth_stop ;
2007-11-15 18:05:47 -05:00
dev - > set_mac_address = lbs_set_mac_address ;
dev - > tx_timeout = lbs_tx_timeout ;
dev - > get_stats = lbs_get_stats ;
2007-05-25 11:58:22 -04:00
dev - > watchdog_timeo = 5 * HZ ;
2007-11-15 18:05:47 -05:00
dev - > ethtool_ops = & lbs_ethtool_ops ;
2007-02-10 12:25:27 -02:00
# ifdef WIRELESS_EXT
2007-11-15 18:05:47 -05:00
dev - > wireless_handlers = ( struct iw_handler_def * ) & lbs_handler_def ;
2007-02-10 12:25:27 -02:00
# endif
dev - > flags | = IFF_BROADCAST | IFF_MULTICAST ;
2007-11-15 18:05:47 -05:00
dev - > set_multicast_list = lbs_set_multicast_list ;
2007-02-10 12:25:27 -02:00
2007-05-25 13:13:25 -04:00
SET_NETDEV_DEV ( dev , dmdev ) ;
2007-08-02 13:16:55 -04:00
priv - > rtap_net_dev = NULL ;
2007-08-20 11:43:25 -04:00
lbs_deb_thread ( " Starting main thread... \n " ) ;
init_waitqueue_head ( & priv - > waitq ) ;
2007-11-15 18:05:47 -05:00
priv - > main_thread = kthread_run ( lbs_thread , dev , " lbs_main " ) ;
2007-08-20 11:43:25 -04:00
if ( IS_ERR ( priv - > main_thread ) ) {
lbs_deb_thread ( " Error creating main thread. \n " ) ;
2007-12-08 18:29:16 +00:00
goto err_init_adapter ;
2007-08-20 11:43:25 -04:00
}
2007-11-15 18:05:47 -05:00
priv - > work_thread = create_singlethread_workqueue ( " lbs_worker " ) ;
INIT_DELAYED_WORK ( & priv - > assoc_work , lbs_association_worker ) ;
INIT_DELAYED_WORK ( & priv - > scan_work , lbs_scan_worker ) ;
INIT_WORK ( & priv - > sync_channel , lbs_sync_channel ) ;
2007-08-20 11:43:25 -04:00
2007-12-11 18:56:42 -05:00
sprintf ( priv - > mesh_ssid , " mesh " ) ;
priv - > mesh_ssid_len = 4 ;
2007-12-12 20:06:06 -05:00
priv - > wol_criteria = 0xffffffff ;
priv - > wol_gpio = 0xff ;
2007-05-25 12:04:31 -04:00
goto done ;
2007-08-20 11:43:25 -04:00
err_init_adapter :
2007-11-15 18:05:47 -05:00
lbs_free_adapter ( priv ) ;
2007-05-25 12:04:31 -04:00
free_netdev ( dev ) ;
2007-05-25 12:09:13 -04:00
priv = NULL ;
2007-08-20 11:43:25 -04:00
2007-05-25 12:04:31 -04:00
done :
2008-01-16 15:59:52 +01:00
lbs_deb_leave_args ( LBS_DEB_MAIN , " priv %p " , priv ) ;
2007-05-25 12:04:31 -04:00
return priv ;
}
2007-11-15 18:05:47 -05:00
EXPORT_SYMBOL_GPL ( lbs_add_card ) ;
2007-05-25 12:04:31 -04:00
2007-08-20 11:43:25 -04:00
2007-11-23 15:43:44 +01:00
int lbs_remove_card ( struct lbs_private * priv )
2007-05-25 12:04:31 -04:00
{
2007-05-25 13:05:16 -04:00
struct net_device * dev = priv - > dev ;
2007-08-20 11:43:25 -04:00
union iwreq_data wrqu ;
2007-05-25 12:04:31 -04:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-02-10 12:25:27 -02:00
2007-12-11 18:56:42 -05:00
lbs_remove_mesh ( priv ) ;
2007-11-15 18:05:47 -05:00
lbs_remove_rtap ( priv ) ;
2007-02-10 12:25:27 -02:00
2007-08-20 11:43:25 -04:00
dev = priv - > dev ;
2007-08-02 13:19:04 -04:00
2007-08-20 11:43:25 -04:00
cancel_delayed_work ( & priv - > scan_work ) ;
cancel_delayed_work ( & priv - > assoc_work ) ;
destroy_workqueue ( priv - > work_thread ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
if ( priv - > psmode = = LBS802_11POWERMODEMAX_PSP ) {
priv - > psmode = LBS802_11POWERMODECAM ;
2007-11-15 18:05:47 -05:00
lbs_ps_wakeup ( priv , CMD_OPTION_WAITFORRSP ) ;
2007-02-10 12:25:27 -02:00
}
2007-08-20 11:43:25 -04:00
memset ( wrqu . ap_addr . sa_data , 0xaa , ETH_ALEN ) ;
wrqu . ap_addr . sa_family = ARPHRD_ETHER ;
wireless_send_event ( priv - > dev , SIOCGIWAP , & wrqu , NULL ) ;
/* Stop the thread servicing the interrupts */
2007-12-08 20:04:36 +00:00
priv - > surpriseremoved = 1 ;
2007-08-20 11:43:25 -04:00
kthread_stop ( priv - > main_thread ) ;
2007-11-15 18:05:47 -05:00
lbs_free_adapter ( priv ) ;
2007-08-20 11:43:25 -04:00
priv - > dev = NULL ;
free_netdev ( dev ) ;
lbs_deb_leave ( LBS_DEB_MAIN ) ;
return 0 ;
}
2007-11-15 18:05:47 -05:00
EXPORT_SYMBOL_GPL ( lbs_remove_card ) ;
2007-08-20 11:43:25 -04:00
2007-11-23 15:43:44 +01:00
int lbs_start_card ( struct lbs_private * priv )
2007-08-20 11:43:25 -04:00
{
struct net_device * dev = priv - > dev ;
int ret = - 1 ;
lbs_deb_enter ( LBS_DEB_MAIN ) ;
/* poke the firmware */
2007-11-15 18:05:47 -05:00
ret = lbs_setup_firmware ( priv ) ;
2007-08-20 11:43:25 -04:00
if ( ret )
goto done ;
/* init 802.11d */
2007-11-15 18:05:47 -05:00
lbs_init_11d ( priv ) ;
2007-02-10 12:25:27 -02:00
if ( register_netdev ( dev ) ) {
2007-05-25 11:27:16 -04:00
lbs_pr_err ( " cannot register ethX device \n " ) ;
2007-08-20 11:43:25 -04:00
goto done ;
2007-02-10 12:25:27 -02:00
}
2007-12-08 18:29:16 +00:00
if ( device_create_file ( & dev - > dev , & dev_attr_lbs_rtap ) )
lbs_pr_err ( " cannot register lbs_rtap attribute \n " ) ;
2007-12-12 23:29:13 -05:00
lbs_update_channel ( priv ) ;
2008-01-16 15:57:44 +01:00
/* 5.0.16p0 is known to NOT support any mesh */
if ( priv - > fwrelease > 0x05001000 ) {
/* Enable mesh, if supported, and work out which TLV it uses.
0x100 + 291 is an unofficial value used in 5.110 .20 . pXX
0x100 + 37 is the official value used in 5.110 .21 . pXX
but we check them in that order because 20. pXX doesn ' t
give an error - - it just silently fails . */
/* 5.110.20.pXX firmware will fail the command if the channel
doesn ' t match the existing channel . But only if the TLV
is correct . If the channel is wrong , _BOTH_ versions will
give an error to 0x100 + 291 , and allow 0x100 + 37 to succeed .
It ' s just that 5.110 .20 . pXX will not have done anything
useful */
priv - > mesh_tlv = 0x100 + 291 ;
if ( lbs_mesh_config ( priv , 1 , priv - > curbssparams . channel ) ) {
priv - > mesh_tlv = 0x100 + 37 ;
if ( lbs_mesh_config ( priv , 1 , priv - > curbssparams . channel ) )
priv - > mesh_tlv = 0 ;
}
if ( priv - > mesh_tlv ) {
lbs_add_mesh ( priv ) ;
if ( device_create_file ( & dev - > dev , & dev_attr_lbs_mesh ) )
lbs_pr_err ( " cannot register lbs_mesh attribute \n " ) ;
}
2007-12-12 23:29:13 -05:00
}
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
lbs_debugfs_init_one ( priv , dev ) ;
2007-02-10 12:25:27 -02:00
2007-08-20 11:43:25 -04:00
lbs_pr_info ( " %s: Marvell WLAN 802.11 adapter \n " , dev - > name ) ;
2007-05-25 12:04:31 -04:00
ret = 0 ;
2007-02-10 12:25:27 -02:00
2007-05-25 12:04:31 -04:00
done :
2007-08-20 11:43:25 -04:00
lbs_deb_leave_args ( LBS_DEB_MAIN , " ret %d " , ret ) ;
return ret ;
}
2007-11-15 18:05:47 -05:00
EXPORT_SYMBOL_GPL ( lbs_start_card ) ;
2007-08-20 11:43:25 -04:00
2007-11-23 15:43:44 +01:00
int lbs_stop_card ( struct lbs_private * priv )
2007-08-20 11:43:25 -04:00
{
struct net_device * dev = priv - > dev ;
int ret = - 1 ;
struct cmd_ctrl_node * cmdnode ;
unsigned long flags ;
lbs_deb_enter ( LBS_DEB_MAIN ) ;
netif_stop_queue ( priv - > dev ) ;
netif_carrier_off ( priv - > dev ) ;
2007-11-15 18:05:47 -05:00
lbs_debugfs_remove_one ( priv ) ;
2007-12-11 12:54:43 -05:00
device_remove_file ( & dev - > dev , & dev_attr_lbs_rtap ) ;
2007-12-12 23:29:13 -05:00
if ( priv - > mesh_tlv )
device_remove_file ( & dev - > dev , & dev_attr_lbs_mesh ) ;
2007-08-20 11:43:25 -04:00
/* Flush pending command nodes */
2007-12-08 20:04:36 +00:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
list_for_each_entry ( cmdnode , & priv - > cmdpendingq , list ) {
2007-12-15 04:22:52 -05:00
cmdnode - > result = - ENOENT ;
2007-08-20 11:43:25 -04:00
cmdnode - > cmdwaitqwoken = 1 ;
wake_up_interruptible ( & cmdnode - > cmdwait_q ) ;
}
2007-12-08 20:04:36 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-08-20 11:43:25 -04:00
unregister_netdev ( dev ) ;
lbs_deb_leave_args ( LBS_DEB_MAIN , " ret %d " , ret ) ;
2007-05-25 12:04:31 -04:00
return ret ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
EXPORT_SYMBOL_GPL ( lbs_stop_card ) ;
2007-05-25 12:37:58 -04:00
2007-02-10 12:25:27 -02:00
2007-05-25 11:49:19 -04:00
/**
* @ brief This function adds mshX interface
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to the struct lbs_private structure
2007-05-25 11:49:19 -04:00
* @ return 0 if successful , - X otherwise
*/
2007-12-11 18:56:42 -05:00
static int lbs_add_mesh ( struct lbs_private * priv )
2007-05-25 11:49:19 -04:00
{
struct net_device * mesh_dev = NULL ;
int ret = 0 ;
lbs_deb_enter ( LBS_DEB_MESH ) ;
/* Allocate a virtual mesh device */
if ( ! ( mesh_dev = alloc_netdev ( 0 , " msh%d " , ether_setup ) ) ) {
lbs_deb_mesh ( " init mshX device failed \n " ) ;
ret = - ENOMEM ;
goto done ;
}
mesh_dev - > priv = priv ;
priv - > mesh_dev = mesh_dev ;
2007-12-10 16:38:18 -05:00
mesh_dev - > open = lbs_dev_open ;
2007-12-09 15:04:19 -05:00
mesh_dev - > hard_start_xmit = lbs_hard_start_xmit ;
2007-12-10 16:38:18 -05:00
mesh_dev - > stop = lbs_mesh_stop ;
2007-11-15 18:05:47 -05:00
mesh_dev - > get_stats = lbs_get_stats ;
mesh_dev - > set_mac_address = lbs_set_mac_address ;
mesh_dev - > ethtool_ops = & lbs_ethtool_ops ;
2007-05-25 13:05:16 -04:00
memcpy ( mesh_dev - > dev_addr , priv - > dev - > dev_addr ,
sizeof ( priv - > dev - > dev_addr ) ) ;
2007-05-25 11:49:19 -04:00
2007-12-11 18:56:42 -05:00
SET_NETDEV_DEV ( priv - > mesh_dev , priv - > dev - > dev . parent ) ;
2007-05-25 13:13:25 -04:00
2007-05-25 11:49:19 -04:00
# ifdef WIRELESS_EXT
2007-05-25 23:08:34 -04:00
mesh_dev - > wireless_handlers = ( struct iw_handler_def * ) & mesh_handler_def ;
2007-05-25 11:49:19 -04:00
# endif
/* Register virtual mesh interface */
ret = register_netdev ( mesh_dev ) ;
if ( ret ) {
lbs_pr_err ( " cannot register mshX virtual interface \n " ) ;
goto err_free ;
}
2007-11-15 18:05:47 -05:00
ret = sysfs_create_group ( & ( mesh_dev - > dev . kobj ) , & lbs_mesh_attr_group ) ;
2007-05-25 11:49:19 -04:00
if ( ret )
goto err_unregister ;
/* Everything successful */
ret = 0 ;
goto done ;
err_unregister :
unregister_netdev ( mesh_dev ) ;
err_free :
free_netdev ( mesh_dev ) ;
done :
lbs_deb_leave_args ( LBS_DEB_MESH , " ret %d " , ret ) ;
return ret ;
}
2007-05-25 12:37:58 -04:00
2007-12-11 18:56:42 -05:00
static void lbs_remove_mesh ( struct lbs_private * priv )
2007-05-25 11:49:19 -04:00
{
struct net_device * mesh_dev ;
mesh_dev = priv - > mesh_dev ;
2007-12-11 18:56:42 -05:00
if ( ! mesh_dev )
2008-01-16 15:59:52 +01:00
return ;
2007-05-25 11:49:19 -04:00
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_MESH ) ;
2007-05-25 11:49:19 -04:00
netif_stop_queue ( mesh_dev ) ;
2007-05-25 12:06:56 -04:00
netif_carrier_off ( priv - > mesh_dev ) ;
2007-11-15 18:05:47 -05:00
sysfs_remove_group ( & ( mesh_dev - > dev . kobj ) , & lbs_mesh_attr_group ) ;
2007-05-25 11:49:19 -04:00
unregister_netdev ( mesh_dev ) ;
2007-12-11 18:56:42 -05:00
priv - > mesh_dev = NULL ;
2007-05-25 11:49:19 -04:00
free_netdev ( mesh_dev ) ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave ( LBS_DEB_MESH ) ;
2007-05-25 11:49:19 -04:00
}
2007-02-10 12:25:27 -02:00
/**
* @ brief This function finds the CFP in
* region_cfp_table based on region and band parameter .
*
* @ param region The region code
* @ param band The band
* @ param cfp_no A pointer to CFP number
* @ return A pointer to CFP
*/
2007-11-15 18:05:47 -05:00
struct chan_freq_power * lbs_get_region_cfp_table ( u8 region , u8 band , int * cfp_no )
2007-02-10 12:25:27 -02:00
{
int i , end ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-02-10 12:25:27 -02:00
2007-09-02 18:30:18 +08:00
end = ARRAY_SIZE ( region_cfp_table ) ;
2007-02-10 12:25:27 -02:00
for ( i = 0 ; i < end ; i + + ) {
2007-05-25 11:27:16 -04:00
lbs_deb_main ( " region_cfp_table[i].region=%d \n " ,
2007-02-10 12:25:27 -02:00
region_cfp_table [ i ] . region ) ;
if ( region_cfp_table [ i ] . region = = region ) {
* cfp_no = region_cfp_table [ i ] . cfp_no_BG ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_MAIN ) ;
2007-02-10 12:25:27 -02:00
return region_cfp_table [ i ] . cfp_BG ;
}
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_MAIN , " ret NULL " ) ;
2007-02-10 12:25:27 -02:00
return NULL ;
}
2007-11-23 15:43:44 +01:00
int lbs_set_regiontable ( struct lbs_private * priv , u8 region , u8 band )
2007-02-10 12:25:27 -02:00
{
2007-05-25 11:27:16 -04:00
int ret = 0 ;
2007-02-10 12:25:27 -02:00
int i = 0 ;
struct chan_freq_power * cfp ;
int cfp_no ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
memset ( priv - > region_channel , 0 , sizeof ( priv - > region_channel ) ) ;
2007-02-10 12:25:27 -02:00
2008-01-16 15:59:52 +01:00
cfp = lbs_get_region_cfp_table ( region , band , & cfp_no ) ;
if ( cfp ! = NULL ) {
priv - > region_channel [ i ] . nrcfp = cfp_no ;
priv - > region_channel [ i ] . CFP = cfp ;
} else {
lbs_deb_main ( " wrong region code %#x in band B/G \n " ,
region ) ;
ret = - 1 ;
goto out ;
2007-02-10 12:25:27 -02:00
}
2008-01-16 15:59:52 +01:00
priv - > region_channel [ i ] . valid = 1 ;
priv - > region_channel [ i ] . region = region ;
priv - > region_channel [ i ] . band = band ;
i + + ;
2007-05-25 11:27:16 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_MAIN , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
/**
* @ brief This function handles the interrupt . it will change PS
* state if applicable . it will wake up main_thread to handle
* the interrupt event as well .
*
* @ param dev A pointer to net_device structure
* @ return n / a
*/
2007-12-10 14:58:37 -05:00
void lbs_interrupt ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
2007-05-25 11:52:42 -04:00
lbs_deb_enter ( LBS_DEB_THREAD ) ;
2007-02-10 12:25:27 -02:00
2007-12-10 14:58:37 -05:00
lbs_deb_thread ( " lbs_interrupt: intcounter=%d \n " , priv - > intcounter ) ;
2007-12-08 20:04:36 +00:00
priv - > intcounter + + ;
2007-12-10 14:58:37 -05:00
if ( priv - > psstate = = PS_STATE_SLEEP )
2007-12-08 20:04:36 +00:00
priv - > psstate = PS_STATE_AWAKE ;
2007-08-02 11:32:25 -04:00
wake_up_interruptible ( & priv - > waitq ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:52:42 -04:00
lbs_deb_leave ( LBS_DEB_THREAD ) ;
2007-02-10 12:25:27 -02:00
}
2007-11-15 18:05:47 -05:00
EXPORT_SYMBOL_GPL ( lbs_interrupt ) ;
2007-02-10 12:25:27 -02:00
2007-11-20 17:43:45 -05:00
static int __init lbs_init_module ( void )
2007-02-10 12:25:27 -02:00
{
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-11-15 18:05:47 -05:00
lbs_debugfs_init ( ) ;
2007-05-25 12:37:58 -04:00
lbs_deb_leave ( LBS_DEB_MAIN ) ;
return 0 ;
2007-02-10 12:25:27 -02:00
}
2007-11-20 17:43:45 -05:00
static void __exit lbs_exit_module ( void )
2007-02-10 12:25:27 -02:00
{
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-11-15 18:05:47 -05:00
lbs_debugfs_remove ( ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_MAIN ) ;
2007-02-10 12:25:27 -02:00
}
2007-08-02 13:16:55 -04:00
/*
* rtap interface support fuctions
*/
2007-11-15 18:05:47 -05:00
static int lbs_rtap_open ( struct net_device * dev )
2007-08-02 13:16:55 -04:00
{
2007-12-10 16:38:18 -05:00
/* Yes, _stop_ the queue. Because we don't support injection */
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
netif_carrier_off ( dev ) ;
netif_stop_queue ( dev ) ;
lbs_deb_leave ( LBS_DEB_LEAVE ) ;
return 0 ;
2007-08-02 13:16:55 -04:00
}
2007-11-15 18:05:47 -05:00
static int lbs_rtap_stop ( struct net_device * dev )
2007-08-02 13:16:55 -04:00
{
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
lbs_deb_leave ( LBS_DEB_MAIN ) ;
return 0 ;
2007-08-02 13:16:55 -04:00
}
2007-11-15 18:05:47 -05:00
static int lbs_rtap_hard_start_xmit ( struct sk_buff * skb , struct net_device * dev )
2007-08-02 13:16:55 -04:00
{
2008-01-16 15:59:52 +01:00
netif_stop_queue ( dev ) ;
return NETDEV_TX_BUSY ;
2007-08-02 13:16:55 -04:00
}
2007-11-15 18:05:47 -05:00
static struct net_device_stats * lbs_rtap_get_stats ( struct net_device * dev )
2007-08-02 13:16:55 -04:00
{
2007-11-23 15:43:44 +01:00
struct lbs_private * priv = dev - > priv ;
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-12-09 16:22:21 -05:00
return & priv - > stats ;
2007-08-02 13:16:55 -04:00
}
2007-12-11 17:44:10 -05:00
static void lbs_remove_rtap ( struct lbs_private * priv )
2007-08-02 13:16:55 -04:00
{
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-08-02 13:16:55 -04:00
if ( priv - > rtap_net_dev = = NULL )
return ;
unregister_netdev ( priv - > rtap_net_dev ) ;
2007-12-09 16:22:21 -05:00
free_netdev ( priv - > rtap_net_dev ) ;
2007-08-02 13:16:55 -04:00
priv - > rtap_net_dev = NULL ;
2008-01-16 15:59:52 +01:00
lbs_deb_leave ( LBS_DEB_MAIN ) ;
2007-08-02 13:16:55 -04:00
}
2007-12-11 17:44:10 -05:00
static int lbs_add_rtap ( struct lbs_private * priv )
2007-08-02 13:16:55 -04:00
{
2008-01-16 15:59:52 +01:00
int ret = 0 ;
2007-12-09 16:22:21 -05:00
struct net_device * rtap_dev ;
2007-08-02 13:16:55 -04:00
2008-01-16 15:59:52 +01:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
if ( priv - > rtap_net_dev ) {
ret = - EPERM ;
goto out ;
}
2007-08-02 13:16:55 -04:00
2007-12-09 16:22:21 -05:00
rtap_dev = alloc_netdev ( 0 , " rtap%d " , ether_setup ) ;
2008-01-16 15:59:52 +01:00
if ( rtap_dev = = NULL ) {
ret = - ENOMEM ;
goto out ;
}
2007-08-02 13:16:55 -04:00
2007-12-09 19:54:11 -05:00
memcpy ( rtap_dev - > dev_addr , priv - > current_addr , ETH_ALEN ) ;
2007-12-09 16:22:21 -05:00
rtap_dev - > type = ARPHRD_IEEE80211_RADIOTAP ;
rtap_dev - > open = lbs_rtap_open ;
rtap_dev - > stop = lbs_rtap_stop ;
rtap_dev - > get_stats = lbs_rtap_get_stats ;
rtap_dev - > hard_start_xmit = lbs_rtap_hard_start_xmit ;
rtap_dev - > set_multicast_list = lbs_set_multicast_list ;
rtap_dev - > priv = priv ;
2007-08-02 13:16:55 -04:00
2008-01-16 15:59:52 +01:00
ret = register_netdev ( rtap_dev ) ;
if ( ret ) {
2007-12-09 16:22:21 -05:00
free_netdev ( rtap_dev ) ;
2008-01-16 15:59:52 +01:00
goto out ;
2007-08-02 13:16:55 -04:00
}
2007-12-09 16:22:21 -05:00
priv - > rtap_net_dev = rtap_dev ;
2007-08-02 13:16:55 -04:00
2008-01-16 15:59:52 +01:00
out :
lbs_deb_leave_args ( LBS_DEB_MAIN , " ret %d " , ret ) ;
return ret ;
2007-08-02 13:16:55 -04:00
}
2007-11-15 18:05:47 -05:00
module_init ( lbs_init_module ) ;
module_exit ( lbs_exit_module ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 12:37:58 -04:00
MODULE_DESCRIPTION ( " Libertas WLAN Driver Library " ) ;
2007-02-10 12:25:27 -02:00
MODULE_AUTHOR ( " Marvell International Ltd. " ) ;
MODULE_LICENSE ( " GPL " ) ;