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/freezer.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-02-10 12:25:27 -02:00
2007-08-03 09:43:03 -04:00
# define DRIVER_RELEASE_VERSION "323.p0"
2007-05-10 23:03:07 -04:00
const char libertas_driver_version [ ] = " COMM-USB8388- " DRIVER_RELEASE_VERSION
# ifdef DEBUG
" -dbg "
# endif
" " ;
2007-05-25 11:32:07 -04:00
/* Module parameters */
unsigned int libertas_debug = 0 ;
module_param ( libertas_debug , int , 0644 ) ;
2007-05-25 12:37:58 -04:00
EXPORT_SYMBOL_GPL ( libertas_debug ) ;
2007-05-25 11:32:07 -04:00
2007-02-10 12:25:27 -02:00
# define WLAN_TX_PWR_DEFAULT 20 /*100mW */
# define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */
# define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */
# define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */
# define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */
/* Format { channel, frequency (MHz), maxtxpower } */
/* band: 'B/G', region: USA FCC/Canada IC */
static struct chan_freq_power channel_freq_power_US_BG [ ] = {
{ 1 , 2412 , WLAN_TX_PWR_US_DEFAULT } ,
{ 2 , 2417 , WLAN_TX_PWR_US_DEFAULT } ,
{ 3 , 2422 , WLAN_TX_PWR_US_DEFAULT } ,
{ 4 , 2427 , WLAN_TX_PWR_US_DEFAULT } ,
{ 5 , 2432 , WLAN_TX_PWR_US_DEFAULT } ,
{ 6 , 2437 , WLAN_TX_PWR_US_DEFAULT } ,
{ 7 , 2442 , WLAN_TX_PWR_US_DEFAULT } ,
{ 8 , 2447 , WLAN_TX_PWR_US_DEFAULT } ,
{ 9 , 2452 , WLAN_TX_PWR_US_DEFAULT } ,
{ 10 , 2457 , WLAN_TX_PWR_US_DEFAULT } ,
{ 11 , 2462 , WLAN_TX_PWR_US_DEFAULT }
} ;
/* band: 'B/G', region: Europe ETSI */
static struct chan_freq_power channel_freq_power_EU_BG [ ] = {
{ 1 , 2412 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 2 , 2417 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 3 , 2422 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 4 , 2427 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 5 , 2432 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 6 , 2437 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 7 , 2442 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 8 , 2447 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 9 , 2452 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 10 , 2457 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 11 , 2462 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 12 , 2467 , WLAN_TX_PWR_EMEA_DEFAULT } ,
{ 13 , 2472 , WLAN_TX_PWR_EMEA_DEFAULT }
} ;
/* band: 'B/G', region: Spain */
static struct chan_freq_power channel_freq_power_SPN_BG [ ] = {
{ 10 , 2457 , WLAN_TX_PWR_DEFAULT } ,
{ 11 , 2462 , WLAN_TX_PWR_DEFAULT }
} ;
/* band: 'B/G', region: France */
static struct chan_freq_power channel_freq_power_FR_BG [ ] = {
{ 10 , 2457 , WLAN_TX_PWR_FR_DEFAULT } ,
{ 11 , 2462 , WLAN_TX_PWR_FR_DEFAULT } ,
{ 12 , 2467 , WLAN_TX_PWR_FR_DEFAULT } ,
{ 13 , 2472 , WLAN_TX_PWR_FR_DEFAULT }
} ;
/* band: 'B/G', region: Japan */
static struct chan_freq_power channel_freq_power_JPN_BG [ ] = {
{ 1 , 2412 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 2 , 2417 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 3 , 2422 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 4 , 2427 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 5 , 2432 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 6 , 2437 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 7 , 2442 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 8 , 2447 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 9 , 2452 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 10 , 2457 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 11 , 2462 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 12 , 2467 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 13 , 2472 , WLAN_TX_PWR_JP_DEFAULT } ,
{ 14 , 2484 , WLAN_TX_PWR_JP_DEFAULT }
} ;
/**
* 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 ,
sizeof ( channel_freq_power_US_BG ) / sizeof ( struct chan_freq_power ) ,
}
,
{ 0x20 , /*CANADA IC */
channel_freq_power_US_BG ,
sizeof ( channel_freq_power_US_BG ) / sizeof ( struct chan_freq_power ) ,
}
,
{ 0x30 , /*EU*/ channel_freq_power_EU_BG ,
sizeof ( channel_freq_power_EU_BG ) / sizeof ( struct chan_freq_power ) ,
}
,
{ 0x31 , /*SPAIN*/ channel_freq_power_SPN_BG ,
sizeof ( channel_freq_power_SPN_BG ) / sizeof ( struct chan_freq_power ) ,
}
,
{ 0x32 , /*FRANCE*/ channel_freq_power_FR_BG ,
sizeof ( channel_freq_power_FR_BG ) / sizeof ( struct chan_freq_power ) ,
}
,
{ 0x40 , /*JAPAN*/ channel_freq_power_JPN_BG ,
sizeof ( channel_freq_power_JPN_BG ) / sizeof ( struct chan_freq_power ) ,
}
,
/*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-08-02 11:40:45 -04:00
u16 libertas_region_code_to_index [ MRVDRV_MAX_REGION_CODE ] =
{ 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-08-02 11:40:45 -04:00
u8 libertas_bg_rates [ MAX_RATES ] =
{ 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-08-02 11:40:45 -04:00
u32 libertas_fw_index_to_data_rate ( u8 idx )
{
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
*/
u8 libertas_data_rate_to_fw_index ( u32 rate )
{
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-06-07 16:40:59 -04:00
static ssize_t libertas_anycast_get ( struct device * dev ,
2007-06-18 11:50:43 -04:00
struct device_attribute * attr , char * buf )
{
2007-02-10 12:25:27 -02:00
struct cmd_ds_mesh_access mesh_access ;
memset ( & mesh_access , 0 , sizeof ( mesh_access ) ) ;
libertas_prepare_and_send_command ( to_net_dev ( dev ) - > priv ,
2007-08-02 11:31:18 -04:00
CMD_MESH_ACCESS ,
CMD_ACT_MESH_GET_ANYCAST ,
CMD_OPTION_WAITFORRSP , 0 , ( void * ) & mesh_access ) ;
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-06-07 16:40:59 -04:00
static ssize_t libertas_anycast_set ( struct device * dev ,
2007-06-18 11:50:43 -04:00
struct device_attribute * attr , const char * buf , size_t count )
{
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-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-02-10 12:25:27 -02:00
libertas_prepare_and_send_command ( ( to_net_dev ( dev ) ) - > priv ,
2007-08-02 11:31:18 -04:00
CMD_MESH_ACCESS ,
CMD_ACT_MESH_SET_ANYCAST ,
CMD_OPTION_WAITFORRSP , 0 , ( void * ) & mesh_access ) ;
2007-02-10 12:25:27 -02:00
return strlen ( buf ) ;
}
2007-08-02 13:16:55 -04:00
int libertas_add_rtap ( wlan_private * priv ) ;
void libertas_remove_rtap ( wlan_private * priv ) ;
/**
* Get function for sysfs attribute rtap
*/
static ssize_t libertas_rtap_get ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2007-08-20 11:45:16 -04:00
wlan_private * priv = ( wlan_private * ) ( to_net_dev ( dev ) ) - > priv ;
2007-08-02 13:16:55 -04:00
wlan_adapter * adapter = priv - > adapter ;
return snprintf ( buf , 5 , " 0x%X \n " , adapter - > monitormode ) ;
}
/**
* Set function for sysfs attribute rtap
*/
static ssize_t libertas_rtap_set ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
int monitor_mode ;
2007-08-20 11:45:16 -04:00
wlan_private * priv = ( wlan_private * ) ( to_net_dev ( dev ) ) - > priv ;
2007-08-02 13:16:55 -04:00
wlan_adapter * adapter = priv - > adapter ;
sscanf ( buf , " %x " , & monitor_mode ) ;
if ( monitor_mode ! = WLAN_MONITOR_OFF ) {
if ( adapter - > monitormode = = monitor_mode )
return strlen ( buf ) ;
if ( adapter - > monitormode = = WLAN_MONITOR_OFF ) {
if ( adapter - > mode = = IW_MODE_INFRA )
libertas_send_deauthentication ( priv ) ;
else if ( adapter - > mode = = IW_MODE_ADHOC )
libertas_stop_adhoc_network ( priv ) ;
libertas_add_rtap ( priv ) ;
}
adapter - > monitormode = monitor_mode ;
}
else {
if ( adapter - > monitormode = = WLAN_MONITOR_OFF )
return strlen ( buf ) ;
adapter - > monitormode = WLAN_MONITOR_OFF ;
libertas_remove_rtap ( priv ) ;
netif_wake_queue ( priv - > dev ) ;
netif_wake_queue ( priv - > mesh_dev ) ;
}
libertas_prepare_and_send_command ( priv ,
CMD_802_11_MONITOR_MODE , CMD_ACT_SET ,
CMD_OPTION_WAITFORRSP , 0 , & adapter - > monitormode ) ;
return strlen ( buf ) ;
}
/**
* libertas_rtap attribute to be exported per mshX interface
* through sysfs ( / sys / class / net / mshX / libertas - rtap )
*/
static DEVICE_ATTR ( libertas_rtap , 0644 , libertas_rtap_get ,
libertas_rtap_set ) ;
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-06-07 16:40:59 -04:00
static DEVICE_ATTR ( anycast_mask , 0644 , libertas_anycast_get , libertas_anycast_set ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:52:29 -04:00
static ssize_t libertas_autostart_enabled_get ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct cmd_ds_mesh_access mesh_access ;
memset ( & mesh_access , 0 , sizeof ( mesh_access ) ) ;
libertas_prepare_and_send_command ( to_net_dev ( dev ) - > priv ,
CMD_MESH_ACCESS ,
CMD_ACT_MESH_GET_AUTOSTART_ENABLED ,
CMD_OPTION_WAITFORRSP , 0 , ( void * ) & mesh_access ) ;
return sprintf ( buf , " %d \n " , le32_to_cpu ( mesh_access . data [ 0 ] ) ) ;
}
static ssize_t libertas_autostart_enabled_set ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct cmd_ds_mesh_access mesh_access ;
uint32_t datum ;
2007-08-02 13:16:02 -04:00
wlan_private * priv = ( to_net_dev ( dev ) ) - > priv ;
int ret ;
2007-08-02 11:52:29 -04:00
memset ( & mesh_access , 0 , sizeof ( mesh_access ) ) ;
sscanf ( buf , " %d " , & datum ) ;
mesh_access . data [ 0 ] = cpu_to_le32 ( datum ) ;
2007-08-02 13:16:02 -04:00
ret = libertas_prepare_and_send_command ( priv ,
2007-08-02 11:52:29 -04:00
CMD_MESH_ACCESS ,
CMD_ACT_MESH_SET_AUTOSTART_ENABLED ,
CMD_OPTION_WAITFORRSP , 0 , ( void * ) & mesh_access ) ;
2007-08-02 13:16:02 -04:00
if ( ret = = 0 )
priv - > mesh_autostart_enabled = datum ? 1 : 0 ;
2007-08-02 11:52:29 -04:00
return strlen ( buf ) ;
}
static DEVICE_ATTR ( autostart_enabled , 0644 ,
libertas_autostart_enabled_get , libertas_autostart_enabled_set ) ;
static struct attribute * libertas_mesh_sysfs_entries [ ] = {
& dev_attr_anycast_mask . attr ,
& dev_attr_autostart_enabled . attr ,
NULL ,
} ;
static struct attribute_group libertas_mesh_attr_group = {
. attrs = libertas_mesh_sysfs_entries ,
} ;
2007-02-10 12:25:27 -02:00
/**
* @ brief Check if the device can be open and wait if necessary .
*
* @ param dev A pointer to net_device structure
* @ return 0
*
* For USB adapter , on some systems the device open handler will be
* called before FW ready . Use the following flag check and wait
* function to work around the issue .
*
*/
2007-05-25 11:27:16 -04:00
static int pre_open_check ( struct net_device * dev )
{
2007-02-10 12:25:27 -02:00
wlan_private * priv = ( wlan_private * ) dev - > priv ;
wlan_adapter * adapter = priv - > adapter ;
int i = 0 ;
while ( ! adapter - > fw_ready & & i < 20 ) {
i + + ;
msleep_interruptible ( 100 ) ;
}
if ( ! adapter - > fw_ready ) {
2007-05-25 11:27:16 -04:00
lbs_pr_err ( " firmware not ready \n " ) ;
2007-02-10 12:25:27 -02:00
return - 1 ;
}
return 0 ;
}
/**
* @ brief This function opens the device
*
* @ param dev A pointer to net_device structure
* @ return 0
*/
2007-08-02 11:39:19 -04:00
static int libertas_dev_open ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
wlan_private * priv = ( wlan_private * ) dev - > priv ;
wlan_adapter * adapter = priv - > adapter ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-02-10 12:25:27 -02:00
priv - > open = 1 ;
2007-08-02 11:31:18 -04:00
if ( adapter - > connect_status = = LIBERTAS_CONNECTED ) {
2007-05-25 13:05:16 -04:00
netif_carrier_on ( priv - > dev ) ;
2007-08-02 11:50:12 -04:00
if ( priv - > mesh_dev )
netif_carrier_on ( priv - > mesh_dev ) ;
2007-05-25 12:06:56 -04:00
} else {
2007-05-25 13:05:16 -04:00
netif_carrier_off ( priv - > dev ) ;
2007-08-02 11:50:12 -04:00
if ( priv - > mesh_dev )
netif_carrier_off ( priv - > mesh_dev ) ;
2007-05-25 12:06:56 -04:00
}
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
return 0 ;
}
/**
* @ brief This function opens the mshX interface
*
* @ param dev A pointer to net_device structure
* @ return 0
*/
2007-08-02 11:39:19 -04:00
static int libertas_mesh_open ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
wlan_private * priv = ( wlan_private * ) dev - > priv ;
2007-05-25 11:49:19 -04:00
if ( pre_open_check ( dev ) = = - 1 )
2007-02-10 12:25:27 -02:00
return - 1 ;
priv - > mesh_open = 1 ;
2007-05-25 12:06:56 -04:00
netif_wake_queue ( priv - > mesh_dev ) ;
2007-02-10 12:25:27 -02:00
if ( priv - > infra_open = = 0 )
2007-08-02 11:39:19 -04:00
return libertas_dev_open ( priv - > dev ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
/**
* @ brief This function opens the ethX interface
*
* @ param dev A pointer to net_device structure
* @ return 0
*/
2007-08-02 11:39:19 -04:00
static int libertas_open ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
wlan_private * priv = ( wlan_private * ) dev - > priv ;
if ( pre_open_check ( dev ) = = - 1 )
return - 1 ;
priv - > infra_open = 1 ;
2007-05-25 13:05:16 -04:00
netif_wake_queue ( priv - > dev ) ;
2007-02-10 12:25:27 -02:00
if ( priv - > open = = 0 )
2007-08-02 11:39:19 -04:00
return libertas_dev_open ( priv - > dev ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-08-02 11:39:19 -04:00
static int libertas_dev_close ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
wlan_private * priv = dev - > priv ;
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 13:05:16 -04:00
netif_carrier_off ( priv - > dev ) ;
2007-02-10 12:25:27 -02:00
priv - > open = 0 ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_NET ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
/**
* @ brief This function closes the mshX interface
*
* @ param dev A pointer to net_device structure
* @ return 0
*/
2007-08-02 11:39:19 -04:00
static int libertas_mesh_close ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
wlan_private * priv = ( wlan_private * ) ( dev - > priv ) ;
priv - > mesh_open = 0 ;
netif_stop_queue ( priv - > mesh_dev ) ;
if ( priv - > infra_open = = 0 )
2007-08-02 11:39:19 -04:00
return libertas_dev_close ( dev ) ;
2007-02-10 12:25:27 -02:00
else
return 0 ;
}
/**
* @ brief This function closes the ethX interface
*
* @ param dev A pointer to net_device structure
* @ return 0
*/
2007-08-02 11:39:19 -04:00
static int libertas_close ( struct net_device * dev )
2007-05-25 11:49:19 -04:00
{
2007-02-10 12:25:27 -02:00
wlan_private * priv = ( wlan_private * ) dev - > priv ;
2007-05-25 13:05:16 -04:00
netif_stop_queue ( dev ) ;
2007-02-10 12:25:27 -02:00
priv - > infra_open = 0 ;
if ( priv - > mesh_open = = 0 )
2007-08-02 11:39:19 -04:00
return libertas_dev_close ( dev ) ;
2007-02-10 12:25:27 -02:00
else
return 0 ;
}
2007-08-02 11:39:19 -04:00
static int libertas_hard_start_xmit ( struct sk_buff * skb , struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
int ret = 0 ;
wlan_private * priv = dev - > priv ;
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 13:05:16 -04:00
if ( priv - > dnld_sent | | priv - > adapter - > TxLockFlag ) {
2007-02-10 12:25:27 -02:00
priv - > stats . tx_dropped + + ;
goto done ;
}
2007-05-25 13:05:16 -04:00
netif_stop_queue ( priv - > dev ) ;
2007-08-02 11:50:12 -04:00
if ( priv - > mesh_dev )
netif_stop_queue ( priv - > mesh_dev ) ;
2007-02-10 12:25:27 -02:00
if ( libertas_process_tx ( priv , skb ) = = 0 )
dev - > trans_start = jiffies ;
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-08-02 11:39:19 -04:00
* @ brief Mark mesh packets and handover them to libertas_hard_start_xmit
2007-02-10 12:25:27 -02:00
*
*/
2007-08-02 11:39:19 -04:00
static int libertas_mesh_pre_start_xmit ( struct sk_buff * skb ,
struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
wlan_private * priv = dev - > priv ;
2007-05-25 11:27:16 -04:00
int ret ;
lbs_deb_enter ( LBS_DEB_MESH ) ;
2007-08-02 13:16:55 -04:00
if ( priv - > adapter - > monitormode ! = WLAN_MONITOR_OFF ) {
netif_stop_queue ( dev ) ;
return - EOPNOTSUPP ;
}
2007-05-25 11:27:16 -04:00
2007-02-10 12:25:27 -02:00
SET_MESH_FRAME ( skb ) ;
2007-08-02 11:39:19 -04:00
ret = libertas_hard_start_xmit ( skb , priv - > dev ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_MESH , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
/**
2007-08-02 11:39:19 -04:00
* @ brief Mark non - mesh packets and handover them to libertas_hard_start_xmit
2007-02-10 12:25:27 -02:00
*
*/
2007-08-02 11:39:19 -04:00
static int libertas_pre_start_xmit ( struct sk_buff * skb , struct net_device * dev )
2007-05-25 11:27:16 -04:00
{
2007-08-02 13:16:55 -04:00
wlan_private * priv = dev - > priv ;
2007-05-25 11:27:16 -04:00
int ret ;
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-08-02 13:16:55 -04:00
if ( priv - > adapter - > monitormode ! = WLAN_MONITOR_OFF ) {
netif_stop_queue ( dev ) ;
return - EOPNOTSUPP ;
}
2007-02-10 12:25:27 -02:00
UNSET_MESH_FRAME ( skb ) ;
2007-05-25 11:27:16 -04:00
2007-08-02 11:39:19 -04:00
ret = libertas_hard_start_xmit ( skb , dev ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_NET , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
2007-08-02 11:39:19 -04:00
static void libertas_tx_timeout ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
wlan_private * priv = ( wlan_private * ) dev - > priv ;
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
2007-05-25 13:05:16 -04:00
priv - > dnld_sent = DNLD_RES_RECEIVED ;
2007-02-10 12:25:27 -02:00
dev - > trans_start = jiffies ;
if ( priv - > adapter - > currenttxskb ) {
2007-08-02 13:16:55 -04:00
if ( priv - > adapter - > monitormode ! = WLAN_MONITOR_OFF ) {
2007-02-10 12:25:27 -02:00
/* If we are here, we have not received feedback from
the previous packet . Assume TX_FAIL and move on . */
priv - > adapter - > eventcause = 0x01000000 ;
libertas_send_tx_feedback ( priv ) ;
} else
2007-08-02 11:32:25 -04:00
wake_up_interruptible ( & priv - > waitq ) ;
2007-08-02 11:31:18 -04:00
} else if ( priv - > adapter - > connect_status = = LIBERTAS_CONNECTED ) {
2007-05-25 13:05:16 -04:00
netif_wake_queue ( priv - > dev ) ;
2007-08-02 11:50:12 -04:00
if ( priv - > mesh_dev )
netif_wake_queue ( priv - > mesh_dev ) ;
2007-05-25 12:06:56 -04:00
}
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_TX ) ;
2007-02-10 12:25:27 -02:00
}
/**
* @ brief This function returns the network statistics
*
* @ param dev A pointer to wlan_private structure
* @ return A pointer to net_device_stats structure
*/
2007-08-02 11:39:19 -04:00
static struct net_device_stats * libertas_get_stats ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
wlan_private * priv = ( wlan_private * ) dev - > priv ;
return & priv - > stats ;
}
2007-08-02 11:39:19 -04:00
static int libertas_set_mac_address ( struct net_device * dev , void * addr )
2007-02-10 12:25:27 -02:00
{
int ret = 0 ;
wlan_private * priv = ( wlan_private * ) dev - > priv ;
wlan_adapter * adapter = priv - > adapter ;
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-02-10 12:25:27 -02:00
memset ( adapter - > current_addr , 0 , ETH_ALEN ) ;
/* 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-02-10 12:25:27 -02:00
memcpy ( adapter - > current_addr , phwaddr - > sa_data , ETH_ALEN ) ;
2007-08-02 11:31:18 -04:00
ret = libertas_prepare_and_send_command ( priv , CMD_802_11_MAC_ADDRESS ,
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-08-02 11:53:06 -04:00
lbs_deb_hex ( LBS_DEB_NET , " adapter->macaddr " , adapter - > current_addr , ETH_ALEN ) ;
2007-02-10 12:25:27 -02:00
memcpy ( dev - > dev_addr , adapter - > current_addr , ETH_ALEN ) ;
2007-05-25 11:49:19 -04:00
if ( priv - > mesh_dev )
memcpy ( priv - > mesh_dev - > dev_addr , adapter - > 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-08-02 11:39:19 -04:00
static int libertas_copy_multicast_address ( wlan_adapter * adapter ,
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 + + ) {
memcpy ( & adapter - > multicastlist [ i ] , mcptr - > dmi_addr , ETH_ALEN ) ;
mcptr = mcptr - > next ;
}
return i ;
}
2007-08-02 11:39:19 -04:00
static void libertas_set_multicast_list ( struct net_device * dev )
2007-02-10 12:25:27 -02:00
{
wlan_private * priv = dev - > priv ;
wlan_adapter * adapter = priv - > adapter ;
int oldpacketfilter ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-02-10 12:25:27 -02:00
oldpacketfilter = adapter - > currentpacketfilter ;
if ( dev - > flags & IFF_PROMISC ) {
2007-05-25 11:27:16 -04:00
lbs_deb_net ( " enable promiscuous mode \n " ) ;
2007-02-10 12:25:27 -02:00
adapter - > currentpacketfilter | =
2007-08-02 11:31:18 -04:00
CMD_ACT_MAC_PROMISCUOUS_ENABLE ;
2007-02-10 12:25:27 -02:00
adapter - > 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 */
adapter - > 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-02-10 12:25:27 -02:00
adapter - > currentpacketfilter | =
2007-08-02 11:31:18 -04:00
CMD_ACT_MAC_ALL_MULTICAST_ENABLE ;
2007-02-10 12:25:27 -02:00
adapter - > currentpacketfilter & =
2007-08-02 11:31:18 -04:00
~ CMD_ACT_MAC_MULTICAST_ENABLE ;
2007-02-10 12:25:27 -02:00
} else {
adapter - > 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-02-10 12:25:27 -02:00
adapter - > 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 ;
adapter - > currentpacketfilter | =
2007-08-02 11:31:18 -04:00
CMD_ACT_MAC_MULTICAST_ENABLE ;
2007-02-10 12:25:27 -02:00
adapter - > nr_of_multicastmacaddr =
2007-08-02 11:39:19 -04:00
libertas_copy_multicast_address ( adapter , 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 + + ) {
2007-05-25 11:27:16 -04:00
lbs_deb_net ( " Multicast address %d: "
MAC_FMT " \n " , i ,
2007-02-10 12:25:27 -02:00
adapter - > multicastlist [ i ] [ 0 ] ,
adapter - > multicastlist [ i ] [ 1 ] ,
adapter - > multicastlist [ i ] [ 2 ] ,
adapter - > multicastlist [ i ] [ 3 ] ,
adapter - > multicastlist [ i ] [ 4 ] ,
adapter - > multicastlist [ i ] [ 5 ] ) ;
}
2007-05-25 11:27:16 -04:00
/* send multicast addresses to firmware */
2007-02-10 12:25:27 -02:00
libertas_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 ) ;
}
}
}
if ( adapter - > currentpacketfilter ! = oldpacketfilter ) {
libertas_set_mac_packet_filter ( priv ) ;
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_NET ) ;
2007-02-10 12:25:27 -02:00
}
/**
2007-05-25 11:27:16 -04:00
* @ brief This function handles the major jobs in the WLAN driver .
* 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
*
* @ param data A pointer to wlan_thread structure
* @ return 0
*/
2007-08-02 11:32:25 -04:00
static int libertas_thread ( void * data )
2007-02-10 12:25:27 -02:00
{
2007-08-02 11:32:25 -04:00
struct net_device * dev = data ;
wlan_private * priv = dev - > priv ;
2007-02-10 12:25:27 -02:00
wlan_adapter * adapter = priv - > adapter ;
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 ) ;
2007-08-20 11:10:45 -04:00
set_freezable ( ) ;
2007-02-10 12:25:27 -02:00
for ( ; ; ) {
2007-05-25 11:27:16 -04:00
lbs_deb_thread ( " main-thread 111: intcounter=%d "
2007-02-10 12:25:27 -02:00
" currenttxskb=%p dnld_sent=%d \n " ,
adapter - > intcounter ,
2007-05-25 13:05:16 -04:00
adapter - > 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 ) ;
spin_lock_irq ( & adapter - > driver_lock ) ;
if ( ( adapter - > psstate = = PS_STATE_SLEEP ) | |
( ! adapter - > intcounter
2007-05-25 13:05:16 -04:00
& & ( priv - > dnld_sent | | adapter - > cur_cmd | |
2007-02-10 12:25:27 -02:00
list_empty ( & adapter - > cmdpendingq ) ) ) ) {
2007-05-25 11:27:16 -04:00
lbs_deb_thread (
2007-02-10 12:25:27 -02:00
" main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d \n " ,
adapter - > connect_status , adapter - > intcounter ,
adapter - > psmode , adapter - > psstate ) ;
spin_unlock_irq ( & adapter - > driver_lock ) ;
schedule ( ) ;
} else
spin_unlock_irq ( & adapter - > driver_lock ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_thread (
2007-02-10 12:25:27 -02:00
" main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
" dnld_sent=%d \n " , adapter - > intcounter ,
2007-05-25 13:05:16 -04:00
adapter - > 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
try_to_freeze ( ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_thread ( " main-thread 333: intcounter=%d currenttxskb=%p "
2007-02-10 12:25:27 -02:00
" dnld_sent=%d \n " ,
adapter - > intcounter ,
2007-05-25 13:05:16 -04:00
adapter - > currenttxskb , priv - > dnld_sent ) ;
2007-02-10 12:25:27 -02:00
if ( kthread_should_stop ( )
| | adapter - > surpriseremoved ) {
2007-05-25 11:27:16 -04:00
lbs_deb_thread (
2007-02-10 12:25:27 -02:00
" main-thread: break from main thread: surpriseremoved=0x%x \n " ,
adapter - > surpriseremoved ) ;
break ;
}
spin_lock_irq ( & adapter - > driver_lock ) ;
if ( adapter - > intcounter ) {
u8 int_status ;
adapter - > 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-05-25 11:27:16 -04:00
lbs_deb_thread (
2007-02-10 12:25:27 -02:00
" main-thread: reading HOST_INT_STATUS_REG failed \n " ) ;
spin_unlock_irq ( & adapter - > driver_lock ) ;
continue ;
}
adapter - > hisregcpy | = ireg ;
}
2007-05-25 11:27:16 -04:00
lbs_deb_thread ( " main-thread 444: intcounter=%d currenttxskb=%p "
2007-02-10 12:25:27 -02:00
" dnld_sent=%d \n " ,
adapter - > intcounter ,
2007-05-25 13:05:16 -04:00
adapter - > currenttxskb , priv - > dnld_sent ) ;
2007-02-10 12:25:27 -02:00
/* command response? */
2007-08-02 11:49:45 -04:00
if ( adapter - > 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-08-02 11:49:45 -04:00
adapter - > hisregcpy & = ~ MRVDRV_CMD_UPLD_RDY ;
2007-02-10 12:25:27 -02:00
spin_unlock_irq ( & adapter - > driver_lock ) ;
libertas_process_rx_command ( priv ) ;
spin_lock_irq ( & adapter - > driver_lock ) ;
}
/* Any Card Event */
2007-08-02 11:49:45 -04:00
if ( adapter - > 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-08-02 11:49:45 -04:00
adapter - > 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-02-10 12:25:27 -02:00
lbs_pr_alert (
2007-05-25 12:17:06 -04:00
" main-thread: hw_read_event_cause failed \n " ) ;
2007-02-10 12:25:27 -02:00
spin_unlock_irq ( & adapter - > driver_lock ) ;
continue ;
}
spin_unlock_irq ( & adapter - > driver_lock ) ;
libertas_process_event ( priv ) ;
} else
spin_unlock_irq ( & adapter - > driver_lock ) ;
/* Check if we need to confirm Sleep Request received previously */
if ( adapter - > psstate = = PS_STATE_PRE_SLEEP ) {
2007-05-25 13:05:16 -04:00
if ( ! priv - > dnld_sent & & ! adapter - > cur_cmd ) {
2007-02-10 12:25:27 -02:00
if ( adapter - > connect_status = =
2007-08-02 11:31:18 -04:00
LIBERTAS_CONNECTED ) {
2007-05-25 11:27:16 -04:00
lbs_deb_thread (
2007-02-10 12:25:27 -02:00
" main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
" dnld_sent=%d cur_cmd=%p, confirm now \n " ,
adapter - > intcounter ,
adapter - > currenttxskb ,
2007-05-25 13:05:16 -04:00
priv - > dnld_sent ,
2007-02-10 12:25:27 -02:00
adapter - > cur_cmd ) ;
libertas_ps_confirm_sleep ( priv ,
( u16 ) adapter - > psmode ) ;
} else {
/* workaround for firmware sending
* deauth / linkloss event immediately
* after sleep request , remove this
* after firmware fixes it
*/
adapter - > psstate = PS_STATE_AWAKE ;
lbs_pr_alert (
" main-thread: ignore PS_SleepConfirm in non-connected state \n " ) ;
}
}
}
/* The PS state is changed during processing of Sleep Request
* event above
*/
if ( ( priv - > adapter - > psstate = = PS_STATE_SLEEP ) | |
( priv - > adapter - > psstate = = PS_STATE_PRE_SLEEP ) )
continue ;
/* Execute the next command */
2007-05-25 13:05:16 -04:00
if ( ! priv - > dnld_sent & & ! priv - > adapter - > cur_cmd )
2007-02-10 12:25:27 -02:00
libertas_execute_next_command ( priv ) ;
/* Wake-up command waiters which can't sleep in
* libertas_prepare_and_send_command
*/
if ( ! adapter - > nr_cmd_pending )
wake_up_all ( & adapter - > cmd_pending ) ;
libertas_tx_runqueue ( priv ) ;
}
del_timer ( & adapter - > command_timer ) ;
adapter - > nr_cmd_pending = 0 ;
wake_up_all ( & adapter - > cmd_pending ) ;
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-08-02 11:45:12 -04:00
/**
* @ brief This function downloads firmware image , gets
* HW spec from firmware and set basic parameters to
* firmware .
*
* @ param priv A pointer to wlan_private structure
* @ return 0 or - 1
*/
2007-08-20 11:43:25 -04:00
static int wlan_setup_firmware ( wlan_private * priv )
2007-08-02 11:45:12 -04:00
{
int ret = - 1 ;
wlan_adapter * adapter = priv - > adapter ;
2007-08-02 13:16:02 -04:00
struct cmd_ds_mesh_access mesh_access ;
2007-08-02 11:45:12 -04:00
lbs_deb_enter ( LBS_DEB_FW ) ;
/*
* Read MAC address from HW
*/
memset ( adapter - > current_addr , 0xff , ETH_ALEN ) ;
ret = libertas_prepare_and_send_command ( priv , CMD_GET_HW_SPEC ,
0 , CMD_OPTION_WAITFORRSP , 0 , NULL ) ;
if ( ret ) {
ret = - 1 ;
goto done ;
}
libertas_set_mac_packet_filter ( priv ) ;
/* Get the supported Data rates */
ret = libertas_prepare_and_send_command ( priv , CMD_802_11_DATA_RATE ,
CMD_ACT_GET_TX_RATE ,
CMD_OPTION_WAITFORRSP , 0 , NULL ) ;
if ( ret ) {
ret = - 1 ;
goto done ;
}
2007-08-02 13:16:02 -04:00
/* Disable mesh autostart */
if ( priv - > mesh_dev ) {
memset ( & mesh_access , 0 , sizeof ( mesh_access ) ) ;
mesh_access . data [ 0 ] = cpu_to_le32 ( 0 ) ;
ret = libertas_prepare_and_send_command ( priv ,
CMD_MESH_ACCESS ,
CMD_ACT_MESH_SET_AUTOSTART_ENABLED ,
CMD_OPTION_WAITFORRSP , 0 , ( void * ) & mesh_access ) ;
if ( ret ) {
ret = - 1 ;
goto done ;
}
priv - > mesh_autostart_enabled = 0 ;
}
2007-08-02 13:19:24 -04:00
/* Set the boot2 version in firmware */
ret = libertas_prepare_and_send_command ( priv , CMD_SET_BOOT2_VER ,
0 , CMD_OPTION_WAITFORRSP , 0 , NULL ) ;
2007-08-02 11:45:12 -04:00
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 )
{
wlan_private * priv = ( wlan_private * ) data ;
wlan_adapter * adapter = priv - > adapter ;
struct cmd_ctrl_node * ptempnode ;
struct cmd_ds_command * cmd ;
unsigned long flags ;
ptempnode = adapter - > cur_cmd ;
if ( ptempnode = = NULL ) {
lbs_deb_fw ( " ptempnode empty \n " ) ;
return ;
}
cmd = ( struct cmd_ds_command * ) ptempnode - > bufvirtualaddr ;
if ( ! cmd ) {
lbs_deb_fw ( " cmd is NULL \n " ) ;
return ;
}
lbs_deb_fw ( " command_timer_fn fired, cmd %x \n " , cmd - > command ) ;
if ( ! adapter - > fw_ready )
return ;
spin_lock_irqsave ( & adapter - > driver_lock , flags ) ;
adapter - > cur_cmd = NULL ;
spin_unlock_irqrestore ( & adapter - > driver_lock , flags ) ;
lbs_deb_fw ( " re-sending same command because of timeout \n " ) ;
libertas_queue_cmd ( adapter , ptempnode , 0 ) ;
wake_up_interruptible ( & priv - > waitq ) ;
return ;
}
2007-08-20 11:43:25 -04:00
static int libertas_init_adapter ( wlan_private * priv )
2007-08-02 11:49:06 -04:00
{
wlan_adapter * adapter = priv - > adapter ;
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
/* Allocate buffer to store the BSSID list */
bufsize = MAX_NETWORK_COUNT * sizeof ( struct bss_descriptor ) ;
adapter - > networks = kzalloc ( bufsize , GFP_KERNEL ) ;
if ( ! adapter - > networks ) {
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 */
INIT_LIST_HEAD ( & adapter - > network_free_list ) ;
INIT_LIST_HEAD ( & adapter - > network_list ) ;
for ( i = 0 ; i < MAX_NETWORK_COUNT ; i + + ) {
list_add_tail ( & adapter - > networks [ i ] . list ,
& adapter - > network_free_list ) ;
}
2007-08-02 11:45:12 -04:00
adapter - > libertas_ps_confirm_sleep . seqnum = cpu_to_le16 ( + + adapter - > seqnum ) ;
adapter - > libertas_ps_confirm_sleep . command =
cpu_to_le16 ( CMD_802_11_PS_MODE ) ;
adapter - > libertas_ps_confirm_sleep . size =
cpu_to_le16 ( sizeof ( struct PS_CMD_ConfirmSleep ) ) ;
adapter - > libertas_ps_confirm_sleep . action =
cpu_to_le16 ( CMD_SUBCMD_SLEEP_CONFIRMED ) ;
memset ( adapter - > current_addr , 0xff , ETH_ALEN ) ;
2007-08-20 11:43:25 -04:00
adapter - > connect_status = LIBERTAS_DISCONNECTED ;
2007-08-02 11:45:12 -04:00
adapter - > secinfo . auth_mode = IW_AUTH_ALG_OPEN_SYSTEM ;
adapter - > mode = IW_MODE_INFRA ;
adapter - > curbssparams . channel = DEFAULT_AD_HOC_CHANNEL ;
2007-08-20 11:43:25 -04:00
adapter - > currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON ;
2007-08-02 11:45:12 -04:00
adapter - > radioon = RADIO_ON ;
adapter - > auto_rate = 1 ;
adapter - > capability = WLAN_CAPABILITY_SHORT_PREAMBLE ;
adapter - > psmode = WLAN802_11POWERMODECAM ;
adapter - > psstate = PS_STATE_FULL_POWER ;
2007-08-20 11:43:25 -04:00
mutex_init ( & adapter - > lock ) ;
2007-08-02 11:45:12 -04:00
memset ( & adapter - > tx_queue_ps , 0 , NR_TX_QUEUE * sizeof ( struct sk_buff * ) ) ;
adapter - > tx_queue_idx = 0 ;
spin_lock_init ( & adapter - > txqueue_lock ) ;
2007-08-20 11:43:25 -04:00
setup_timer ( & adapter - > command_timer , command_timer_fn ,
( unsigned long ) priv ) ;
2007-08-02 11:45:12 -04:00
2007-08-20 11:43:25 -04:00
INIT_LIST_HEAD ( & adapter - > cmdfreeq ) ;
INIT_LIST_HEAD ( & adapter - > cmdpendingq ) ;
2007-08-02 11:45:12 -04:00
2007-08-20 11:43:25 -04:00
spin_lock_init ( & adapter - > driver_lock ) ;
init_waitqueue_head ( & adapter - > cmd_pending ) ;
adapter - > nr_cmd_pending = 0 ;
2007-08-02 11:45:12 -04:00
2007-08-20 11:43:25 -04:00
/* Allocate the command buffers */
if ( libertas_allocate_cmd_buffer ( priv ) ) {
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 :
return ret ;
}
2007-08-02 11:45:12 -04:00
2007-08-20 11:43:25 -04:00
static void libertas_free_adapter ( wlan_private * priv )
{
wlan_adapter * adapter = priv - > adapter ;
2007-08-02 11:45:12 -04:00
2007-08-20 11:43:25 -04:00
if ( ! adapter ) {
lbs_deb_fw ( " why double free adapter? \n " ) ;
return ;
2007-08-02 11:45:12 -04:00
}
2007-08-20 11:43:25 -04:00
lbs_deb_fw ( " free command buffer \n " ) ;
libertas_free_cmd_buffer ( priv ) ;
2007-08-02 11:45:12 -04:00
2007-08-20 11:43:25 -04:00
lbs_deb_fw ( " free command_timer \n " ) ;
del_timer ( & adapter - > command_timer ) ;
lbs_deb_fw ( " free scan results table \n " ) ;
kfree ( adapter - > networks ) ;
adapter - > networks = NULL ;
/* Free the adapter object itself */
lbs_deb_fw ( " free adapter \n " ) ;
kfree ( adapter ) ;
priv - > adapter = NULL ;
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
* card , allocate the wlan_priv and initialize the device .
*
* @ param card A pointer to card
* @ return A pointer to wlan_private structure
*/
2007-05-25 13:13:25 -04:00
wlan_private * libertas_add_card ( void * card , struct device * dmdev )
2007-02-10 12:25:27 -02:00
{
struct net_device * dev = NULL ;
wlan_private * priv = NULL ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_NET ) ;
2007-02-10 12:25:27 -02:00
/* Allocate an Ethernet device and register it */
if ( ! ( dev = alloc_etherdev ( sizeof ( wlan_private ) ) ) ) {
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
/* allocate buffer for wlan_adapter */
2007-05-25 11:58:22 -04:00
if ( ! ( priv - > adapter = kzalloc ( sizeof ( wlan_adapter ) , GFP_KERNEL ) ) ) {
2007-05-25 11:27:16 -04:00
lbs_pr_err ( " allocate buffer for wlan_adapter failed \n " ) ;
2007-05-25 11:58:22 -04:00
goto err_kzalloc ;
2007-02-10 12:25:27 -02:00
}
2007-08-20 11:43:25 -04:00
if ( libertas_init_adapter ( priv ) ) {
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 ;
2007-08-20 11:43:25 -04:00
priv - > hotplug_device = dmdev ;
2007-02-10 12:25:27 -02:00
/* Setup the OS Interface to our functions */
2007-08-02 11:39:19 -04:00
dev - > open = libertas_open ;
dev - > hard_start_xmit = libertas_pre_start_xmit ;
dev - > stop = libertas_close ;
dev - > set_mac_address = libertas_set_mac_address ;
dev - > tx_timeout = libertas_tx_timeout ;
dev - > get_stats = libertas_get_stats ;
2007-05-25 11:58:22 -04:00
dev - > watchdog_timeo = 5 * HZ ;
2007-02-10 12:25:27 -02:00
dev - > ethtool_ops = & libertas_ethtool_ops ;
# ifdef WIRELESS_EXT
dev - > wireless_handlers = ( struct iw_handler_def * ) & libertas_handler_def ;
# endif
# define NETIF_F_DYNALLOC 16
dev - > features | = NETIF_F_DYNALLOC ;
dev - > flags | = IFF_BROADCAST | IFF_MULTICAST ;
2007-08-02 11:39:19 -04:00
dev - > set_multicast_list = libertas_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 ;
if ( device_create_file ( dmdev , & dev_attr_libertas_rtap ) )
2007-08-20 11:43:25 -04:00
goto err_init_adapter ;
lbs_deb_thread ( " Starting main thread... \n " ) ;
init_waitqueue_head ( & priv - > waitq ) ;
priv - > main_thread = kthread_run ( libertas_thread , dev , " libertas_main " ) ;
if ( IS_ERR ( priv - > main_thread ) ) {
lbs_deb_thread ( " Error creating main thread. \n " ) ;
goto err_kthread_run ;
}
priv - > work_thread = create_singlethread_workqueue ( " libertas_worker " ) ;
INIT_DELAYED_WORK ( & priv - > assoc_work , libertas_association_worker ) ;
INIT_DELAYED_WORK ( & priv - > scan_work , libertas_scan_worker ) ;
INIT_WORK ( & priv - > sync_channel , libertas_sync_channel ) ;
2007-05-25 12:04:31 -04:00
goto done ;
2007-08-20 11:43:25 -04:00
err_kthread_run :
device_remove_file ( dmdev , & dev_attr_libertas_rtap ) ;
err_init_adapter :
libertas_free_adapter ( priv ) ;
2007-05-25 12:04:31 -04:00
err_kzalloc :
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 :
lbs_deb_leave_args ( LBS_DEB_NET , " priv %p " , priv ) ;
return priv ;
}
2007-05-25 12:37:58 -04:00
EXPORT_SYMBOL_GPL ( libertas_add_card ) ;
2007-05-25 12:04:31 -04:00
2007-08-20 11:43:25 -04:00
int libertas_remove_card ( wlan_private * priv )
2007-05-25 12:04:31 -04:00
{
2007-08-20 11:43:25 -04:00
wlan_adapter * adapter = priv - > adapter ;
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-08-20 11:43:25 -04:00
libertas_remove_rtap ( priv ) ;
2007-02-10 12:25:27 -02:00
2007-08-20 11:43:25 -04:00
dev = priv - > dev ;
device_remove_file ( priv - > hotplug_device , & dev_attr_libertas_rtap ) ;
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-08-20 11:43:25 -04:00
if ( adapter - > psmode = = WLAN802_11POWERMODEMAX_PSP ) {
adapter - > psmode = WLAN802_11POWERMODECAM ;
libertas_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 */
adapter - > surpriseremoved = 1 ;
kthread_stop ( priv - > main_thread ) ;
libertas_free_adapter ( priv ) ;
priv - > dev = NULL ;
free_netdev ( dev ) ;
lbs_deb_leave ( LBS_DEB_MAIN ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( libertas_remove_card ) ;
int libertas_start_card ( wlan_private * priv )
{
struct net_device * dev = priv - > dev ;
int ret = - 1 ;
lbs_deb_enter ( LBS_DEB_MAIN ) ;
/* poke the firmware */
ret = wlan_setup_firmware ( priv ) ;
if ( ret )
goto done ;
/* init 802.11d */
libertas_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
}
libertas_debugfs_init_one ( priv , dev ) ;
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 ;
}
EXPORT_SYMBOL_GPL ( libertas_start_card ) ;
int libertas_stop_card ( wlan_private * priv )
{
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 ) ;
libertas_debugfs_remove_one ( priv ) ;
/* Flush pending command nodes */
spin_lock_irqsave ( & priv - > adapter - > driver_lock , flags ) ;
list_for_each_entry ( cmdnode , & priv - > adapter - > cmdpendingq , list ) {
cmdnode - > cmdwaitqwoken = 1 ;
wake_up_interruptible ( & cmdnode - > cmdwait_q ) ;
}
spin_unlock_irqrestore ( & priv - > adapter - > driver_lock , flags ) ;
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-08-20 11:43:25 -04:00
EXPORT_SYMBOL_GPL ( libertas_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
*
* @ param priv A pointer to the wlan_private structure
* @ return 0 if successful , - X otherwise
*/
2007-05-25 13:13:25 -04:00
int libertas_add_mesh ( wlan_private * priv , struct device * dev )
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-08-02 11:39:19 -04:00
mesh_dev - > open = libertas_mesh_open ;
mesh_dev - > hard_start_xmit = libertas_mesh_pre_start_xmit ;
mesh_dev - > stop = libertas_mesh_close ;
mesh_dev - > get_stats = libertas_get_stats ;
mesh_dev - > set_mac_address = libertas_set_mac_address ;
2007-05-25 11:49:19 -04:00
mesh_dev - > ethtool_ops = & libertas_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-05-25 13:13:25 -04:00
SET_NETDEV_DEV ( priv - > mesh_dev , dev ) ;
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
# define NETIF_F_DYNALLOC 16
/* Register virtual mesh interface */
ret = register_netdev ( mesh_dev ) ;
if ( ret ) {
lbs_pr_err ( " cannot register mshX virtual interface \n " ) ;
goto err_free ;
}
2007-08-02 11:52:29 -04:00
ret = sysfs_create_group ( & ( mesh_dev - > dev . kobj ) , & libertas_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
EXPORT_SYMBOL_GPL ( libertas_add_mesh ) ;
2007-05-25 11:49:19 -04:00
2007-05-25 12:37:58 -04:00
void libertas_remove_mesh ( wlan_private * priv )
2007-05-25 11:49:19 -04:00
{
struct net_device * mesh_dev ;
2007-08-20 11:43:25 -04:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-05-25 11:49:19 -04:00
if ( ! priv )
goto out ;
mesh_dev = priv - > mesh_dev ;
netif_stop_queue ( mesh_dev ) ;
2007-05-25 12:06:56 -04:00
netif_carrier_off ( priv - > mesh_dev ) ;
2007-05-25 11:49:19 -04:00
2007-08-02 11:52:29 -04:00
sysfs_remove_group ( & ( mesh_dev - > dev . kobj ) , & libertas_mesh_attr_group ) ;
2007-05-25 11:49:19 -04:00
unregister_netdev ( mesh_dev ) ;
priv - > mesh_dev = NULL ;
free_netdev ( mesh_dev ) ;
out :
2007-08-20 11:43:25 -04:00
lbs_deb_leave ( LBS_DEB_MAIN ) ;
2007-05-25 11:49:19 -04:00
}
2007-05-25 12:37:58 -04:00
EXPORT_SYMBOL_GPL ( libertas_remove_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
*/
struct chan_freq_power * libertas_get_region_cfp_table ( u8 region , u8 band , int * cfp_no )
{
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
end = sizeof ( region_cfp_table ) / sizeof ( struct region_cfp_table ) ;
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 ;
}
int libertas_set_regiontable ( wlan_private * priv , u8 region , u8 band )
{
wlan_adapter * adapter = priv - > adapter ;
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
memset ( adapter - > region_channel , 0 , sizeof ( adapter - > region_channel ) ) ;
{
cfp = libertas_get_region_cfp_table ( region , band , & cfp_no ) ;
if ( cfp ! = NULL ) {
adapter - > region_channel [ i ] . nrcfp = cfp_no ;
adapter - > region_channel [ i ] . CFP = cfp ;
} else {
2007-05-25 11:27:16 -04:00
lbs_deb_main ( " wrong region code %#x in band B/G \n " ,
2007-02-10 12:25:27 -02:00
region ) ;
2007-05-25 11:27:16 -04:00
ret = - 1 ;
goto out ;
2007-02-10 12:25:27 -02:00
}
adapter - > region_channel [ i ] . valid = 1 ;
adapter - > region_channel [ i ] . region = region ;
adapter - > 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
*/
void libertas_interrupt ( struct net_device * dev )
{
wlan_private * priv = dev - > priv ;
2007-05-25 11:52:42 -04:00
lbs_deb_enter ( LBS_DEB_THREAD ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:52:42 -04:00
lbs_deb_thread ( " libertas_interrupt: intcounter=%d \n " ,
2007-02-10 12:25:27 -02:00
priv - > adapter - > intcounter ) ;
priv - > adapter - > intcounter + + ;
if ( priv - > adapter - > psstate = = PS_STATE_SLEEP ) {
priv - > adapter - > psstate = PS_STATE_AWAKE ;
netif_wake_queue ( dev ) ;
2007-08-02 11:50:12 -04:00
if ( priv - > mesh_dev )
netif_wake_queue ( priv - > mesh_dev ) ;
2007-02-10 12:25:27 -02:00
}
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-05-25 12:37:58 -04:00
EXPORT_SYMBOL_GPL ( libertas_interrupt ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:36:22 -04:00
int libertas_reset_device ( wlan_private * priv )
{
int ret ;
lbs_deb_enter ( LBS_DEB_MAIN ) ;
ret = libertas_prepare_and_send_command ( priv , CMD_802_11_RESET ,
CMD_ACT_HALT , 0 , 0 , NULL ) ;
msleep_interruptible ( 10 ) ;
lbs_deb_leave_args ( LBS_DEB_MAIN , " ret %d " , ret ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( libertas_reset_device ) ;
2007-05-25 12:37:58 -04:00
static int libertas_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-02-10 12:25:27 -02:00
libertas_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-05-25 12:37:58 -04:00
static void libertas_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-02-10 12:25:27 -02:00
libertas_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
*/
static int libertas_rtap_open ( struct net_device * dev )
{
netif_carrier_off ( dev ) ;
netif_stop_queue ( dev ) ;
return 0 ;
}
static int libertas_rtap_stop ( struct net_device * dev )
{
return 0 ;
}
static int libertas_rtap_hard_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
netif_stop_queue ( dev ) ;
return - EOPNOTSUPP ;
}
static struct net_device_stats * libertas_rtap_get_stats ( struct net_device * dev )
{
wlan_private * priv = dev - > priv ;
return & priv - > ieee - > stats ;
}
void libertas_remove_rtap ( wlan_private * priv )
{
if ( priv - > rtap_net_dev = = NULL )
return ;
unregister_netdev ( priv - > rtap_net_dev ) ;
free_ieee80211 ( priv - > rtap_net_dev ) ;
priv - > rtap_net_dev = NULL ;
}
int libertas_add_rtap ( wlan_private * priv )
{
int rc = 0 ;
if ( priv - > rtap_net_dev )
return - EPERM ;
priv - > rtap_net_dev = alloc_ieee80211 ( 0 ) ;
if ( priv - > rtap_net_dev = = NULL )
return - ENOMEM ;
priv - > ieee = netdev_priv ( priv - > rtap_net_dev ) ;
strcpy ( priv - > rtap_net_dev - > name , " rtap%d " ) ;
priv - > rtap_net_dev - > type = ARPHRD_IEEE80211_RADIOTAP ;
priv - > rtap_net_dev - > open = libertas_rtap_open ;
priv - > rtap_net_dev - > stop = libertas_rtap_stop ;
priv - > rtap_net_dev - > get_stats = libertas_rtap_get_stats ;
priv - > rtap_net_dev - > hard_start_xmit = libertas_rtap_hard_start_xmit ;
priv - > rtap_net_dev - > set_multicast_list = libertas_set_multicast_list ;
priv - > rtap_net_dev - > priv = priv ;
priv - > ieee - > iw_mode = IW_MODE_MONITOR ;
rc = register_netdev ( priv - > rtap_net_dev ) ;
if ( rc ) {
free_ieee80211 ( priv - > rtap_net_dev ) ;
priv - > rtap_net_dev = NULL ;
return rc ;
}
return 0 ;
}
2007-05-25 12:37:58 -04:00
module_init ( libertas_init_module ) ;
module_exit ( libertas_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 " ) ;