2009-06-12 14:17:19 +03:00
# include "wl1251_cmd.h"
2009-04-29 23:33:31 +03:00
# include <linux/module.h>
# include <linux/crc7.h>
2009-06-12 14:17:25 +03:00
# include "wl1251.h"
2009-04-29 23:33:31 +03:00
# include "reg.h"
2009-08-07 13:32:56 +03:00
# include "wl1251_io.h"
2009-06-12 14:17:19 +03:00
# include "wl1251_ps.h"
# include "wl1251_acx.h"
2009-06-12 14:14:19 +03:00
/**
* send command to firmware
*
* @ wl : wl struct
* @ id : command id
* @ buf : buffer containing the command , must work with dma
* @ len : length of the buffer
*/
2009-06-12 14:17:39 +03:00
int wl1251_cmd_send ( struct wl1251 * wl , u16 id , void * buf , size_t len )
2009-04-29 23:33:31 +03:00
{
2009-06-12 14:17:39 +03:00
struct wl1251_cmd_header * cmd ;
2009-04-29 23:33:31 +03:00
unsigned long timeout ;
u32 intr ;
int ret = 0 ;
2009-06-12 14:14:19 +03:00
cmd = buf ;
cmd - > id = id ;
cmd - > status = 0 ;
WARN_ON ( len % 4 ! = 0 ) ;
2009-04-29 23:33:31 +03:00
2009-08-07 13:32:56 +03:00
wl1251_mem_write ( wl , wl - > cmd_box_addr , buf , len ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
wl1251_reg_write32 ( wl , ACX_REG_INTERRUPT_TRIG , INTR_TRIG_CMD ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
timeout = jiffies + msecs_to_jiffies ( WL1251_COMMAND_TIMEOUT ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
intr = wl1251_reg_read32 ( wl , ACX_REG_INTERRUPT_NO_CLEAR ) ;
2009-08-07 13:33:57 +03:00
while ( ! ( intr & WL1251_ACX_INTR_CMD_COMPLETE ) ) {
2009-04-29 23:33:31 +03:00
if ( time_after ( jiffies , timeout ) ) {
2009-06-12 14:17:39 +03:00
wl1251_error ( " command complete timeout " ) ;
2009-04-29 23:33:31 +03:00
ret = - ETIMEDOUT ;
goto out ;
}
msleep ( 1 ) ;
2009-06-12 14:17:39 +03:00
intr = wl1251_reg_read32 ( wl , ACX_REG_INTERRUPT_NO_CLEAR ) ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:17:39 +03:00
wl1251_reg_write32 ( wl , ACX_REG_INTERRUPT_ACK ,
2009-08-07 13:33:57 +03:00
WL1251_ACX_INTR_CMD_COMPLETE ) ;
2009-04-29 23:33:31 +03:00
out :
return ret ;
}
2009-06-12 14:14:19 +03:00
/**
* send test command to firmware
*
* @ wl : wl struct
2009-06-12 14:16:13 +03:00
* @ buf : buffer containing the command , with all headers , must work with dma
2009-06-12 14:14:19 +03:00
* @ len : length of the buffer
* @ answer : is answer needed
*/
2009-06-12 14:17:39 +03:00
int wl1251_cmd_test ( struct wl1251 * wl , void * buf , size_t buf_len , u8 answer )
2009-04-29 23:33:31 +03:00
{
int ret ;
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_CMD , " cmd test " ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , CMD_TEST , buf , buf_len ) ;
2009-06-12 14:14:19 +03:00
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_warning ( " TEST command failed " ) ;
2009-06-12 14:16:13 +03:00
return ret ;
2009-04-29 23:33:31 +03:00
}
if ( answer ) {
2009-06-12 14:17:39 +03:00
struct wl1251_command * cmd_answer ;
2009-06-12 14:16:13 +03:00
2009-04-29 23:33:31 +03:00
/*
* The test command got in , we can read the answer .
2009-06-12 14:17:39 +03:00
* The answer would be a wl1251_command , where the
2009-04-29 23:33:31 +03:00
* parameter array contains the actual answer .
*/
2009-08-07 13:32:56 +03:00
wl1251_mem_read ( wl , wl - > cmd_box_addr , buf , buf_len ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:16:13 +03:00
cmd_answer = buf ;
if ( cmd_answer - > header . status ! = CMD_STATUS_SUCCESS )
2009-06-12 14:17:39 +03:00
wl1251_error ( " TEST command answer error: %d " ,
2009-06-12 14:16:13 +03:00
cmd_answer - > header . status ) ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:16:13 +03:00
return 0 ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:14:19 +03:00
/**
* read acx from firmware
*
* @ wl : wl struct
* @ id : acx id
* @ buf : buffer for the response , including all headers , must work with dma
* @ len : lenght of buf
*/
2009-06-12 14:17:39 +03:00
int wl1251_cmd_interrogate ( struct wl1251 * wl , u16 id , void * buf , size_t len )
2009-04-29 23:33:31 +03:00
{
2009-06-12 14:14:19 +03:00
struct acx_header * acx = buf ;
2009-04-29 23:33:31 +03:00
int ret ;
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_CMD , " cmd interrogate " ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
acx - > id = id ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
/* payload length, does not include any headers */
acx - > len = len - sizeof ( * acx ) ;
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , CMD_INTERROGATE , acx , sizeof ( * acx ) ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_error ( " INTERROGATE command failed " ) ;
2009-06-12 14:14:19 +03:00
goto out ;
2009-04-29 23:33:31 +03:00
}
/* the interrogate command got in, we can read the answer */
2009-08-07 13:32:56 +03:00
wl1251_mem_read ( wl , wl - > cmd_box_addr , buf , len ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
acx = buf ;
if ( acx - > cmd . status ! = CMD_STATUS_SUCCESS )
2009-06-12 14:17:39 +03:00
wl1251_error ( " INTERROGATE command error: %d " ,
2009-06-12 14:14:19 +03:00
acx - > cmd . status ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
out :
return ret ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:14:19 +03:00
/**
* write acx value to firmware
*
* @ wl : wl struct
* @ id : acx id
* @ buf : buffer containing acx , including all headers , must work with dma
* @ len : length of buf
*/
2009-06-12 14:17:39 +03:00
int wl1251_cmd_configure ( struct wl1251 * wl , u16 id , void * buf , size_t len )
2009-04-29 23:33:31 +03:00
{
2009-06-12 14:14:19 +03:00
struct acx_header * acx = buf ;
2009-04-29 23:33:31 +03:00
int ret ;
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_CMD , " cmd configure " ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
acx - > id = id ;
/* payload length, does not include any headers */
acx - > len = len - sizeof ( * acx ) ;
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , CMD_CONFIGURE , acx , len ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_warning ( " CONFIGURE command NOK " ) ;
2009-04-29 23:33:31 +03:00
return ret ;
}
return 0 ;
}
2009-06-12 14:17:39 +03:00
int wl1251_cmd_vbm ( struct wl1251 * wl , u8 identity ,
2009-04-29 23:33:31 +03:00
void * bitmap , u16 bitmap_len , u8 bitmap_control )
{
2009-06-12 14:17:39 +03:00
struct wl1251_cmd_vbm_update * vbm ;
2009-04-29 23:33:31 +03:00
int ret ;
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_CMD , " cmd vbm " ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
vbm = kzalloc ( sizeof ( * vbm ) , GFP_KERNEL ) ;
if ( ! vbm ) {
ret = - ENOMEM ;
goto out ;
}
2009-04-29 23:33:31 +03:00
/* Count and period will be filled by the target */
2009-06-12 14:14:19 +03:00
vbm - > tim . bitmap_ctrl = bitmap_control ;
2009-04-29 23:33:31 +03:00
if ( bitmap_len > PARTIAL_VBM_MAX ) {
2009-06-12 14:17:39 +03:00
wl1251_warning ( " cmd vbm len is %d B, truncating to %d " ,
2009-04-29 23:33:31 +03:00
bitmap_len , PARTIAL_VBM_MAX ) ;
bitmap_len = PARTIAL_VBM_MAX ;
}
2009-06-12 14:14:19 +03:00
memcpy ( vbm - > tim . pvb_field , bitmap , bitmap_len ) ;
vbm - > tim . identity = identity ;
vbm - > tim . length = bitmap_len + 3 ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
vbm - > len = cpu_to_le16 ( bitmap_len + 5 ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , CMD_VBM , vbm , sizeof ( * vbm ) ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_error ( " VBM command failed " ) ;
2009-06-12 14:14:19 +03:00
goto out ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:14:19 +03:00
out :
kfree ( vbm ) ;
2009-04-29 23:33:31 +03:00
return 0 ;
}
2009-06-12 14:17:39 +03:00
int wl1251_cmd_data_path ( struct wl1251 * wl , u8 channel , bool enable )
2009-04-29 23:33:31 +03:00
{
2009-06-12 14:14:19 +03:00
struct cmd_enabledisable_path * cmd ;
2009-04-29 23:33:31 +03:00
int ret ;
u16 cmd_rx , cmd_tx ;
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_CMD , " cmd data path " ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
cmd = kzalloc ( sizeof ( * cmd ) , GFP_KERNEL ) ;
if ( ! cmd ) {
ret = - ENOMEM ;
goto out ;
}
cmd - > channel = channel ;
2009-04-29 23:33:31 +03:00
if ( enable ) {
cmd_rx = CMD_ENABLE_RX ;
cmd_tx = CMD_ENABLE_TX ;
} else {
cmd_rx = CMD_DISABLE_RX ;
cmd_tx = CMD_DISABLE_TX ;
}
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , cmd_rx , cmd , sizeof ( * cmd ) ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_error ( " rx %s cmd for channel %d failed " ,
2009-04-29 23:33:31 +03:00
enable ? " start " : " stop " , channel ) ;
2009-06-12 14:14:19 +03:00
goto out ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_BOOT , " rx %s cmd channel %d " ,
2009-04-29 23:33:31 +03:00
enable ? " start " : " stop " , channel ) ;
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , cmd_tx , cmd , sizeof ( * cmd ) ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_error ( " tx %s cmd for channel %d failed " ,
2009-04-29 23:33:31 +03:00
enable ? " start " : " stop " , channel ) ;
return ret ;
}
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_BOOT , " tx %s cmd channel %d " ,
2009-04-29 23:33:31 +03:00
enable ? " start " : " stop " , channel ) ;
2009-06-12 14:14:19 +03:00
out :
kfree ( cmd ) ;
return ret ;
2009-04-29 23:33:31 +03:00
}
2009-08-07 13:34:05 +03:00
int wl1251_cmd_join ( struct wl1251 * wl , u8 bss_type , u16 beacon_interval ,
u8 dtim_interval , bool wait )
2009-04-29 23:33:31 +03:00
{
unsigned long timeout ;
2009-06-12 14:14:19 +03:00
struct cmd_join * join ;
2009-04-29 23:33:31 +03:00
int ret , i ;
u8 * bssid ;
2009-06-12 14:14:19 +03:00
join = kzalloc ( sizeof ( * join ) , GFP_KERNEL ) ;
if ( ! join ) {
ret = - ENOMEM ;
goto out ;
}
2009-04-29 23:33:31 +03:00
/* FIXME: this should be in main.c */
2009-06-12 14:17:39 +03:00
ret = wl1251_acx_frame_rates ( wl , DEFAULT_HW_GEN_TX_RATE ,
2009-04-29 23:33:31 +03:00
DEFAULT_HW_GEN_MODULATION_TYPE ,
wl - > tx_mgmt_frm_rate ,
wl - > tx_mgmt_frm_mod ) ;
if ( ret < 0 )
2009-06-12 14:14:19 +03:00
goto out ;
2009-04-29 23:33:31 +03:00
2009-08-07 13:34:12 +03:00
wl1251_debug ( DEBUG_CMD , " cmd join%s %d %d%s " ,
bss_type = = BSS_TYPE_IBSS ? " ibss " : " " ,
beacon_interval , dtim_interval ,
wait ? " wait " : " " ) ;
2009-04-29 23:33:31 +03:00
/* Reverse order BSSID */
2009-06-12 14:14:19 +03:00
bssid = ( u8 * ) & join - > bssid_lsb ;
2009-04-29 23:33:31 +03:00
for ( i = 0 ; i < ETH_ALEN ; i + + )
bssid [ i ] = wl - > bssid [ ETH_ALEN - i - 1 ] ;
2009-06-12 14:14:19 +03:00
join - > rx_config_options = wl - > rx_config ;
join - > rx_filter_options = wl - > rx_filter ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
join - > basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
2009-04-29 23:33:31 +03:00
RATE_MASK_5_5MBPS | RATE_MASK_11MBPS ;
2009-06-12 14:14:19 +03:00
join - > beacon_interval = beacon_interval ;
join - > dtim_interval = dtim_interval ;
join - > bss_type = bss_type ;
join - > channel = wl - > channel ;
join - > ctrl = JOIN_CMD_CTRL_TX_FLUSH ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , CMD_START_JOIN , join , sizeof ( * join ) ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_error ( " failed to initiate cmd join " ) ;
2009-06-12 14:14:19 +03:00
goto out ;
2009-04-29 23:33:31 +03:00
}
timeout = msecs_to_jiffies ( JOIN_TIMEOUT ) ;
/*
* ugly hack : we should wait for JOIN_EVENT_COMPLETE_ID but to
* simplify locking we just sleep instead , for now
*/
if ( wait )
msleep ( 10 ) ;
2009-06-12 14:14:19 +03:00
out :
kfree ( join ) ;
return ret ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:17:39 +03:00
int wl1251_cmd_ps_mode ( struct wl1251 * wl , u8 ps_mode )
2009-04-29 23:33:31 +03:00
{
2009-06-12 14:17:39 +03:00
struct wl1251_cmd_ps_params * ps_params = NULL ;
2009-06-12 14:14:19 +03:00
int ret = 0 ;
2009-04-29 23:33:31 +03:00
/* FIXME: this should be in ps.c */
2009-06-12 14:17:39 +03:00
ret = wl1251_acx_wake_up_conditions ( wl , WAKE_UP_EVENT_DTIM_BITMAP ,
2009-06-12 14:15:46 +03:00
wl - > listen_int ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_error ( " couldn't set wake up conditions " ) ;
2009-06-12 14:14:19 +03:00
goto out ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_CMD , " cmd set ps mode " ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
ps_params = kzalloc ( sizeof ( * ps_params ) , GFP_KERNEL ) ;
if ( ! ps_params ) {
ret = - ENOMEM ;
goto out ;
}
ps_params - > ps_mode = ps_mode ;
ps_params - > send_null_data = 1 ;
ps_params - > retries = 5 ;
ps_params - > hang_over_period = 128 ;
ps_params - > null_data_rate = 1 ; /* 1 Mbps */
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , CMD_SET_PS_MODE , ps_params ,
2009-06-12 14:14:19 +03:00
sizeof ( * ps_params ) ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_error ( " cmd set_ps_mode failed " ) ;
2009-06-12 14:14:19 +03:00
goto out ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:14:19 +03:00
out :
kfree ( ps_params ) ;
return ret ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:17:39 +03:00
int wl1251_cmd_read_memory ( struct wl1251 * wl , u32 addr , void * answer ,
2009-06-12 14:14:19 +03:00
size_t len )
2009-04-29 23:33:31 +03:00
{
2009-06-12 14:14:19 +03:00
struct cmd_read_write_memory * cmd ;
int ret = 0 ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_CMD , " cmd read memory " ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
cmd = kzalloc ( sizeof ( * cmd ) , GFP_KERNEL ) ;
if ( ! cmd ) {
ret = - ENOMEM ;
goto out ;
}
WARN_ON ( len > MAX_READ_SIZE ) ;
len = min_t ( size_t , len , MAX_READ_SIZE ) ;
cmd - > addr = addr ;
cmd - > size = len ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , CMD_READ_MEMORY , cmd , sizeof ( * cmd ) ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_error ( " read memory command failed: %d " , ret ) ;
2009-06-12 14:14:19 +03:00
goto out ;
2009-04-29 23:33:31 +03:00
}
/* the read command got in, we can now read the answer */
2009-08-07 13:32:56 +03:00
wl1251_mem_read ( wl , wl - > cmd_box_addr , cmd , sizeof ( * cmd ) ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
if ( cmd - > header . status ! = CMD_STATUS_SUCCESS )
2009-06-12 14:17:39 +03:00
wl1251_error ( " error in read command result: %d " ,
2009-06-12 14:14:19 +03:00
cmd - > header . status ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
memcpy ( answer , cmd - > value , len ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:14:19 +03:00
out :
kfree ( cmd ) ;
return ret ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:17:39 +03:00
int wl1251_cmd_template_set ( struct wl1251 * wl , u16 cmd_id ,
2009-04-29 23:33:31 +03:00
void * buf , size_t buf_len )
{
2009-06-12 14:17:39 +03:00
struct wl1251_cmd_packet_template * cmd ;
2009-06-12 14:14:19 +03:00
size_t cmd_len ;
int ret = 0 ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
wl1251_debug ( DEBUG_CMD , " cmd template %d " , cmd_id ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
WARN_ON ( buf_len > WL1251_MAX_TEMPLATE_SIZE ) ;
buf_len = min_t ( size_t , buf_len , WL1251_MAX_TEMPLATE_SIZE ) ;
2009-06-12 14:14:19 +03:00
cmd_len = ALIGN ( sizeof ( * cmd ) + buf_len , 4 ) ;
cmd = kzalloc ( cmd_len , GFP_KERNEL ) ;
if ( ! cmd ) {
ret = - ENOMEM ;
goto out ;
}
cmd - > size = cpu_to_le16 ( buf_len ) ;
2009-04-29 23:33:31 +03:00
if ( buf )
2009-06-12 14:14:19 +03:00
memcpy ( cmd - > data , buf , buf_len ) ;
2009-04-29 23:33:31 +03:00
2009-06-12 14:17:39 +03:00
ret = wl1251_cmd_send ( wl , cmd_id , cmd , cmd_len ) ;
2009-04-29 23:33:31 +03:00
if ( ret < 0 ) {
2009-06-12 14:17:39 +03:00
wl1251_warning ( " cmd set_template failed: %d " , ret ) ;
2009-06-12 14:14:19 +03:00
goto out ;
2009-04-29 23:33:31 +03:00
}
2009-06-12 14:14:19 +03:00
out :
kfree ( cmd ) ;
return ret ;
2009-04-29 23:33:31 +03:00
}