2007-02-10 12:25:27 -02:00
/**
* This file contains the handling of command .
* It prepares command and sends it to firmware when it is ready .
*/
# include <net/iw_handler.h>
2008-09-24 18:13:14 -04:00
# include <net/lib80211.h>
2008-04-01 14:50:43 +02:00
# include <linux/kfifo.h>
2007-02-10 12:25:27 -02:00
# include "host.h"
# include "decl.h"
# include "defs.h"
# include "dev.h"
2008-04-02 16:27:10 +02:00
# include "assoc.h"
2007-02-10 12:25:27 -02:00
# include "wext.h"
2009-10-22 15:30:48 +02:00
# include "scan.h"
2007-12-11 12:42:16 -05:00
# include "cmd.h"
2007-02-10 12:25:27 -02:00
2007-12-11 17:44:10 -05:00
static struct cmd_ctrl_node * lbs_get_cmd_ctrl_node ( struct lbs_private * priv ) ;
2007-12-05 17:58:06 +01:00
2008-03-19 10:11:00 +01:00
/**
* @ brief Simple callback that copies response back into command
*
* @ param priv A pointer to struct lbs_private structure
* @ param extra A pointer to the original command structure for which
* ' resp ' is a response
* @ param resp A pointer to the command response
*
* @ return 0 on success , error on failure
*/
int lbs_cmd_copyback ( struct lbs_private * priv , unsigned long extra ,
struct cmd_header * resp )
{
struct cmd_header * buf = ( void * ) extra ;
uint16_t copy_len ;
copy_len = min ( le16_to_cpu ( buf - > size ) , le16_to_cpu ( resp - > size ) ) ;
memcpy ( buf , resp , copy_len ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( lbs_cmd_copyback ) ;
/**
* @ brief Simple callback that ignores the result . Use this if
* you just want to send a command to the hardware , but don ' t
* care for the result .
*
* @ param priv ignored
* @ param extra ignored
* @ param resp ignored
*
* @ return 0 for success
*/
static int lbs_cmd_async_callback ( struct lbs_private * priv , unsigned long extra ,
struct cmd_header * resp )
{
return 0 ;
}
2007-02-10 12:25:27 -02:00
/**
2007-12-10 15:24:47 -05:00
* @ brief Checks whether a command is allowed in Power Save mode
2007-02-10 12:25:27 -02:00
*
* @ param command the command ID
2007-12-10 15:24:47 -05:00
* @ return 1 if allowed , 0 if not allowed
2007-02-10 12:25:27 -02:00
*/
2007-12-10 15:24:47 -05:00
static u8 is_command_allowed_in_ps ( u16 cmd )
2007-02-10 12:25:27 -02:00
{
2007-12-10 15:24:47 -05:00
switch ( cmd ) {
case CMD_802_11_RSSI :
return 1 ;
default :
break ;
2007-02-10 12:25:27 -02:00
}
return 0 ;
}
2009-10-06 19:20:28 -07:00
/**
* @ brief This function checks if the command is allowed .
*
* @ param priv A pointer to lbs_private structure
* @ return allowed or not allowed .
*/
static int lbs_is_cmd_allowed ( struct lbs_private * priv )
{
int ret = 1 ;
lbs_deb_enter ( LBS_DEB_CMD ) ;
if ( ! priv - > is_auto_deep_sleep_enabled ) {
if ( priv - > is_deep_sleep ) {
lbs_deb_cmd ( " command not allowed in deep sleep \n " ) ;
ret = 0 ;
}
}
lbs_deb_leave ( LBS_DEB_CMD ) ;
return ret ;
}
2007-12-11 12:42:16 -05:00
/**
* @ brief Updates the hardware details like MAC address and regulatory region
*
* @ param priv A pointer to struct lbs_private structure
*
* @ return 0 on success , error on failure
*/
int lbs_update_hw_spec ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
2007-12-11 12:42:16 -05:00
struct cmd_ds_get_hw_spec cmd ;
int ret = - 1 ;
u32 i ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2007-12-11 12:42:16 -05:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
memcpy ( cmd . permanentaddr , priv - > current_addr , ETH_ALEN ) ;
2007-12-12 16:00:42 -05:00
ret = lbs_cmd_with_response ( priv , CMD_GET_HW_SPEC , & cmd ) ;
2007-12-11 12:42:16 -05:00
if ( ret )
goto out ;
priv - > fwcapinfo = le32_to_cpu ( cmd . fwcapinfo ) ;
2008-01-16 15:55:22 +01:00
/* The firmware release is in an interesting format: the patch
* level is in the most significant nibble . . . so fix that : */
priv - > fwrelease = le32_to_cpu ( cmd . fwrelease ) ;
priv - > fwrelease = ( priv - > fwrelease < < 8 ) |
( priv - > fwrelease > > 24 & 0xff ) ;
/* Some firmware capabilities:
* CF card firmware 5.0 .16 p0 : cap 0x00000303
* USB dongle firmware 5.110 .17 p2 : cap 0x00000303
*/
2008-10-27 15:59:26 -07:00
lbs_pr_info ( " %pM, fw %u.%u.%up%u, cap 0x%08x \n " ,
cmd . permanentaddr ,
2008-01-16 15:55:22 +01:00
priv - > fwrelease > > 24 & 0xff ,
priv - > fwrelease > > 16 & 0xff ,
priv - > fwrelease > > 8 & 0xff ,
priv - > fwrelease & 0xff ,
priv - > fwcapinfo ) ;
2007-12-11 12:42:16 -05:00
lbs_deb_cmd ( " GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x \n " ,
cmd . hwifversion , cmd . version ) ;
2009-03-25 09:51:16 -07:00
/* Determine mesh_fw_ver from fwrelease and fwcapinfo */
/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
/* 5.110.22 have mesh command with 0xa3 command id */
/* 10.0.0.p0 FW brings in mesh config command with different id */
/* Check FW version MSB and initialize mesh_fw_ver */
if ( MRVL_FW_MAJOR_REV ( priv - > fwrelease ) = = MRVL_FW_V5 )
priv - > mesh_fw_ver = MESH_FW_OLD ;
else if ( ( MRVL_FW_MAJOR_REV ( priv - > fwrelease ) > = MRVL_FW_V10 ) & &
( priv - > fwcapinfo & MESH_CAPINFO_ENABLE_MASK ) )
priv - > mesh_fw_ver = MESH_FW_NEW ;
else
priv - > mesh_fw_ver = MESH_NONE ;
2007-12-11 12:42:16 -05:00
/* Clamp region code to 8-bit since FW spec indicates that it should
* only ever be 8 - bit , even though the field size is 16 - bit . Some firmware
* returns non - zero high 8 bits here .
2009-07-16 19:19:53 +02:00
*
* Firmware version 4.0 .102 used in CF8381 has region code shifted . We
* need to check for this problem and handle it properly .
2007-12-11 12:42:16 -05:00
*/
2009-07-16 19:19:53 +02:00
if ( MRVL_FW_MAJOR_REV ( priv - > fwrelease ) = = MRVL_FW_V4 )
priv - > regioncode = ( le16_to_cpu ( cmd . regioncode ) > > 8 ) & 0xFF ;
else
priv - > regioncode = le16_to_cpu ( cmd . regioncode ) & 0xFF ;
2007-12-11 12:42:16 -05:00
for ( i = 0 ; i < MRVDRV_MAX_REGION_CODE ; i + + ) {
/* use the region code to search for the index */
if ( priv - > regioncode = = lbs_region_code_to_index [ i ] )
break ;
}
/* if it's unidentified region code, use the default (USA) */
if ( i > = MRVDRV_MAX_REGION_CODE ) {
priv - > regioncode = 0x10 ;
lbs_pr_info ( " unidentified region code; using the default (USA) \n " ) ;
}
if ( priv - > current_addr [ 0 ] = = 0xff )
memmove ( priv - > current_addr , cmd . permanentaddr , ETH_ALEN ) ;
2007-02-10 12:25:27 -02:00
2007-12-11 12:42:16 -05:00
memcpy ( priv - > dev - > dev_addr , priv - > current_addr , ETH_ALEN ) ;
if ( priv - > mesh_dev )
memcpy ( priv - > mesh_dev - > dev_addr , priv - > current_addr , ETH_ALEN ) ;
if ( lbs_set_regiontable ( priv , priv - > regioncode , 0 ) ) {
ret = - 1 ;
goto out ;
}
out :
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
2007-12-11 12:42:16 -05:00
return ret ;
2007-02-10 12:25:27 -02:00
}
2008-10-20 16:46:56 -07:00
int lbs_host_sleep_cfg ( struct lbs_private * priv , uint32_t criteria ,
struct wol_config * p_wol_config )
2007-12-12 15:19:29 -05:00
{
struct cmd_ds_host_sleep cmd_config ;
int ret ;
2007-12-15 03:46:44 -05:00
cmd_config . hdr . size = cpu_to_le16 ( sizeof ( cmd_config ) ) ;
2007-12-12 15:19:29 -05:00
cmd_config . criteria = cpu_to_le32 ( criteria ) ;
2007-12-12 20:06:06 -05:00
cmd_config . gpio = priv - > wol_gpio ;
cmd_config . gap = priv - > wol_gap ;
2007-12-12 15:19:29 -05:00
2008-10-20 16:46:56 -07:00
if ( p_wol_config ! = NULL )
memcpy ( ( uint8_t * ) & cmd_config . wol_conf , ( uint8_t * ) p_wol_config ,
sizeof ( struct wol_config ) ) ;
else
cmd_config . wol_conf . action = CMD_ACT_ACTION_NONE ;
2007-12-12 16:00:42 -05:00
ret = lbs_cmd_with_response ( priv , CMD_802_11_HOST_SLEEP_CFG , & cmd_config ) ;
2007-12-12 20:06:06 -05:00
if ( ! ret ) {
2008-10-20 16:46:56 -07:00
if ( criteria ) {
lbs_deb_cmd ( " Set WOL criteria to %x \n " , criteria ) ;
priv - > wol_criteria = criteria ;
} else
memcpy ( ( uint8_t * ) p_wol_config ,
( uint8_t * ) & cmd_config . wol_conf ,
sizeof ( struct wol_config ) ) ;
2007-12-12 20:06:06 -05:00
} else {
2007-12-12 15:19:29 -05:00
lbs_pr_info ( " HOST_SLEEP_CFG failed %d \n " , ret ) ;
}
2007-12-12 20:06:06 -05:00
2007-12-12 15:19:29 -05:00
return ret ;
}
EXPORT_SYMBOL_GPL ( lbs_host_sleep_cfg ) ;
2008-03-19 14:25:58 +01:00
static int lbs_cmd_802_11_ps_mode ( struct cmd_ds_command * cmd ,
2007-02-10 12:25:27 -02:00
u16 cmd_action )
{
struct cmd_ds_802_11_ps_mode * psm = & cmd - > params . psmode ;
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:31:18 -04:00
cmd - > command = cpu_to_le16 ( CMD_802_11_PS_MODE ) ;
2007-05-25 23:36:54 -04:00
cmd - > size = cpu_to_le16 ( sizeof ( struct cmd_ds_802_11_ps_mode ) +
2009-10-22 15:30:55 +02:00
sizeof ( struct cmd_header ) ) ;
2007-02-10 12:25:27 -02:00
psm - > action = cpu_to_le16 ( cmd_action ) ;
psm - > multipledtim = 0 ;
2007-05-25 23:36:54 -04:00
switch ( cmd_action ) {
2007-08-02 11:31:18 -04:00
case CMD_SUBCMD_ENTER_PS :
2007-05-25 11:27:16 -04:00
lbs_deb_cmd ( " PS command: " " SubCode- Enter PS \n " ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 13:09:34 -04:00
psm - > locallisteninterval = 0 ;
2007-08-02 13:09:15 -04:00
psm - > nullpktinterval = 0 ;
2007-02-10 12:25:27 -02:00
psm - > multipledtim =
2007-08-02 13:09:49 -04:00
cpu_to_le16 ( MRVDRV_DEFAULT_MULTIPLE_DTIM ) ;
2007-02-10 12:25:27 -02:00
break ;
2007-08-02 11:31:18 -04:00
case CMD_SUBCMD_EXIT_PS :
2007-05-25 11:27:16 -04:00
lbs_deb_cmd ( " PS command: " " SubCode- Exit PS \n " ) ;
2007-02-10 12:25:27 -02:00
break ;
2007-08-02 11:31:18 -04:00
case CMD_SUBCMD_SLEEP_CONFIRMED :
2007-05-25 11:27:16 -04:00
lbs_deb_cmd ( " PS command: SubCode- sleep confirm \n " ) ;
2007-02-10 12:25:27 -02:00
break ;
default :
break ;
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-12-17 23:48:31 -05:00
int lbs_cmd_802_11_sleep_params ( struct lbs_private * priv , uint16_t cmd_action ,
struct sleep_params * sp )
2007-02-10 12:25:27 -02:00
{
2007-12-17 23:48:31 -05:00
struct cmd_ds_802_11_sleep_params cmd ;
int ret ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:31:18 -04:00
if ( cmd_action = = CMD_ACT_GET ) {
2007-12-17 23:48:31 -05:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
} else {
cmd . error = cpu_to_le16 ( sp - > sp_error ) ;
cmd . offset = cpu_to_le16 ( sp - > sp_offset ) ;
cmd . stabletime = cpu_to_le16 ( sp - > sp_stabletime ) ;
cmd . calcontrol = sp - > sp_calcontrol ;
cmd . externalsleepclk = sp - > sp_extsleepclk ;
cmd . reserved = cpu_to_le16 ( sp - > sp_reserved ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-17 23:48:31 -05:00
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( cmd_action ) ;
2007-02-10 12:25:27 -02:00
2007-12-17 23:48:31 -05:00
ret = lbs_cmd_with_response ( priv , CMD_802_11_SLEEP_PARAMS , & cmd ) ;
if ( ! ret ) {
lbs_deb_cmd ( " error 0x%x, offset 0x%x, stabletime 0x%x, "
" calcontrol 0x%x extsleepclk 0x%x \n " ,
le16_to_cpu ( cmd . error ) , le16_to_cpu ( cmd . offset ) ,
le16_to_cpu ( cmd . stabletime ) , cmd . calcontrol ,
cmd . externalsleepclk ) ;
sp - > sp_error = le16_to_cpu ( cmd . error ) ;
sp - > sp_offset = le16_to_cpu ( cmd . offset ) ;
sp - > sp_stabletime = le16_to_cpu ( cmd . stabletime ) ;
sp - > sp_calcontrol = cmd . calcontrol ;
sp - > sp_extsleepclk = cmd . externalsleepclk ;
sp - > sp_reserved = le16_to_cpu ( cmd . reserved ) ;
}
lbs_deb_leave_args ( LBS_DEB_CMD , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2009-09-30 20:04:38 -07:00
static int lbs_wait_for_ds_awake ( struct lbs_private * priv )
{
int ret = 0 ;
lbs_deb_enter ( LBS_DEB_CMD ) ;
if ( priv - > is_deep_sleep ) {
if ( ! wait_event_interruptible_timeout ( priv - > ds_awake_q ,
! priv - > is_deep_sleep , ( 10 * HZ ) ) ) {
lbs_pr_err ( " ds_awake_q: timer expired \n " ) ;
ret = - 1 ;
}
}
lbs_deb_leave_args ( LBS_DEB_CMD , " ret %d " , ret ) ;
return ret ;
}
int lbs_set_deep_sleep ( struct lbs_private * priv , int deep_sleep )
{
int ret = 0 ;
lbs_deb_enter ( LBS_DEB_CMD ) ;
if ( deep_sleep ) {
if ( priv - > is_deep_sleep ! = 1 ) {
lbs_deb_cmd ( " deep sleep: sleep \n " ) ;
BUG_ON ( ! priv - > enter_deep_sleep ) ;
ret = priv - > enter_deep_sleep ( priv ) ;
if ( ! ret ) {
netif_stop_queue ( priv - > dev ) ;
netif_carrier_off ( priv - > dev ) ;
}
} else {
lbs_pr_err ( " deep sleep: already enabled \n " ) ;
}
} else {
if ( priv - > is_deep_sleep ) {
lbs_deb_cmd ( " deep sleep: wakeup \n " ) ;
BUG_ON ( ! priv - > exit_deep_sleep ) ;
ret = priv - > exit_deep_sleep ( priv ) ;
if ( ! ret ) {
ret = lbs_wait_for_ds_awake ( priv ) ;
if ( ret )
lbs_pr_err ( " deep sleep: wakeup "
" failed \n " ) ;
}
}
}
lbs_deb_leave_args ( LBS_DEB_CMD , " ret %d " , ret ) ;
return ret ;
}
2008-09-10 12:49:00 -04:00
/**
* @ brief Set an SNMP MIB value
*
* @ param priv A pointer to struct lbs_private structure
* @ param oid The OID to set in the firmware
* @ param val Value to set the OID to
*
* @ return 0 on success , error on failure
*/
int lbs_set_snmp_mib ( struct lbs_private * priv , u32 oid , u16 val )
2007-02-10 12:25:27 -02:00
{
2008-09-10 12:49:00 -04:00
struct cmd_ds_802_11_snmp_mib cmd ;
int ret ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2008-09-10 12:49:00 -04:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( CMD_ACT_SET ) ;
cmd . oid = cpu_to_le16 ( ( u16 ) oid ) ;
2007-02-10 12:25:27 -02:00
2008-09-10 12:49:00 -04:00
switch ( oid ) {
case SNMP_MIB_OID_BSS_TYPE :
cmd . bufsize = cpu_to_le16 ( sizeof ( u8 ) ) ;
cmd . value [ 0 ] = ( val = = IW_MODE_ADHOC ) ? 2 : 1 ;
break ;
case SNMP_MIB_OID_11D_ENABLE :
case SNMP_MIB_OID_FRAG_THRESHOLD :
case SNMP_MIB_OID_RTS_THRESHOLD :
case SNMP_MIB_OID_SHORT_RETRY_LIMIT :
case SNMP_MIB_OID_LONG_RETRY_LIMIT :
cmd . bufsize = cpu_to_le16 ( sizeof ( u16 ) ) ;
* ( ( __le16 * ) ( & cmd . value ) ) = cpu_to_le16 ( val ) ;
2007-02-10 12:25:27 -02:00
break ;
2008-09-10 12:49:00 -04:00
default :
lbs_deb_cmd ( " SNMP_CMD: (set) unhandled OID 0x%x \n " , oid ) ;
ret = - EINVAL ;
goto out ;
2007-02-10 12:25:27 -02:00
}
2008-09-10 12:49:00 -04:00
lbs_deb_cmd ( " SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x \n " ,
le16_to_cpu ( cmd . oid ) , le16_to_cpu ( cmd . bufsize ) , val ) ;
2007-02-10 12:25:27 -02:00
2008-09-10 12:49:00 -04:00
ret = lbs_cmd_with_response ( priv , CMD_802_11_SNMP_MIB , & cmd ) ;
2007-02-10 12:25:27 -02:00
2008-09-10 12:49:00 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_CMD , " ret %d " , ret ) ;
return ret ;
}
2007-02-10 12:25:27 -02:00
2008-09-10 12:49:00 -04:00
/**
* @ brief Get an SNMP MIB value
*
* @ param priv A pointer to struct lbs_private structure
* @ param oid The OID to retrieve from the firmware
* @ param out_val Location for the returned value
*
* @ return 0 on success , error on failure
*/
int lbs_get_snmp_mib ( struct lbs_private * priv , u32 oid , u16 * out_val )
{
struct cmd_ds_802_11_snmp_mib cmd ;
int ret ;
2007-02-10 12:25:27 -02:00
2008-09-10 12:49:00 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2008-09-10 12:49:00 -04:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( CMD_ACT_GET ) ;
cmd . oid = cpu_to_le16 ( oid ) ;
2007-02-10 12:25:27 -02:00
2008-09-10 12:49:00 -04:00
ret = lbs_cmd_with_response ( priv , CMD_802_11_SNMP_MIB , & cmd ) ;
if ( ret )
goto out ;
2007-02-10 12:25:27 -02:00
2008-09-10 12:49:00 -04:00
switch ( le16_to_cpu ( cmd . bufsize ) ) {
case sizeof ( u8 ) :
if ( oid = = SNMP_MIB_OID_BSS_TYPE ) {
if ( cmd . value [ 0 ] = = 2 )
* out_val = IW_MODE_ADHOC ;
else
* out_val = IW_MODE_INFRA ;
} else
* out_val = cmd . value [ 0 ] ;
break ;
case sizeof ( u16 ) :
* out_val = le16_to_cpu ( * ( ( __le16 * ) ( & cmd . value ) ) ) ;
2007-02-10 12:25:27 -02:00
break ;
default :
2008-09-10 12:49:00 -04:00
lbs_deb_cmd ( " SNMP_CMD: (get) unhandled OID 0x%x size %d \n " ,
oid , le16_to_cpu ( cmd . bufsize ) ) ;
2007-02-10 12:25:27 -02:00
break ;
}
2008-09-10 12:49:00 -04:00
out :
lbs_deb_leave_args ( LBS_DEB_CMD , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
2008-08-19 15:15:35 -04:00
/**
* @ brief Get the min , max , and current TX power
*
* @ param priv A pointer to struct lbs_private structure
* @ param curlevel Current power level in dBm
* @ param minlevel Minimum supported power level in dBm ( optional )
* @ param maxlevel Maximum supported power level in dBm ( optional )
*
* @ return 0 on success , error on failure
*/
int lbs_get_tx_power ( struct lbs_private * priv , s16 * curlevel , s16 * minlevel ,
s16 * maxlevel )
2007-02-10 12:25:27 -02:00
{
2008-08-19 15:15:35 -04:00
struct cmd_ds_802_11_rf_tx_power cmd ;
int ret ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2008-08-19 15:15:35 -04:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( CMD_ACT_GET ) ;
ret = lbs_cmd_with_response ( priv , CMD_802_11_RF_TX_POWER , & cmd ) ;
if ( ret = = 0 ) {
* curlevel = le16_to_cpu ( cmd . curlevel ) ;
if ( minlevel )
2008-10-29 10:35:02 +01:00
* minlevel = cmd . minlevel ;
2008-08-19 15:15:35 -04:00
if ( maxlevel )
2008-10-29 10:35:02 +01:00
* maxlevel = cmd . maxlevel ;
2008-08-19 15:15:35 -04:00
}
2007-02-10 12:25:27 -02:00
2008-08-19 15:15:35 -04:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
return ret ;
}
2007-02-10 12:25:27 -02:00
2008-08-19 15:15:35 -04:00
/**
* @ brief Set the TX power
*
* @ param priv A pointer to struct lbs_private structure
* @ param dbm The desired power level in dBm
*
* @ return 0 on success , error on failure
*/
int lbs_set_tx_power ( struct lbs_private * priv , s16 dbm )
{
struct cmd_ds_802_11_rf_tx_power cmd ;
int ret ;
2007-02-10 12:25:27 -02:00
2008-08-19 15:15:35 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2008-08-19 15:15:35 -04:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( CMD_ACT_SET ) ;
cmd . curlevel = cpu_to_le16 ( dbm ) ;
2007-02-10 12:25:27 -02:00
2008-08-19 15:15:35 -04:00
lbs_deb_cmd ( " SET_RF_TX_POWER: %d dBm \n " , dbm ) ;
ret = lbs_cmd_with_response ( priv , CMD_802_11_RF_TX_POWER , & cmd ) ;
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
2008-08-19 15:15:35 -04:00
return ret ;
2007-02-10 12:25:27 -02:00
}
2008-03-19 14:25:58 +01:00
static int lbs_cmd_802_11_monitor_mode ( struct cmd_ds_command * cmd ,
2007-08-02 13:16:55 -04:00
u16 cmd_action , void * pdata_buf )
{
struct cmd_ds_802_11_monitor_mode * monitor = & cmd - > params . monitor ;
cmd - > command = cpu_to_le16 ( CMD_802_11_MONITOR_MODE ) ;
cmd - > size =
cpu_to_le16 ( sizeof ( struct cmd_ds_802_11_monitor_mode ) +
2009-10-22 15:30:55 +02:00
sizeof ( struct cmd_header ) ) ;
2007-08-02 13:16:55 -04:00
monitor - > action = cpu_to_le16 ( cmd_action ) ;
if ( cmd_action = = CMD_ACT_SET ) {
monitor - > mode =
cpu_to_le16 ( ( u16 ) ( * ( u32 * ) pdata_buf ) ) ;
}
return 0 ;
}
2007-12-11 16:54:15 -05:00
/**
* @ brief Get the radio channel
*
* @ param priv A pointer to struct lbs_private structure
*
* @ return The channel on success , error on failure
*/
2009-10-16 17:33:56 +02:00
static int lbs_get_channel ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
2007-12-11 16:54:15 -05:00
struct cmd_ds_802_11_rf_channel cmd ;
int ret = 0 ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2008-04-09 10:23:31 +02:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
2007-12-11 16:54:15 -05:00
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( CMD_OPT_802_11_RF_CHANNEL_GET ) ;
2007-02-10 12:25:27 -02:00
2007-12-12 16:00:42 -05:00
ret = lbs_cmd_with_response ( priv , CMD_802_11_RF_CHANNEL , & cmd ) ;
2007-12-11 16:54:15 -05:00
if ( ret )
goto out ;
2007-02-10 12:25:27 -02:00
2007-12-11 17:35:51 -05:00
ret = le16_to_cpu ( cmd . channel ) ;
lbs_deb_cmd ( " current radio channel is %d \n " , ret ) ;
2007-12-11 16:54:15 -05:00
out :
lbs_deb_leave_args ( LBS_DEB_CMD , " ret %d " , ret ) ;
return ret ;
}
2008-04-02 16:52:19 +02:00
int lbs_update_channel ( struct lbs_private * priv )
{
int ret ;
/* the channel in f/w could be out of sync; get the current channel */
lbs_deb_enter ( LBS_DEB_ASSOC ) ;
ret = lbs_get_channel ( priv ) ;
if ( ret > 0 ) {
2009-10-22 15:30:50 +02:00
priv - > channel = ret ;
2008-04-02 16:52:19 +02:00
ret = 0 ;
}
lbs_deb_leave_args ( LBS_DEB_ASSOC , " ret %d " , ret ) ;
return ret ;
}
2007-12-11 16:54:15 -05:00
/**
* @ brief Set the radio channel
*
* @ param priv A pointer to struct lbs_private structure
* @ param channel The desired channel , or 0 to clear a locked channel
*
* @ return 0 on success , error on failure
*/
int lbs_set_channel ( struct lbs_private * priv , u8 channel )
{
struct cmd_ds_802_11_rf_channel cmd ;
2008-10-13 16:22:42 +05:30
# ifdef DEBUG
2009-10-22 15:30:50 +02:00
u8 old_channel = priv - > channel ;
2008-10-13 16:22:42 +05:30
# endif
2007-12-11 16:54:15 -05:00
int ret = 0 ;
lbs_deb_enter ( LBS_DEB_CMD ) ;
2008-04-09 10:23:31 +02:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
2007-12-11 16:54:15 -05:00
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( CMD_OPT_802_11_RF_CHANNEL_SET ) ;
cmd . channel = cpu_to_le16 ( channel ) ;
2007-12-12 16:00:42 -05:00
ret = lbs_cmd_with_response ( priv , CMD_802_11_RF_CHANNEL , & cmd ) ;
2007-12-11 16:54:15 -05:00
if ( ret )
goto out ;
2009-10-22 15:30:50 +02:00
priv - > channel = ( uint8_t ) le16_to_cpu ( cmd . channel ) ;
2007-12-11 17:35:51 -05:00
lbs_deb_cmd ( " channel switch from %d to %d \n " , old_channel ,
2009-10-22 15:30:50 +02:00
priv - > channel ) ;
2007-12-11 16:54:15 -05:00
out :
lbs_deb_leave_args ( LBS_DEB_CMD , " ret %d " , ret ) ;
return ret ;
2007-02-10 12:25:27 -02:00
}
2008-03-19 14:25:58 +01:00
static int lbs_cmd_reg_access ( struct cmd_ds_command * cmdptr ,
2007-02-10 12:25:27 -02:00
u8 cmd_action , void * pdata_buf )
{
2007-11-15 18:05:47 -05:00
struct lbs_offset_value * offval ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
offval = ( struct lbs_offset_value * ) pdata_buf ;
2007-02-10 12:25:27 -02:00
2007-12-07 15:30:44 +00:00
switch ( le16_to_cpu ( cmdptr - > command ) ) {
2007-08-02 11:31:18 -04:00
case CMD_MAC_REG_ACCESS :
2007-02-10 12:25:27 -02:00
{
struct cmd_ds_mac_reg_access * macreg ;
cmdptr - > size =
2007-05-25 23:36:54 -04:00
cpu_to_le16 ( sizeof ( struct cmd_ds_mac_reg_access )
2009-10-22 15:30:55 +02:00
+ sizeof ( struct cmd_header ) ) ;
2007-02-10 12:25:27 -02:00
macreg =
( struct cmd_ds_mac_reg_access * ) & cmdptr - > params .
macreg ;
macreg - > action = cpu_to_le16 ( cmd_action ) ;
macreg - > offset = cpu_to_le16 ( ( u16 ) offval - > offset ) ;
macreg - > value = cpu_to_le32 ( offval - > value ) ;
break ;
}
2007-08-02 11:31:18 -04:00
case CMD_BBP_REG_ACCESS :
2007-02-10 12:25:27 -02:00
{
struct cmd_ds_bbp_reg_access * bbpreg ;
cmdptr - > size =
cpu_to_le16 ( sizeof
( struct cmd_ds_bbp_reg_access )
2009-10-22 15:30:55 +02:00
+ sizeof ( struct cmd_header ) ) ;
2007-02-10 12:25:27 -02:00
bbpreg =
( struct cmd_ds_bbp_reg_access * ) & cmdptr - > params .
bbpreg ;
bbpreg - > action = cpu_to_le16 ( cmd_action ) ;
bbpreg - > offset = cpu_to_le16 ( ( u16 ) offval - > offset ) ;
bbpreg - > value = ( u8 ) offval - > value ;
break ;
}
2007-08-02 11:31:18 -04:00
case CMD_RF_REG_ACCESS :
2007-02-10 12:25:27 -02:00
{
struct cmd_ds_rf_reg_access * rfreg ;
cmdptr - > size =
cpu_to_le16 ( sizeof
( struct cmd_ds_rf_reg_access ) +
2009-10-22 15:30:55 +02:00
sizeof ( struct cmd_header ) ) ;
2007-02-10 12:25:27 -02:00
rfreg =
( struct cmd_ds_rf_reg_access * ) & cmdptr - > params .
rfreg ;
rfreg - > action = cpu_to_le16 ( cmd_action ) ;
rfreg - > offset = cpu_to_le16 ( ( u16 ) offval - > offset ) ;
rfreg - > value = ( u8 ) offval - > value ;
break ;
}
default :
break ;
}
2007-05-25 11:27:16 -04:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2008-03-19 14:25:58 +01:00
static int lbs_cmd_bt_access ( struct cmd_ds_command * cmd ,
2007-02-10 12:25:27 -02:00
u16 cmd_action , void * pdata_buf )
{
struct cmd_ds_bt_access * bt_access = & cmd - > params . bt ;
2007-08-02 11:54:31 -04:00
lbs_deb_enter_args ( LBS_DEB_CMD , " action %d " , cmd_action ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:31:18 -04:00
cmd - > command = cpu_to_le16 ( CMD_BT_ACCESS ) ;
2009-10-22 15:30:55 +02:00
cmd - > size = cpu_to_le16 ( sizeof ( struct cmd_ds_bt_access ) +
sizeof ( struct cmd_header ) ) ;
2007-02-10 12:25:27 -02:00
cmd - > result = 0 ;
bt_access - > action = cpu_to_le16 ( cmd_action ) ;
switch ( cmd_action ) {
2007-08-02 11:31:18 -04:00
case CMD_ACT_BT_ACCESS_ADD :
2007-02-10 12:25:27 -02:00
memcpy ( bt_access - > addr1 , pdata_buf , 2 * ETH_ALEN ) ;
2007-08-02 11:53:06 -04:00
lbs_deb_hex ( LBS_DEB_MESH , " BT_ADD: blinded MAC addr " , bt_access - > addr1 , 6 ) ;
2007-02-10 12:25:27 -02:00
break ;
2007-08-02 11:31:18 -04:00
case CMD_ACT_BT_ACCESS_DEL :
2007-02-10 12:25:27 -02:00
memcpy ( bt_access - > addr1 , pdata_buf , 1 * ETH_ALEN ) ;
2007-08-02 11:53:06 -04:00
lbs_deb_hex ( LBS_DEB_MESH , " BT_DEL: blinded MAC addr " , bt_access - > addr1 , 6 ) ;
2007-02-10 12:25:27 -02:00
break ;
2007-08-02 11:31:18 -04:00
case CMD_ACT_BT_ACCESS_LIST :
2007-02-10 12:25:27 -02:00
bt_access - > id = cpu_to_le32 ( * ( u32 * ) pdata_buf ) ;
break ;
2007-08-02 11:31:18 -04:00
case CMD_ACT_BT_ACCESS_RESET :
2007-02-10 12:25:27 -02:00
break ;
2007-08-02 11:31:18 -04:00
case CMD_ACT_BT_ACCESS_SET_INVERT :
2007-05-25 13:53:26 -04:00
bt_access - > id = cpu_to_le32 ( * ( u32 * ) pdata_buf ) ;
break ;
2007-08-02 11:31:18 -04:00
case CMD_ACT_BT_ACCESS_GET_INVERT :
2007-05-25 13:53:26 -04:00
break ;
2007-02-10 12:25:27 -02:00
default :
break ;
}
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2008-03-19 14:25:58 +01:00
static int lbs_cmd_fwt_access ( struct cmd_ds_command * cmd ,
2007-02-10 12:25:27 -02:00
u16 cmd_action , void * pdata_buf )
{
struct cmd_ds_fwt_access * fwt_access = & cmd - > params . fwt ;
2007-08-02 11:54:31 -04:00
lbs_deb_enter_args ( LBS_DEB_CMD , " action %d " , cmd_action ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:31:18 -04:00
cmd - > command = cpu_to_le16 ( CMD_FWT_ACCESS ) ;
2009-10-22 15:30:55 +02:00
cmd - > size = cpu_to_le16 ( sizeof ( struct cmd_ds_fwt_access ) +
sizeof ( struct cmd_header ) ) ;
2007-02-10 12:25:27 -02:00
cmd - > result = 0 ;
if ( pdata_buf )
memcpy ( fwt_access , pdata_buf , sizeof ( * fwt_access ) ) ;
else
memset ( fwt_access , 0 , sizeof ( * fwt_access ) ) ;
fwt_access - > action = cpu_to_le16 ( cmd_action ) ;
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
2007-12-11 15:23:59 -05:00
int lbs_mesh_access ( struct lbs_private * priv , uint16_t cmd_action ,
struct cmd_ds_mesh_access * cmd )
2007-02-10 12:25:27 -02:00
{
2007-12-11 15:23:59 -05:00
int ret ;
2007-08-02 11:54:31 -04:00
lbs_deb_enter_args ( LBS_DEB_CMD , " action %d " , cmd_action ) ;
2007-02-10 12:25:27 -02:00
2007-12-11 15:23:59 -05:00
cmd - > hdr . command = cpu_to_le16 ( CMD_MESH_ACCESS ) ;
2007-12-15 03:46:44 -05:00
cmd - > hdr . size = cpu_to_le16 ( sizeof ( * cmd ) ) ;
2007-12-11 15:23:59 -05:00
cmd - > hdr . result = 0 ;
2007-02-10 12:25:27 -02:00
2007-12-11 15:23:59 -05:00
cmd - > action = cpu_to_le16 ( cmd_action ) ;
2007-02-10 12:25:27 -02:00
2007-12-12 16:00:42 -05:00
ret = lbs_cmd_with_response ( priv , CMD_MESH_ACCESS , cmd ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
2007-12-11 15:23:59 -05:00
return ret ;
2007-02-10 12:25:27 -02:00
}
2008-07-21 11:02:46 -07:00
static int __lbs_mesh_config_send ( struct lbs_private * priv ,
struct cmd_ds_mesh_config * cmd ,
uint16_t action , uint16_t type )
2008-05-17 00:55:10 -07:00
{
int ret ;
2009-03-25 09:51:16 -07:00
u16 command = CMD_MESH_CONFIG_OLD ;
2008-05-17 00:55:10 -07:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2009-03-25 09:51:16 -07:00
/*
* Command id is 0xac for v10 FW along with mesh interface
* id in bits 14 - 13 - 12.
*/
if ( priv - > mesh_fw_ver = = MESH_FW_NEW )
command = CMD_MESH_CONFIG |
( MESH_IFACE_ID < < MESH_IFACE_BIT_OFFSET ) ;
cmd - > hdr . command = cpu_to_le16 ( command ) ;
2008-05-17 00:55:10 -07:00
cmd - > hdr . size = cpu_to_le16 ( sizeof ( struct cmd_ds_mesh_config ) ) ;
cmd - > hdr . result = 0 ;
cmd - > type = cpu_to_le16 ( type ) ;
cmd - > action = cpu_to_le16 ( action ) ;
2009-03-25 09:51:16 -07:00
ret = lbs_cmd_with_response ( priv , command , cmd ) ;
2008-05-17 00:55:10 -07:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
return ret ;
}
2008-07-21 11:02:46 -07:00
int lbs_mesh_config_send ( struct lbs_private * priv ,
struct cmd_ds_mesh_config * cmd ,
uint16_t action , uint16_t type )
{
int ret ;
if ( ! ( priv - > fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG ) )
return - EOPNOTSUPP ;
ret = __lbs_mesh_config_send ( priv , cmd , action , type ) ;
return ret ;
}
2008-05-17 00:55:10 -07:00
/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
* START and STOP actions . The extended actions supported by CMD_MESH_CONFIG
* are all handled by preparing a struct cmd_ds_mesh_config and passing it to
* lbs_mesh_config_send .
*/
int lbs_mesh_config ( struct lbs_private * priv , uint16_t action , uint16_t chan )
2007-12-11 18:56:42 -05:00
{
struct cmd_ds_mesh_config cmd ;
2008-05-17 00:55:10 -07:00
struct mrvl_meshie * ie ;
2008-09-30 20:59:05 -04:00
DECLARE_SSID_BUF ( ssid ) ;
2007-12-11 18:56:42 -05:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
2007-12-13 00:32:36 -05:00
cmd . channel = cpu_to_le16 ( chan ) ;
2008-05-17 00:55:10 -07:00
ie = ( struct mrvl_meshie * ) cmd . data ;
switch ( action ) {
case CMD_ACT_MESH_CONFIG_START :
2008-10-30 22:09:54 +01:00
ie - > id = WLAN_EID_GENERIC ;
2008-05-17 00:55:10 -07:00
ie - > val . oui [ 0 ] = 0x00 ;
ie - > val . oui [ 1 ] = 0x50 ;
ie - > val . oui [ 2 ] = 0x43 ;
ie - > val . type = MARVELL_MESH_IE_TYPE ;
ie - > val . subtype = MARVELL_MESH_IE_SUBTYPE ;
ie - > val . version = MARVELL_MESH_IE_VERSION ;
ie - > val . active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP ;
ie - > val . active_metric_id = MARVELL_MESH_METRIC_ID ;
ie - > val . mesh_capability = MARVELL_MESH_CAPABILITY ;
ie - > val . mesh_id_len = priv - > mesh_ssid_len ;
memcpy ( ie - > val . mesh_id , priv - > mesh_ssid , priv - > mesh_ssid_len ) ;
2008-10-30 22:09:54 +01:00
ie - > len = sizeof ( struct mrvl_meshie_val ) -
2009-10-22 15:30:47 +02:00
IEEE80211_MAX_SSID_LEN + priv - > mesh_ssid_len ;
2008-05-17 00:55:10 -07:00
cmd . length = cpu_to_le16 ( sizeof ( struct mrvl_meshie_val ) ) ;
break ;
case CMD_ACT_MESH_CONFIG_STOP :
break ;
default :
return - 1 ;
2007-12-11 18:56:42 -05:00
}
2008-05-17 00:55:10 -07:00
lbs_deb_cmd ( " mesh config action %d type %x channel %d SSID %s \n " ,
action , priv - > mesh_tlv , chan ,
2008-09-30 20:59:05 -04:00
print_ssid ( ssid , priv - > mesh_ssid , priv - > mesh_ssid_len ) ) ;
2008-05-17 00:55:10 -07:00
2008-07-21 11:02:46 -07:00
return __lbs_mesh_config_send ( priv , & cmd , action , priv - > mesh_tlv ) ;
2007-12-11 18:56:42 -05:00
}
2007-12-15 20:04:54 -05:00
static void lbs_queue_cmd ( struct lbs_private * priv ,
struct cmd_ctrl_node * cmdnode )
2007-02-10 12:25:27 -02:00
{
unsigned long flags ;
2007-12-15 20:04:54 -05:00
int addtail = 1 ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
2007-12-15 00:41:51 -05:00
if ( ! cmdnode ) {
lbs_deb_host ( " QUEUE_CMD: cmdnode is NULL \n " ) ;
2007-02-10 12:25:27 -02:00
goto done ;
}
2007-12-15 00:09:25 -05:00
if ( ! cmdnode - > cmdbuf - > size ) {
lbs_deb_host ( " DNLD_CMD: cmd size is zero \n " ) ;
goto done ;
}
2007-12-15 04:22:52 -05:00
cmdnode - > result = 0 ;
2007-02-10 12:25:27 -02:00
/* Exit_PS command needs to be queued in the header always. */
2007-12-11 13:49:39 -05:00
if ( le16_to_cpu ( cmdnode - > cmdbuf - > command ) = = CMD_802_11_PS_MODE ) {
2007-12-16 23:26:54 -05:00
struct cmd_ds_802_11_ps_mode * psm = ( void * ) & cmdnode - > cmdbuf [ 1 ] ;
2007-12-11 13:49:39 -05:00
2007-08-02 11:31:18 -04:00
if ( psm - > action = = cpu_to_le16 ( CMD_SUBCMD_EXIT_PS ) ) {
2007-12-08 20:04:36 +00:00
if ( priv - > psstate ! = PS_STATE_FULL_POWER )
2007-02-10 12:25:27 -02:00
addtail = 0 ;
}
}
2007-12-08 20:04:36 +00:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 00:35:00 +00:00
if ( addtail )
2007-12-08 20:04:36 +00:00
list_add_tail ( & cmdnode - > list , & priv - > cmdpendingq ) ;
2007-12-08 00:35:00 +00:00
else
2007-12-08 20:04:36 +00:00
list_add ( & cmdnode - > list , & priv - > cmdpendingq ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " QUEUE_CMD: inserted command 0x%04x into cmdpendingq \n " ,
2007-12-15 00:41:51 -05:00
le16_to_cpu ( cmdnode - > cmdbuf - > command ) ) ;
2007-02-10 12:25:27 -02:00
done :
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-17 16:03:58 -05:00
static void lbs_submit_command ( struct lbs_private * priv ,
struct cmd_ctrl_node * cmdnode )
2007-02-10 12:25:27 -02:00
{
unsigned long flags ;
2007-12-11 13:49:39 -05:00
struct cmd_header * cmd ;
2007-12-17 16:03:58 -05:00
uint16_t cmdsize ;
uint16_t command ;
2008-05-14 16:30:28 +02:00
int timeo = 3 * HZ ;
2007-12-17 16:03:58 -05:00
int ret ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
2007-12-11 13:49:39 -05:00
cmd = cmdnode - > cmdbuf ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
priv - > cur_cmd = cmdnode ;
priv - > cur_cmd_retcode = 0 ;
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
2007-12-11 13:49:39 -05:00
cmdsize = le16_to_cpu ( cmd - > size ) ;
command = le16_to_cpu ( cmd - > command ) ;
2007-02-10 12:25:27 -02:00
2007-12-17 16:03:58 -05:00
/* These commands take longer */
2009-05-22 20:05:25 -04:00
if ( command = = CMD_802_11_SCAN | | command = = CMD_802_11_ASSOCIATE )
2008-05-14 16:30:28 +02:00
timeo = 5 * HZ ;
2007-12-17 16:03:58 -05:00
2008-03-26 10:04:44 +01:00
lbs_deb_cmd ( " DNLD_CMD: command 0x%04x, seq %d, size %d \n " ,
command , le16_to_cpu ( cmd - > seqnum ) , cmdsize ) ;
2008-01-29 09:14:40 +01:00
lbs_deb_hex ( LBS_DEB_CMD , " DNLD_CMD " , ( void * ) cmdnode - > cmdbuf , cmdsize ) ;
2007-08-02 11:54:31 -04:00
2007-12-11 13:49:39 -05:00
ret = priv - > hw_host_to_card ( priv , MVMS_CMD , ( u8 * ) cmd , cmdsize ) ;
2007-12-17 16:03:58 -05:00
2007-12-15 00:09:25 -05:00
if ( ret ) {
lbs_pr_info ( " DNLD_CMD: hw_host_to_card failed: %d \n " , ret ) ;
2007-12-17 16:03:58 -05:00
/* Let the timer kick in and retry, and potentially reset
the whole thing if the condition persists */
2008-05-14 16:30:28 +02:00
timeo = HZ / 4 ;
2008-01-29 09:14:40 +01:00
}
2007-02-10 12:25:27 -02:00
2009-09-30 20:04:38 -07:00
if ( command = = CMD_802_11_DEEP_SLEEP ) {
if ( priv - > is_auto_deep_sleep_enabled ) {
priv - > wakeup_dev_required = 1 ;
priv - > dnld_sent = 0 ;
}
priv - > is_deep_sleep = 1 ;
lbs_complete_command ( priv , cmdnode , 0 ) ;
} else {
/* Setup the timer after transmit command */
mod_timer ( & priv - > command_timer , jiffies + timeo ) ;
}
2007-02-10 12:25:27 -02:00
2007-12-17 16:03:58 -05:00
lbs_deb_leave ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
}
/**
* This function inserts command node to cmdfreeq
2007-12-08 20:04:36 +00:00
* after cleans it . Requires priv - > driver_lock held .
2007-02-10 12:25:27 -02:00
*/
2007-12-15 01:52:54 -05:00
static void __lbs_cleanup_and_insert_cmd ( struct lbs_private * priv ,
2007-12-15 02:02:56 -05:00
struct cmd_ctrl_node * cmdnode )
2007-02-10 12:25:27 -02:00
{
2007-12-15 02:02:56 -05:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
if ( ! cmdnode )
goto out ;
cmdnode - > callback = NULL ;
cmdnode - > callback_arg = 0 ;
2007-02-10 12:25:27 -02:00
2007-12-15 02:02:56 -05:00
memset ( cmdnode - > cmdbuf , 0 , LBS_CMD_BUFFER_SIZE ) ;
2007-02-10 12:25:27 -02:00
2007-12-15 02:02:56 -05:00
list_add_tail ( & cmdnode - > list , & priv - > cmdfreeq ) ;
out :
lbs_deb_leave ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
}
2007-11-23 15:43:44 +01:00
static void lbs_cleanup_and_insert_cmd ( struct lbs_private * priv ,
struct cmd_ctrl_node * ptempcmd )
2007-02-10 12:25:27 -02:00
{
unsigned long flags ;
2007-12-08 20:04:36 +00:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
2007-11-15 18:05:47 -05:00
__lbs_cleanup_and_insert_cmd ( priv , ptempcmd ) ;
2007-12-08 20:04:36 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-15 01:52:54 -05:00
void lbs_complete_command ( struct lbs_private * priv , struct cmd_ctrl_node * cmd ,
int result )
{
if ( cmd = = priv - > cur_cmd )
priv - > cur_cmd_retcode = result ;
2007-12-15 02:02:56 -05:00
2007-12-15 04:22:52 -05:00
cmd - > result = result ;
2007-12-15 02:02:56 -05:00
cmd - > cmdwaitqwoken = 1 ;
wake_up_interruptible ( & cmd - > cmdwait_q ) ;
2008-03-19 10:11:00 +01:00
if ( ! cmd - > callback | | cmd - > callback = = lbs_cmd_async_callback )
2007-12-15 02:06:16 -05:00
__lbs_cleanup_and_insert_cmd ( priv , cmd ) ;
2007-12-15 01:52:54 -05:00
priv - > cur_cmd = NULL ;
}
2008-08-21 17:51:07 -04:00
int lbs_set_radio ( struct lbs_private * priv , u8 preamble , u8 radio_on )
2007-02-10 12:25:27 -02:00
{
2007-12-17 22:43:48 -05:00
struct cmd_ds_802_11_radio_control cmd ;
2008-08-21 17:51:07 -04:00
int ret = - EINVAL ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2007-12-17 22:43:48 -05:00
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( CMD_ACT_SET ) ;
2008-08-21 17:51:07 -04:00
/* Only v8 and below support setting the preamble */
if ( priv - > fwrelease < 0x09000000 ) {
switch ( preamble ) {
case RADIO_PREAMBLE_SHORT :
if ( ! ( priv - > capability & WLAN_CAPABILITY_SHORT_PREAMBLE ) )
goto out ;
/* Fall through */
case RADIO_PREAMBLE_AUTO :
case RADIO_PREAMBLE_LONG :
cmd . control = cpu_to_le16 ( preamble ) ;
break ;
default :
goto out ;
}
}
2007-12-17 22:43:48 -05:00
2008-08-21 17:51:07 -04:00
if ( radio_on )
cmd . control | = cpu_to_le16 ( 0x1 ) ;
else {
cmd . control & = cpu_to_le16 ( ~ 0x1 ) ;
priv - > txpower_cur = 0 ;
2007-12-17 22:43:48 -05:00
}
2007-02-10 12:25:27 -02:00
2008-08-21 17:51:07 -04:00
lbs_deb_cmd ( " RADIO_CONTROL: radio %s, preamble %d \n " ,
radio_on ? " ON " : " OFF " , preamble ) ;
2007-12-17 22:43:48 -05:00
2008-08-21 17:51:07 -04:00
priv - > radio_on = radio_on ;
2007-12-17 22:43:48 -05:00
ret = lbs_cmd_with_response ( priv , CMD_802_11_RADIO_CONTROL , & cmd ) ;
2007-02-10 12:25:27 -02:00
2008-08-21 17:51:07 -04:00
out :
2007-05-25 11:27:16 -04:00
lbs_deb_leave_args ( LBS_DEB_CMD , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2008-03-18 11:20:21 +01:00
void lbs_set_mac_control ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
2008-03-12 16:05:40 +01:00
struct cmd_ds_mac_control cmd ;
2007-02-10 12:25:27 -02:00
2007-05-25 11:27:16 -04:00
lbs_deb_enter ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
2008-03-12 16:05:40 +01:00
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
2008-03-12 16:06:43 +01:00
cmd . action = cpu_to_le16 ( priv - > mac_control ) ;
2008-03-12 16:05:40 +01:00
cmd . reserved = 0 ;
2008-05-20 13:32:45 +01:00
lbs_cmd_async ( priv , CMD_MAC_CONTROL , & cmd . hdr , sizeof ( cmd ) ) ;
2007-02-10 12:25:27 -02:00
2008-03-18 11:20:21 +01:00
lbs_deb_leave ( LBS_DEB_CMD ) ;
2007-02-10 12:25:27 -02:00
}
/**
* @ brief This function prepare the command before send to firmware .
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
* @ param cmd_no command number
* @ param cmd_action command action : GET or SET
* @ param wait_option wait option : wait response or not
* @ param cmd_oid cmd oid : treated as sub command
* @ param pdata_buf A pointer to informaion buffer
* @ return 0 or - 1
*/
2007-11-23 15:43:44 +01:00
int lbs_prepare_and_send_command ( struct lbs_private * priv ,
2007-02-10 12:25:27 -02:00
u16 cmd_no ,
u16 cmd_action ,
u16 wait_option , u32 cmd_oid , void * pdata_buf )
{
int ret = 0 ;
struct cmd_ctrl_node * cmdnode ;
struct cmd_ds_command * cmdptr ;
unsigned long flags ;
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
if ( ! priv ) {
lbs_deb_host ( " PREP_CMD: priv is NULL \n " ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
goto done ;
}
2007-12-08 20:04:36 +00:00
if ( priv - > surpriseremoved ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " PREP_CMD: card removed \n " ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
goto done ;
}
2009-10-06 19:20:28 -07:00
if ( ! lbs_is_cmd_allowed ( priv ) ) {
ret = - EBUSY ;
goto done ;
}
2007-12-05 17:58:06 +01:00
cmdnode = lbs_get_cmd_ctrl_node ( priv ) ;
2007-02-10 12:25:27 -02:00
if ( cmdnode = = NULL ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " PREP_CMD: cmdnode is NULL \n " ) ;
2007-02-10 12:25:27 -02:00
/* Wake up main thread to execute next command */
2007-08-02 11:32:25 -04:00
wake_up_interruptible ( & priv - > waitq ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
goto done ;
}
2008-03-19 14:25:58 +01:00
cmdnode - > callback = NULL ;
cmdnode - > callback_arg = ( unsigned long ) pdata_buf ;
2007-02-10 12:25:27 -02:00
2007-12-11 13:49:39 -05:00
cmdptr = ( struct cmd_ds_command * ) cmdnode - > cmdbuf ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " PREP_CMD: command 0x%04x \n " , cmd_no ) ;
2007-02-10 12:25:27 -02:00
/* Set sequence number, command and INT option */
2007-12-08 20:04:36 +00:00
priv - > seqnum + + ;
cmdptr - > seqnum = cpu_to_le16 ( priv - > seqnum ) ;
2007-02-10 12:25:27 -02:00
2007-05-25 23:36:54 -04:00
cmdptr - > command = cpu_to_le16 ( cmd_no ) ;
2007-02-10 12:25:27 -02:00
cmdptr - > result = 0 ;
switch ( cmd_no ) {
2007-08-02 11:31:18 -04:00
case CMD_802_11_PS_MODE :
2008-03-19 14:25:58 +01:00
ret = lbs_cmd_802_11_ps_mode ( cmdptr , cmd_action ) ;
2007-02-10 12:25:27 -02:00
break ;
2007-08-02 11:31:18 -04:00
case CMD_MAC_REG_ACCESS :
case CMD_BBP_REG_ACCESS :
case CMD_RF_REG_ACCESS :
2008-03-19 14:25:58 +01:00
ret = lbs_cmd_reg_access ( cmdptr , cmd_action , pdata_buf ) ;
2007-02-10 12:25:27 -02:00
break ;
2007-08-02 13:16:55 -04:00
case CMD_802_11_MONITOR_MODE :
2008-03-19 14:25:58 +01:00
ret = lbs_cmd_802_11_monitor_mode ( cmdptr ,
2007-08-02 13:16:55 -04:00
cmd_action , pdata_buf ) ;
break ;
2007-08-02 11:31:18 -04:00
case CMD_802_11_RSSI :
2007-11-15 18:05:47 -05:00
ret = lbs_cmd_802_11_rssi ( priv , cmdptr ) ;
2007-02-10 12:25:27 -02:00
break ;
2007-08-02 11:31:18 -04:00
case CMD_802_11_SET_AFC :
case CMD_802_11_GET_AFC :
2007-02-10 12:25:27 -02:00
cmdptr - > command = cpu_to_le16 ( cmd_no ) ;
2007-05-25 23:36:54 -04:00
cmdptr - > size = cpu_to_le16 ( sizeof ( struct cmd_ds_802_11_afc ) +
2009-10-22 15:30:55 +02:00
sizeof ( struct cmd_header ) ) ;
2007-02-10 12:25:27 -02:00
memmove ( & cmdptr - > params . afc ,
pdata_buf , sizeof ( struct cmd_ds_802_11_afc ) ) ;
ret = 0 ;
goto done ;
2007-08-02 11:31:18 -04:00
case CMD_802_11_TPC_CFG :
cmdptr - > command = cpu_to_le16 ( CMD_802_11_TPC_CFG ) ;
2007-02-10 12:25:27 -02:00
cmdptr - > size =
cpu_to_le16 ( sizeof ( struct cmd_ds_802_11_tpc_cfg ) +
2009-10-22 15:30:55 +02:00
sizeof ( struct cmd_header ) ) ;
2007-02-10 12:25:27 -02:00
memmove ( & cmdptr - > params . tpccfg ,
pdata_buf , sizeof ( struct cmd_ds_802_11_tpc_cfg ) ) ;
ret = 0 ;
break ;
2007-12-18 02:01:37 -05:00
2007-08-02 11:31:18 -04:00
case CMD_BT_ACCESS :
2008-03-19 14:25:58 +01:00
ret = lbs_cmd_bt_access ( cmdptr , cmd_action , pdata_buf ) ;
2007-02-10 12:25:27 -02:00
break ;
2007-08-02 11:31:18 -04:00
case CMD_FWT_ACCESS :
2008-03-19 14:25:58 +01:00
ret = lbs_cmd_fwt_access ( cmdptr , cmd_action , pdata_buf ) ;
2007-02-10 12:25:27 -02:00
break ;
2007-11-20 17:44:28 -05:00
case CMD_802_11_BEACON_CTRL :
ret = lbs_cmd_bcn_ctrl ( priv , cmdptr , cmd_action ) ;
break ;
2009-09-30 20:04:38 -07:00
case CMD_802_11_DEEP_SLEEP :
cmdptr - > command = cpu_to_le16 ( CMD_802_11_DEEP_SLEEP ) ;
2009-10-22 15:30:55 +02:00
cmdptr - > size = cpu_to_le16 ( sizeof ( struct cmd_header ) ) ;
2009-09-30 20:04:38 -07:00
break ;
2007-02-10 12:25:27 -02:00
default :
2008-05-20 11:47:16 +01:00
lbs_pr_err ( " PREP_CMD: unknown command 0x%04x \n " , cmd_no ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
break ;
}
/* return error, since the command preparation failed */
if ( ret ! = 0 ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " PREP_CMD: command preparation failed \n " ) ;
2007-11-15 18:05:47 -05:00
lbs_cleanup_and_insert_cmd ( priv , cmdnode ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
goto done ;
}
cmdnode - > cmdwaitqwoken = 0 ;
2007-12-15 20:04:54 -05:00
lbs_queue_cmd ( priv , cmdnode ) ;
2007-08-02 11:32:25 -04:00
wake_up_interruptible ( & priv - > waitq ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:31:18 -04:00
if ( wait_option & CMD_OPTION_WAITFORRSP ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " PREP_CMD: wait for response \n " ) ;
2007-02-10 12:25:27 -02:00
might_sleep ( ) ;
wait_event_interruptible ( cmdnode - > cmdwait_q ,
cmdnode - > cmdwaitqwoken ) ;
}
2007-12-08 20:04:36 +00:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
if ( priv - > cur_cmd_retcode ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " PREP_CMD: command failed with return code %d \n " ,
2007-12-08 20:04:36 +00:00
priv - > cur_cmd_retcode ) ;
priv - > cur_cmd_retcode = 0 ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
}
2007-12-08 20:04:36 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
done :
2007-08-02 11:54:31 -04:00
lbs_deb_leave_args ( LBS_DEB_HOST , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
/**
* @ brief This function allocates the command buffer and link
* it to command free queue .
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
* @ return 0 or - 1
*/
2007-11-23 15:43:44 +01:00
int lbs_allocate_cmd_buffer ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
int ret = 0 ;
2007-12-11 13:49:39 -05:00
u32 bufsize ;
2007-02-10 12:25:27 -02:00
u32 i ;
2007-12-11 13:49:39 -05:00
struct cmd_ctrl_node * cmdarray ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
2007-12-11 13:49:39 -05:00
/* Allocate and initialize the command array */
bufsize = sizeof ( struct cmd_ctrl_node ) * LBS_NUM_CMD_BUFFERS ;
if ( ! ( cmdarray = kzalloc ( bufsize , GFP_KERNEL ) ) ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " ALLOC_CMD_BUF: tempcmd_array is NULL \n " ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
goto done ;
}
2007-12-11 13:49:39 -05:00
priv - > cmd_array = cmdarray ;
2007-02-10 12:25:27 -02:00
2007-12-11 13:49:39 -05:00
/* Allocate and initialize each command buffer in the command array */
for ( i = 0 ; i < LBS_NUM_CMD_BUFFERS ; i + + ) {
cmdarray [ i ] . cmdbuf = kzalloc ( LBS_CMD_BUFFER_SIZE , GFP_KERNEL ) ;
if ( ! cmdarray [ i ] . cmdbuf ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " ALLOC_CMD_BUF: ptempvirtualaddr is NULL \n " ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
goto done ;
}
}
2007-12-11 13:49:39 -05:00
for ( i = 0 ; i < LBS_NUM_CMD_BUFFERS ; i + + ) {
init_waitqueue_head ( & cmdarray [ i ] . cmdwait_q ) ;
lbs_cleanup_and_insert_cmd ( priv , & cmdarray [ i ] ) ;
2007-02-10 12:25:27 -02:00
}
ret = 0 ;
2007-05-25 11:27:16 -04:00
done :
2007-08-02 11:54:31 -04:00
lbs_deb_leave_args ( LBS_DEB_HOST , " ret %d " , ret ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
/**
* @ brief This function frees the command buffer .
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
* @ return 0 or - 1
*/
2007-11-23 15:43:44 +01:00
int lbs_free_cmd_buffer ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
2007-12-11 13:49:39 -05:00
struct cmd_ctrl_node * cmdarray ;
2007-02-10 12:25:27 -02:00
unsigned int i ;
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
/* need to check if cmd array is allocated or not */
2007-12-08 20:04:36 +00:00
if ( priv - > cmd_array = = NULL ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " FREE_CMD_BUF: cmd_array is NULL \n " ) ;
2007-02-10 12:25:27 -02:00
goto done ;
}
2007-12-11 13:49:39 -05:00
cmdarray = priv - > cmd_array ;
2007-02-10 12:25:27 -02:00
/* Release shared memory buffers */
2007-12-11 13:49:39 -05:00
for ( i = 0 ; i < LBS_NUM_CMD_BUFFERS ; i + + ) {
if ( cmdarray [ i ] . cmdbuf ) {
kfree ( cmdarray [ i ] . cmdbuf ) ;
cmdarray [ i ] . cmdbuf = NULL ;
2007-02-10 12:25:27 -02:00
}
}
/* Release cmd_ctrl_node */
2007-12-08 20:04:36 +00:00
if ( priv - > cmd_array ) {
kfree ( priv - > cmd_array ) ;
priv - > cmd_array = NULL ;
2007-02-10 12:25:27 -02:00
}
done :
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
return 0 ;
}
/**
* @ brief This function gets a free command node if available in
* command free queue .
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
* @ return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
*/
2007-12-11 17:44:10 -05:00
static struct cmd_ctrl_node * lbs_get_cmd_ctrl_node ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
struct cmd_ctrl_node * tempnode ;
unsigned long flags ;
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-12-08 20:04:36 +00:00
if ( ! priv )
2007-02-10 12:25:27 -02:00
return NULL ;
2007-12-08 20:04:36 +00:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
if ( ! list_empty ( & priv - > cmdfreeq ) ) {
tempnode = list_first_entry ( & priv - > cmdfreeq ,
2007-12-06 13:01:21 +01:00
struct cmd_ctrl_node , list ) ;
list_del ( & tempnode - > list ) ;
2007-02-10 12:25:27 -02:00
} else {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " GET_CMD_NODE: cmd_ctrl_node is not available \n " ) ;
2007-02-10 12:25:27 -02:00
tempnode = NULL ;
}
2007-12-08 20:04:36 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
return tempnode ;
}
/**
* @ brief This function executes next command in command
2009-01-26 11:06:57 +01:00
* pending queue . It will put firmware back to PS mode
2007-02-10 12:25:27 -02:00
* if applicable .
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
* @ return 0 or - 1
*/
2007-11-23 15:43:44 +01:00
int lbs_execute_next_command ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
struct cmd_ctrl_node * cmdnode = NULL ;
2007-12-11 13:49:39 -05:00
struct cmd_header * cmd ;
2007-02-10 12:25:27 -02:00
unsigned long flags ;
int ret = 0 ;
2008-01-29 09:14:40 +01:00
/* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
* only caller to us is lbs_thread ( ) and we get even when a
* data packet is received */
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_THREAD ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
2007-12-08 20:04:36 +00:00
if ( priv - > cur_cmd ) {
2007-08-02 11:54:31 -04:00
lbs_pr_alert ( " EXEC_NEXT_CMD: already processing command! \n " ) ;
2007-12-08 20:04:36 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
goto done ;
}
2007-12-08 20:04:36 +00:00
if ( ! list_empty ( & priv - > cmdpendingq ) ) {
cmdnode = list_first_entry ( & priv - > cmdpendingq ,
2007-12-06 13:01:21 +01:00
struct cmd_ctrl_node , list ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-08 20:04:36 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
if ( cmdnode ) {
2007-12-11 13:49:39 -05:00
cmd = cmdnode - > cmdbuf ;
2007-02-10 12:25:27 -02:00
2007-12-11 13:49:39 -05:00
if ( is_command_allowed_in_ps ( le16_to_cpu ( cmd - > command ) ) ) {
2007-12-08 20:04:36 +00:00
if ( ( priv - > psstate = = PS_STATE_SLEEP ) | |
( priv - > psstate = = PS_STATE_PRE_SLEEP ) ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host (
" EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d \n " ,
2007-12-11 13:49:39 -05:00
le16_to_cpu ( cmd - > command ) ,
2007-12-08 20:04:36 +00:00
priv - > psstate ) ;
2007-02-10 12:25:27 -02:00
ret = - 1 ;
goto done ;
}
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " EXEC_NEXT_CMD: OK to send command "
2007-12-11 13:49:39 -05:00
" 0x%04x in psstate %d \n " ,
le16_to_cpu ( cmd - > command ) , priv - > psstate ) ;
2007-12-08 20:04:36 +00:00
} else if ( priv - > psstate ! = PS_STATE_FULL_POWER ) {
2007-02-10 12:25:27 -02:00
/*
* 1. Non - PS command :
* Queue it . set needtowakeup to TRUE if current state
2007-11-15 18:05:47 -05:00
* is SLEEP , otherwise call lbs_ps_wakeup to send Exit_PS .
2007-02-10 12:25:27 -02:00
* 2. PS command but not Exit_PS :
* Ignore it .
* 3. PS command Exit_PS :
* Set needtowakeup to TRUE if current state is SLEEP ,
* otherwise send this command down to firmware
* immediately .
*/
2007-12-11 13:49:39 -05:00
if ( cmd - > command ! = cpu_to_le16 ( CMD_802_11_PS_MODE ) ) {
2007-02-10 12:25:27 -02:00
/* Prepare to send Exit PS,
* this non PS command will be sent later */
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
) {
/* w/ new scheme, it will not reach here.
since it is blocked in main_thread . */
2007-12-08 20:04:36 +00:00
priv - > needtowakeup = 1 ;
2007-02-10 12:25:27 -02:00
} else
2007-11-15 18:05:47 -05:00
lbs_ps_wakeup ( priv , 0 ) ;
2007-02-10 12:25:27 -02:00
ret = 0 ;
goto done ;
} else {
/*
* PS command . Ignore it if it is not Exit_PS .
* otherwise send it down immediately .
*/
2007-12-16 23:26:54 -05:00
struct cmd_ds_802_11_ps_mode * psm = ( void * ) & cmd [ 1 ] ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_host (
" EXEC_NEXT_CMD: PS cmd, action 0x%02x \n " ,
2007-02-10 12:25:27 -02:00
psm - > action ) ;
if ( psm - > action ! =
2007-08-02 11:31:18 -04:00
cpu_to_le16 ( CMD_SUBCMD_EXIT_PS ) ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host (
" EXEC_NEXT_CMD: ignore ENTER_PS cmd \n " ) ;
2007-12-06 13:01:21 +01:00
list_del ( & cmdnode - > list ) ;
2007-12-15 01:52:54 -05:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
lbs_complete_command ( priv , cmdnode , 0 ) ;
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
ret = 0 ;
goto done ;
}
2007-12-08 20:04:36 +00:00
if ( ( priv - > psstate = = PS_STATE_SLEEP ) | |
( priv - > psstate = = PS_STATE_PRE_SLEEP ) ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host (
" EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep \n " ) ;
2007-12-06 13:01:21 +01:00
list_del ( & cmdnode - > list ) ;
2007-12-15 01:52:54 -05:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
lbs_complete_command ( priv , cmdnode , 0 ) ;
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-12-08 20:04:36 +00:00
priv - > needtowakeup = 1 ;
2007-02-10 12:25:27 -02:00
ret = 0 ;
goto done ;
}
2007-08-02 11:54:31 -04:00
lbs_deb_host (
" EXEC_NEXT_CMD: sending EXIT_PS \n " ) ;
2007-02-10 12:25:27 -02:00
}
}
2007-12-06 13:01:21 +01:00
list_del ( & cmdnode - > list ) ;
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " EXEC_NEXT_CMD: sending command 0x%04x \n " ,
2007-12-11 13:49:39 -05:00
le16_to_cpu ( cmd - > command ) ) ;
2007-12-15 00:09:25 -05:00
lbs_submit_command ( priv , cmdnode ) ;
2007-02-10 12:25:27 -02:00
} else {
/*
* check if in power save mode , if yes , put the device back
* to PS mode
*/
2007-12-08 20:04:36 +00:00
if ( ( priv - > psmode ! = LBS802_11POWERMODECAM ) & &
( priv - > psstate = = PS_STATE_FULL_POWER ) & &
( ( priv - > connect_status = = LBS_CONNECTED ) | |
( priv - > mesh_connect_status = = LBS_CONNECTED ) ) ) {
if ( priv - > secinfo . WPAenabled | |
priv - > secinfo . WPA2enabled ) {
2007-02-10 12:25:27 -02:00
/* check for valid WPA group keys */
2007-12-08 20:04:36 +00:00
if ( priv - > wpa_mcast_key . len | |
priv - > wpa_unicast_key . len ) {
2007-08-02 11:54:31 -04:00
lbs_deb_host (
2007-02-10 12:25:27 -02:00
" EXEC_NEXT_CMD: WPA enabled and GTK_SET "
" go back to PS_SLEEP " ) ;
2007-11-15 18:05:47 -05:00
lbs_ps_sleep ( priv , 0 ) ;
2007-02-10 12:25:27 -02:00
}
} else {
2007-08-02 11:54:31 -04:00
lbs_deb_host (
" EXEC_NEXT_CMD: cmdpendingq empty, "
" go back to PS_SLEEP " ) ;
2007-11-15 18:05:47 -05:00
lbs_ps_sleep ( priv , 0 ) ;
2007-02-10 12:25:27 -02:00
}
}
}
ret = 0 ;
done :
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_THREAD ) ;
2007-02-10 12:25:27 -02:00
return ret ;
}
2008-03-26 13:22:11 +01:00
static void lbs_send_confirmsleep ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
unsigned long flags ;
2008-03-26 13:22:11 +01:00
int ret ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2008-03-26 13:22:11 +01:00
lbs_deb_hex ( LBS_DEB_HOST , " sleep confirm " , ( u8 * ) & confirm_sleep ,
sizeof ( confirm_sleep ) ) ;
2007-02-10 12:25:27 -02:00
2008-03-26 13:22:11 +01:00
ret = priv - > hw_host_to_card ( priv , MVMS_CMD , ( u8 * ) & confirm_sleep ,
sizeof ( confirm_sleep ) ) ;
2007-02-10 12:25:27 -02:00
if ( ret ) {
2008-03-26 13:22:11 +01:00
lbs_pr_alert ( " confirm_sleep failed \n " ) ;
2008-04-01 14:50:43 +02:00
goto out ;
2007-02-10 12:25:27 -02:00
}
2008-04-01 14:50:43 +02:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
2008-06-04 11:10:40 +02:00
/* We don't get a response on the sleep-confirmation */
priv - > dnld_sent = DNLD_RES_RECEIVED ;
2008-04-01 14:50:43 +02:00
/* If nothing to do, go back to sleep (?) */
if ( ! __kfifo_len ( priv - > event_fifo ) & & ! priv - > resp_len [ priv - > resp_idx ] )
priv - > psstate = PS_STATE_SLEEP ;
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
out :
2008-03-26 13:22:11 +01:00
lbs_deb_leave ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
}
2007-11-23 15:43:44 +01:00
void lbs_ps_sleep ( struct lbs_private * priv , int wait_option )
2007-02-10 12:25:27 -02:00
{
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
/*
* PS is currently supported only in Infrastructure mode
* Remove this check if it is to be supported in IBSS mode also
*/
2007-11-15 18:05:47 -05:00
lbs_prepare_and_send_command ( priv , CMD_802_11_PS_MODE ,
2007-08-02 11:31:18 -04:00
CMD_SUBCMD_ENTER_PS , wait_option , 0 , NULL ) ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
}
/**
2007-08-02 11:54:31 -04:00
* @ brief This function sends Exit_PS command to firmware .
2007-02-10 12:25:27 -02:00
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
* @ param wait_option wait response or not
* @ return n / a
*/
2007-11-23 15:43:44 +01:00
void lbs_ps_wakeup ( struct lbs_private * priv , int wait_option )
2007-02-10 12:25:27 -02:00
{
2007-05-25 23:36:54 -04:00
__le32 Localpsmode ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
Localpsmode = cpu_to_le32 ( LBS802_11POWERMODECAM ) ;
2007-02-10 12:25:27 -02:00
2007-11-15 18:05:47 -05:00
lbs_prepare_and_send_command ( priv , CMD_802_11_PS_MODE ,
2007-08-02 11:31:18 -04:00
CMD_SUBCMD_EXIT_PS ,
2007-02-10 12:25:27 -02:00
wait_option , 0 , & Localpsmode ) ;
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
}
/**
* @ brief This function checks condition and prepares to
* send sleep confirm command to firmware if ok .
*
2007-11-23 15:43:44 +01:00
* @ param priv A pointer to struct lbs_private structure
2007-02-10 12:25:27 -02:00
* @ param psmode Power Saving mode
* @ return n / a
*/
2008-03-19 14:25:18 +01:00
void lbs_ps_confirm_sleep ( struct lbs_private * priv )
2007-02-10 12:25:27 -02:00
{
unsigned long flags = 0 ;
2008-03-19 14:25:18 +01:00
int allowed = 1 ;
2007-02-10 12:25:27 -02:00
2007-08-02 11:54:31 -04:00
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
2008-06-04 11:10:40 +02:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
2007-05-25 13:05:16 -04:00
if ( priv - > dnld_sent ) {
2007-02-10 12:25:27 -02:00
allowed = 0 ;
2007-12-12 00:14:21 -05:00
lbs_deb_host ( " dnld_sent was set \n " ) ;
2007-02-10 12:25:27 -02:00
}
2008-04-01 14:50:43 +02:00
/* In-progress command? */
2007-12-08 20:04:36 +00:00
if ( priv - > cur_cmd ) {
2007-02-10 12:25:27 -02:00
allowed = 0 ;
2007-12-12 00:14:21 -05:00
lbs_deb_host ( " cur_cmd was set \n " ) ;
2007-02-10 12:25:27 -02:00
}
2008-04-01 14:50:43 +02:00
/* Pending events or command responses? */
if ( __kfifo_len ( priv - > event_fifo ) | | priv - > resp_len [ priv - > resp_idx ] ) {
2007-02-10 12:25:27 -02:00
allowed = 0 ;
2008-04-01 14:50:43 +02:00
lbs_deb_host ( " pending events or command responses \n " ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-08 20:04:36 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-02-10 12:25:27 -02:00
if ( allowed ) {
2007-11-15 18:05:47 -05:00
lbs_deb_host ( " sending lbs_ps_confirm_sleep \n " ) ;
2008-03-26 13:22:11 +01:00
lbs_send_confirmsleep ( priv ) ;
2007-02-10 12:25:27 -02:00
} else {
2007-08-02 11:54:31 -04:00
lbs_deb_host ( " sleep confirm has been delayed \n " ) ;
2007-02-10 12:25:27 -02:00
}
2007-08-02 11:54:31 -04:00
lbs_deb_leave ( LBS_DEB_HOST ) ;
2007-02-10 12:25:27 -02:00
}
2007-12-05 17:58:11 +01:00
2008-09-11 11:17:25 -07:00
/**
* @ brief Configures the transmission power control functionality .
*
* @ param priv A pointer to struct lbs_private structure
* @ param enable Transmission power control enable
* @ param p0 Power level when link quality is good ( dBm ) .
* @ param p1 Power level when link quality is fair ( dBm ) .
* @ param p2 Power level when link quality is poor ( dBm ) .
* @ param usesnr Use Signal to Noise Ratio in TPC
*
* @ return 0 on success
*/
int lbs_set_tpc_cfg ( struct lbs_private * priv , int enable , int8_t p0 , int8_t p1 ,
int8_t p2 , int usesnr )
{
struct cmd_ds_802_11_tpc_cfg cmd ;
int ret ;
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( CMD_ACT_SET ) ;
cmd . enable = ! ! enable ;
2008-09-26 11:34:35 -04:00
cmd . usesnr = ! ! usesnr ;
2008-09-11 11:17:25 -07:00
cmd . P0 = p0 ;
cmd . P1 = p1 ;
cmd . P2 = p2 ;
ret = lbs_cmd_with_response ( priv , CMD_802_11_TPC_CFG , & cmd ) ;
return ret ;
}
/**
* @ brief Configures the power adaptation settings .
*
* @ param priv A pointer to struct lbs_private structure
* @ param enable Power adaptation enable
* @ param p0 Power level for 1 , 2 , 5.5 and 11 Mbps ( dBm ) .
* @ param p1 Power level for 6 , 9 , 12 , 18 , 22 , 24 and 36 Mbps ( dBm ) .
* @ param p2 Power level for 48 and 54 Mbps ( dBm ) .
*
* @ return 0 on Success
*/
int lbs_set_power_adapt_cfg ( struct lbs_private * priv , int enable , int8_t p0 ,
int8_t p1 , int8_t p2 )
{
struct cmd_ds_802_11_pa_cfg cmd ;
int ret ;
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
cmd . hdr . size = cpu_to_le16 ( sizeof ( cmd ) ) ;
cmd . action = cpu_to_le16 ( CMD_ACT_SET ) ;
cmd . enable = ! ! enable ;
cmd . P0 = p0 ;
cmd . P1 = p1 ;
cmd . P2 = p2 ;
ret = lbs_cmd_with_response ( priv , CMD_802_11_PA_CFG , & cmd ) ;
return ret ;
}
2009-10-14 16:49:53 +02:00
struct cmd_ctrl_node * __lbs_cmd_async ( struct lbs_private * priv ,
2008-03-19 10:11:00 +01:00
uint16_t command , struct cmd_header * in_cmd , int in_cmd_size ,
int ( * callback ) ( struct lbs_private * , unsigned long , struct cmd_header * ) ,
unsigned long callback_arg )
2007-12-05 17:58:11 +01:00
{
struct cmd_ctrl_node * cmdnode ;
lbs_deb_enter ( LBS_DEB_HOST ) ;
2007-12-08 20:04:36 +00:00
if ( priv - > surpriseremoved ) {
2007-12-05 17:58:11 +01:00
lbs_deb_host ( " PREP_CMD: card removed \n " ) ;
2007-12-15 03:09:33 -05:00
cmdnode = ERR_PTR ( - ENOENT ) ;
2007-12-05 17:58:11 +01:00
goto done ;
}
2009-10-06 19:20:28 -07:00
if ( ! lbs_is_cmd_allowed ( priv ) ) {
cmdnode = ERR_PTR ( - EBUSY ) ;
goto done ;
}
2007-12-05 17:58:11 +01:00
cmdnode = lbs_get_cmd_ctrl_node ( priv ) ;
if ( cmdnode = = NULL ) {
lbs_deb_host ( " PREP_CMD: cmdnode is NULL \n " ) ;
/* Wake up main thread to execute next command */
wake_up_interruptible ( & priv - > waitq ) ;
2007-12-15 03:09:33 -05:00
cmdnode = ERR_PTR ( - ENOBUFS ) ;
2007-12-05 17:58:11 +01:00
goto done ;
}
2007-12-08 00:59:54 +00:00
cmdnode - > callback = callback ;
2007-12-10 13:36:10 -05:00
cmdnode - > callback_arg = callback_arg ;
2007-12-05 17:58:11 +01:00
2007-12-11 12:33:30 -05:00
/* Copy the incoming command to the buffer */
2007-12-11 13:49:39 -05:00
memcpy ( cmdnode - > cmdbuf , in_cmd , in_cmd_size ) ;
2007-12-11 12:33:30 -05:00
2007-12-05 17:58:11 +01:00
/* Set sequence number, clean result, move to buffer */
2007-12-08 20:04:36 +00:00
priv - > seqnum + + ;
2007-12-11 13:49:39 -05:00
cmdnode - > cmdbuf - > command = cpu_to_le16 ( command ) ;
cmdnode - > cmdbuf - > size = cpu_to_le16 ( in_cmd_size ) ;
cmdnode - > cmdbuf - > seqnum = cpu_to_le16 ( priv - > seqnum ) ;
cmdnode - > cmdbuf - > result = 0 ;
2007-12-05 17:58:11 +01:00
lbs_deb_host ( " PREP_CMD: command 0x%04x \n " , command ) ;
cmdnode - > cmdwaitqwoken = 0 ;
2007-12-15 20:04:54 -05:00
lbs_queue_cmd ( priv , cmdnode ) ;
2007-12-05 17:58:11 +01:00
wake_up_interruptible ( & priv - > waitq ) ;
2007-12-15 03:09:33 -05:00
done :
lbs_deb_leave_args ( LBS_DEB_HOST , " ret %p " , cmdnode ) ;
return cmdnode ;
}
2008-03-19 10:11:00 +01:00
void lbs_cmd_async ( struct lbs_private * priv , uint16_t command ,
struct cmd_header * in_cmd , int in_cmd_size )
{
lbs_deb_enter ( LBS_DEB_CMD ) ;
__lbs_cmd_async ( priv , command , in_cmd , in_cmd_size ,
lbs_cmd_async_callback , 0 ) ;
lbs_deb_leave ( LBS_DEB_CMD ) ;
}
2007-12-15 03:09:33 -05:00
int __lbs_cmd ( struct lbs_private * priv , uint16_t command ,
struct cmd_header * in_cmd , int in_cmd_size ,
int ( * callback ) ( struct lbs_private * , unsigned long , struct cmd_header * ) ,
unsigned long callback_arg )
{
struct cmd_ctrl_node * cmdnode ;
unsigned long flags ;
int ret = 0 ;
lbs_deb_enter ( LBS_DEB_HOST ) ;
cmdnode = __lbs_cmd_async ( priv , command , in_cmd , in_cmd_size ,
callback , callback_arg ) ;
if ( IS_ERR ( cmdnode ) ) {
ret = PTR_ERR ( cmdnode ) ;
goto done ;
}
2007-12-05 17:58:11 +01:00
might_sleep ( ) ;
wait_event_interruptible ( cmdnode - > cmdwait_q , cmdnode - > cmdwaitqwoken ) ;
2007-12-08 20:04:36 +00:00
spin_lock_irqsave ( & priv - > driver_lock , flags ) ;
2007-12-15 04:22:52 -05:00
ret = cmdnode - > result ;
if ( ret )
lbs_pr_info ( " PREP_CMD: command 0x%04x failed: %d \n " ,
command , ret ) ;
2007-12-15 03:09:33 -05:00
2007-12-15 02:06:16 -05:00
__lbs_cleanup_and_insert_cmd ( priv , cmdnode ) ;
2007-12-08 20:04:36 +00:00
spin_unlock_irqrestore ( & priv - > driver_lock , flags ) ;
2007-12-05 17:58:11 +01:00
done :
lbs_deb_leave_args ( LBS_DEB_HOST , " ret %d " , ret ) ;
return ret ;
}
2007-12-10 15:11:23 -05:00
EXPORT_SYMBOL_GPL ( __lbs_cmd ) ;