2005-05-13 06:54:16 +04:00
static int prism2_enable_aux_port ( struct net_device * dev , int enable )
{
u16 val , reg ;
int i , tries ;
unsigned long flags ;
struct hostap_interface * iface ;
local_info_t * local ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( local - > no_pri ) {
if ( enable ) {
PDEBUG ( DEBUG_EXTRA2 , " %s: no PRI f/w - assuming Aux "
" port is already enabled \n " , dev - > name ) ;
}
return 0 ;
}
spin_lock_irqsave ( & local - > cmdlock , flags ) ;
/* wait until busy bit is clear */
tries = HFA384X_CMD_BUSY_TIMEOUT ;
while ( HFA384X_INW ( HFA384X_CMD_OFF ) & HFA384X_CMD_BUSY & & tries > 0 ) {
tries - - ;
udelay ( 1 ) ;
}
if ( tries = = 0 ) {
reg = HFA384X_INW ( HFA384X_CMD_OFF ) ;
spin_unlock_irqrestore ( & local - > cmdlock , flags ) ;
printk ( " %s: prism2_enable_aux_port - timeout - reg=0x%04x \n " ,
dev - > name , reg ) ;
return - ETIMEDOUT ;
}
val = HFA384X_INW ( HFA384X_CONTROL_OFF ) ;
if ( enable ) {
HFA384X_OUTW ( HFA384X_AUX_MAGIC0 , HFA384X_PARAM0_OFF ) ;
HFA384X_OUTW ( HFA384X_AUX_MAGIC1 , HFA384X_PARAM1_OFF ) ;
HFA384X_OUTW ( HFA384X_AUX_MAGIC2 , HFA384X_PARAM2_OFF ) ;
if ( ( val & HFA384X_AUX_PORT_MASK ) ! = HFA384X_AUX_PORT_DISABLED )
printk ( " prism2_enable_aux_port: was not disabled!? \n " ) ;
val & = ~ HFA384X_AUX_PORT_MASK ;
val | = HFA384X_AUX_PORT_ENABLE ;
} else {
HFA384X_OUTW ( 0 , HFA384X_PARAM0_OFF ) ;
HFA384X_OUTW ( 0 , HFA384X_PARAM1_OFF ) ;
HFA384X_OUTW ( 0 , HFA384X_PARAM2_OFF ) ;
if ( ( val & HFA384X_AUX_PORT_MASK ) ! = HFA384X_AUX_PORT_ENABLED )
printk ( " prism2_enable_aux_port: was not enabled!? \n " ) ;
val & = ~ HFA384X_AUX_PORT_MASK ;
val | = HFA384X_AUX_PORT_DISABLE ;
}
HFA384X_OUTW ( val , HFA384X_CONTROL_OFF ) ;
udelay ( 5 ) ;
i = 10000 ;
while ( i > 0 ) {
val = HFA384X_INW ( HFA384X_CONTROL_OFF ) ;
val & = HFA384X_AUX_PORT_MASK ;
if ( ( enable & & val = = HFA384X_AUX_PORT_ENABLED ) | |
( ! enable & & val = = HFA384X_AUX_PORT_DISABLED ) )
break ;
udelay ( 10 ) ;
i - - ;
}
spin_unlock_irqrestore ( & local - > cmdlock , flags ) ;
if ( i = = 0 ) {
printk ( " prism2_enable_aux_port(%d) timed out \n " ,
enable ) ;
return - ETIMEDOUT ;
}
return 0 ;
}
static int hfa384x_from_aux ( struct net_device * dev , unsigned int addr , int len ,
void * buf )
{
u16 page , offset ;
if ( addr & 1 | | len & 1 )
return - 1 ;
page = addr > > 7 ;
offset = addr & 0x7f ;
HFA384X_OUTW ( page , HFA384X_AUXPAGE_OFF ) ;
HFA384X_OUTW ( offset , HFA384X_AUXOFFSET_OFF ) ;
udelay ( 5 ) ;
# ifdef PRISM2_PCI
{
2007-12-21 11:30:16 +03:00
__le16 * pos = ( __le16 * ) buf ;
2005-05-13 06:54:16 +04:00
while ( len > 0 ) {
* pos + + = HFA384X_INW_DATA ( HFA384X_AUXDATA_OFF ) ;
len - = 2 ;
}
}
# else /* PRISM2_PCI */
HFA384X_INSW ( HFA384X_AUXDATA_OFF , buf , len / 2 ) ;
# endif /* PRISM2_PCI */
return 0 ;
}
static int hfa384x_to_aux ( struct net_device * dev , unsigned int addr , int len ,
void * buf )
{
u16 page , offset ;
if ( addr & 1 | | len & 1 )
return - 1 ;
page = addr > > 7 ;
offset = addr & 0x7f ;
HFA384X_OUTW ( page , HFA384X_AUXPAGE_OFF ) ;
HFA384X_OUTW ( offset , HFA384X_AUXOFFSET_OFF ) ;
udelay ( 5 ) ;
# ifdef PRISM2_PCI
{
2007-12-21 11:30:16 +03:00
__le16 * pos = ( __le16 * ) buf ;
2005-05-13 06:54:16 +04:00
while ( len > 0 ) {
HFA384X_OUTW_DATA ( * pos + + , HFA384X_AUXDATA_OFF ) ;
len - = 2 ;
}
}
# else /* PRISM2_PCI */
HFA384X_OUTSW ( HFA384X_AUXDATA_OFF , buf , len / 2 ) ;
# endif /* PRISM2_PCI */
return 0 ;
}
static int prism2_pda_ok ( u8 * buf )
{
2007-12-21 11:30:16 +03:00
__le16 * pda = ( __le16 * ) buf ;
2005-05-13 06:54:16 +04:00
int pos ;
u16 len , pdr ;
if ( buf [ 0 ] = = 0xff & & buf [ 1 ] = = 0x00 & & buf [ 2 ] = = 0xff & &
buf [ 3 ] = = 0x00 )
return 0 ;
pos = 0 ;
while ( pos + 1 < PRISM2_PDA_SIZE / 2 ) {
len = le16_to_cpu ( pda [ pos ] ) ;
pdr = le16_to_cpu ( pda [ pos + 1 ] ) ;
if ( len = = 0 | | pos + len > PRISM2_PDA_SIZE / 2 )
return 0 ;
if ( pdr = = 0x0000 & & len = = 2 ) {
/* PDA end found */
return 1 ;
}
pos + = len + 1 ;
}
return 0 ;
}
2013-04-11 00:13:23 +04:00
# define prism2_download_aux_dump_npages 65536
2005-05-13 06:54:16 +04:00
2013-04-11 00:13:23 +04:00
struct prism2_download_aux_dump {
local_info_t * local ;
u16 page [ 0x80 ] ;
} ;
static int prism2_download_aux_dump_proc_show ( struct seq_file * m , void * v )
{
struct prism2_download_aux_dump * ctx = m - > private ;
2005-05-13 06:54:16 +04:00
2013-04-11 00:13:23 +04:00
hfa384x_from_aux ( ctx - > local - > dev , ( unsigned long ) v - 1 , 0x80 , ctx - > page ) ;
seq_write ( m , ctx - > page , 0x80 ) ;
2005-05-13 06:54:16 +04:00
return 0 ;
}
2013-04-11 00:13:23 +04:00
static void * prism2_download_aux_dump_proc_start ( struct seq_file * m , loff_t * _pos )
{
struct prism2_download_aux_dump * ctx = m - > private ;
prism2_enable_aux_port ( ctx - > local - > dev , 1 ) ;
if ( * _pos > = prism2_download_aux_dump_npages )
return NULL ;
return ( void * ) ( ( unsigned long ) * _pos + 1 ) ;
}
static void * prism2_download_aux_dump_proc_next ( struct seq_file * m , void * v , loff_t * _pos )
{
+ + * _pos ;
if ( * _pos > = prism2_download_aux_dump_npages )
return NULL ;
return ( void * ) ( ( unsigned long ) * _pos + 1 ) ;
}
static void prism2_download_aux_dump_proc_stop ( struct seq_file * m , void * v )
{
struct prism2_download_aux_dump * ctx = m - > private ;
prism2_enable_aux_port ( ctx - > local - > dev , 0 ) ;
}
static const struct seq_operations prism2_download_aux_dump_proc_seqops = {
. start = prism2_download_aux_dump_proc_start ,
. next = prism2_download_aux_dump_proc_next ,
. stop = prism2_download_aux_dump_proc_stop ,
. show = prism2_download_aux_dump_proc_show ,
} ;
static int prism2_download_aux_dump_proc_open ( struct inode * inode , struct file * file )
{
int ret = seq_open_private ( file , & prism2_download_aux_dump_proc_seqops ,
sizeof ( struct prism2_download_aux_dump ) ) ;
if ( ret = = 0 ) {
struct seq_file * m = file - > private_data ;
m - > private = PDE_DATA ( inode ) ;
}
return ret ;
}
static const struct file_operations prism2_download_aux_dump_proc_fops = {
. open = prism2_download_aux_dump_proc_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release_private ,
} ;
2005-05-13 06:54:16 +04:00
static u8 * prism2_read_pda ( struct net_device * dev )
{
u8 * buf ;
int res , i , found = 0 ;
# define NUM_PDA_ADDRS 4
unsigned int pda_addr [ NUM_PDA_ADDRS ] = {
0x7f0000 /* others than HFA3841 */ ,
0x3f0000 /* HFA3841 */ ,
0x390000 /* apparently used in older cards */ ,
0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */ ,
} ;
2006-12-13 11:35:56 +03:00
buf = kmalloc ( PRISM2_PDA_SIZE , GFP_KERNEL ) ;
2005-05-13 06:54:16 +04:00
if ( buf = = NULL )
return NULL ;
/* Note: wlan card should be in initial state (just after init cmd)
* and no other operations should be performed concurrently . */
prism2_enable_aux_port ( dev , 1 ) ;
for ( i = 0 ; i < NUM_PDA_ADDRS ; i + + ) {
PDEBUG ( DEBUG_EXTRA2 , " %s: trying to read PDA from 0x%08x " ,
dev - > name , pda_addr [ i ] ) ;
res = hfa384x_from_aux ( dev , pda_addr [ i ] , PRISM2_PDA_SIZE , buf ) ;
if ( res )
continue ;
if ( res = = 0 & & prism2_pda_ok ( buf ) ) {
PDEBUG2 ( DEBUG_EXTRA2 , " : OK \n " ) ;
found = 1 ;
break ;
} else {
PDEBUG2 ( DEBUG_EXTRA2 , " : failed \n " ) ;
}
}
prism2_enable_aux_port ( dev , 0 ) ;
if ( ! found ) {
printk ( KERN_DEBUG " %s: valid PDA not found \n " , dev - > name ) ;
kfree ( buf ) ;
buf = NULL ;
}
return buf ;
}
static int prism2_download_volatile ( local_info_t * local ,
struct prism2_download_data * param )
{
struct net_device * dev = local - > dev ;
int ret = 0 , i ;
u16 param0 , param1 ;
if ( local - > hw_downloading ) {
printk ( KERN_WARNING " %s: Already downloading - aborting new "
" request \n " , dev - > name ) ;
return - 1 ;
}
local - > hw_downloading = 1 ;
if ( local - > pri_only ) {
hfa384x_disable_interrupts ( dev ) ;
} else {
prism2_hw_shutdown ( dev , 0 ) ;
if ( prism2_hw_init ( dev , 0 ) ) {
printk ( KERN_WARNING " %s: Could not initialize card for "
" download \n " , dev - > name ) ;
ret = - 1 ;
goto out ;
}
}
if ( prism2_enable_aux_port ( dev , 1 ) ) {
printk ( KERN_WARNING " %s: Could not enable AUX port \n " ,
dev - > name ) ;
ret = - 1 ;
goto out ;
}
param0 = param - > start_addr & 0xffff ;
param1 = param - > start_addr > > 16 ;
HFA384X_OUTW ( 0 , HFA384X_PARAM2_OFF ) ;
HFA384X_OUTW ( param1 , HFA384X_PARAM1_OFF ) ;
if ( hfa384x_cmd_wait ( dev , HFA384X_CMDCODE_DOWNLOAD |
( HFA384X_PROGMODE_ENABLE_VOLATILE < < 8 ) ,
param0 ) ) {
printk ( KERN_WARNING " %s: Download command execution failed \n " ,
dev - > name ) ;
ret = - 1 ;
goto out ;
}
for ( i = 0 ; i < param - > num_areas ; i + + ) {
PDEBUG ( DEBUG_EXTRA2 , " %s: Writing %d bytes at 0x%08x \n " ,
dev - > name , param - > data [ i ] . len , param - > data [ i ] . addr ) ;
if ( hfa384x_to_aux ( dev , param - > data [ i ] . addr ,
param - > data [ i ] . len , param - > data [ i ] . data ) ) {
printk ( KERN_WARNING " %s: RAM download at 0x%08x "
" (len=%d) failed \n " , dev - > name ,
param - > data [ i ] . addr , param - > data [ i ] . len ) ;
ret = - 1 ;
goto out ;
}
}
HFA384X_OUTW ( param1 , HFA384X_PARAM1_OFF ) ;
HFA384X_OUTW ( 0 , HFA384X_PARAM2_OFF ) ;
if ( hfa384x_cmd_no_wait ( dev , HFA384X_CMDCODE_DOWNLOAD |
( HFA384X_PROGMODE_DISABLE < < 8 ) , param0 ) ) {
printk ( KERN_WARNING " %s: Download command execution failed \n " ,
dev - > name ) ;
ret = - 1 ;
goto out ;
}
/* ProgMode disable causes the hardware to restart itself from the
* given starting address . Give hw some time and ACK command just in
* case restart did not happen . */
mdelay ( 5 ) ;
HFA384X_OUTW ( HFA384X_EV_CMD , HFA384X_EVACK_OFF ) ;
if ( prism2_enable_aux_port ( dev , 0 ) ) {
printk ( KERN_DEBUG " %s: Disabling AUX port failed \n " ,
dev - > name ) ;
/* continue anyway.. restart should have taken care of this */
}
mdelay ( 5 ) ;
local - > hw_downloading = 0 ;
if ( prism2_hw_config ( dev , 2 ) ) {
printk ( KERN_WARNING " %s: Card configuration after RAM "
" download failed \n " , dev - > name ) ;
ret = - 1 ;
goto out ;
}
out :
local - > hw_downloading = 0 ;
return ret ;
}
static int prism2_enable_genesis ( local_info_t * local , int hcr )
{
struct net_device * dev = local - > dev ;
u8 initseq [ 4 ] = { 0x00 , 0xe1 , 0xa1 , 0xff } ;
u8 readbuf [ 4 ] ;
printk ( KERN_DEBUG " %s: test Genesis mode with HCR 0x%02x \n " ,
dev - > name , hcr ) ;
local - > func - > cor_sreset ( local ) ;
hfa384x_to_aux ( dev , 0x7e0038 , sizeof ( initseq ) , initseq ) ;
local - > func - > genesis_reset ( local , hcr ) ;
/* Readback test */
hfa384x_from_aux ( dev , 0x7e0038 , sizeof ( readbuf ) , readbuf ) ;
hfa384x_to_aux ( dev , 0x7e0038 , sizeof ( initseq ) , initseq ) ;
hfa384x_from_aux ( dev , 0x7e0038 , sizeof ( readbuf ) , readbuf ) ;
if ( memcmp ( initseq , readbuf , sizeof ( initseq ) ) = = 0 ) {
printk ( KERN_DEBUG " Readback test succeeded, HCR 0x%02x \n " ,
hcr ) ;
return 0 ;
} else {
printk ( KERN_DEBUG " Readback test failed, HCR 0x%02x "
" write %02x %02x %02x %02x read %02x %02x %02x %02x \n " ,
hcr , initseq [ 0 ] , initseq [ 1 ] , initseq [ 2 ] , initseq [ 3 ] ,
readbuf [ 0 ] , readbuf [ 1 ] , readbuf [ 2 ] , readbuf [ 3 ] ) ;
return 1 ;
}
}
static int prism2_get_ram_size ( local_info_t * local )
{
int ret ;
/* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
if ( prism2_enable_genesis ( local , 0x1f ) = = 0 )
ret = 8 ;
else if ( prism2_enable_genesis ( local , 0x0f ) = = 0 )
ret = 16 ;
else
ret = - 1 ;
/* Disable genesis mode */
local - > func - > genesis_reset ( local , ret = = 16 ? 0x07 : 0x17 ) ;
return ret ;
}
static int prism2_download_genesis ( local_info_t * local ,
struct prism2_download_data * param )
{
struct net_device * dev = local - > dev ;
int ram16 = 0 , i ;
int ret = 0 ;
if ( local - > hw_downloading ) {
printk ( KERN_WARNING " %s: Already downloading - aborting new "
" request \n " , dev - > name ) ;
return - EBUSY ;
}
if ( ! local - > func - > genesis_reset | | ! local - > func - > cor_sreset ) {
printk ( KERN_INFO " %s: Genesis mode downloading not supported "
" with this hwmodel \n " , dev - > name ) ;
return - EOPNOTSUPP ;
}
local - > hw_downloading = 1 ;
if ( prism2_enable_aux_port ( dev , 1 ) ) {
printk ( KERN_DEBUG " %s: failed to enable AUX port \n " ,
dev - > name ) ;
ret = - EIO ;
goto out ;
}
if ( local - > sram_type = = - 1 ) {
/* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
if ( prism2_enable_genesis ( local , 0x1f ) = = 0 ) {
ram16 = 0 ;
PDEBUG ( DEBUG_EXTRA2 , " %s: Genesis mode OK using x8 "
" SRAM \n " , dev - > name ) ;
} else if ( prism2_enable_genesis ( local , 0x0f ) = = 0 ) {
ram16 = 1 ;
PDEBUG ( DEBUG_EXTRA2 , " %s: Genesis mode OK using x16 "
" SRAM \n " , dev - > name ) ;
} else {
printk ( KERN_DEBUG " %s: Could not initiate genesis "
" mode \n " , dev - > name ) ;
ret = - EIO ;
goto out ;
}
} else {
if ( prism2_enable_genesis ( local , local - > sram_type = = 8 ?
0x1f : 0x0f ) ) {
printk ( KERN_DEBUG " %s: Failed to set Genesis "
" mode (sram_type=%d) \n " , dev - > name ,
local - > sram_type ) ;
ret = - EIO ;
goto out ;
}
ram16 = local - > sram_type ! = 8 ;
}
for ( i = 0 ; i < param - > num_areas ; i + + ) {
PDEBUG ( DEBUG_EXTRA2 , " %s: Writing %d bytes at 0x%08x \n " ,
dev - > name , param - > data [ i ] . len , param - > data [ i ] . addr ) ;
if ( hfa384x_to_aux ( dev , param - > data [ i ] . addr ,
param - > data [ i ] . len , param - > data [ i ] . data ) ) {
printk ( KERN_WARNING " %s: RAM download at 0x%08x "
" (len=%d) failed \n " , dev - > name ,
param - > data [ i ] . addr , param - > data [ i ] . len ) ;
ret = - EIO ;
goto out ;
}
}
PDEBUG ( DEBUG_EXTRA2 , " Disable genesis mode \n " ) ;
local - > func - > genesis_reset ( local , ram16 ? 0x07 : 0x17 ) ;
if ( prism2_enable_aux_port ( dev , 0 ) ) {
printk ( KERN_DEBUG " %s: Failed to disable AUX port \n " ,
dev - > name ) ;
}
mdelay ( 5 ) ;
local - > hw_downloading = 0 ;
PDEBUG ( DEBUG_EXTRA2 , " Trying to initialize card \n " ) ;
/*
* Make sure the INIT command does not generate a command completion
* event by disabling interrupts .
*/
hfa384x_disable_interrupts ( dev ) ;
if ( prism2_hw_init ( dev , 1 ) ) {
printk ( KERN_DEBUG " %s: Initialization after genesis mode "
" download failed \n " , dev - > name ) ;
ret = - EIO ;
goto out ;
}
PDEBUG ( DEBUG_EXTRA2 , " Card initialized - running PRI only \n " ) ;
if ( prism2_hw_init2 ( dev , 1 ) ) {
printk ( KERN_DEBUG " %s: Initialization(2) after genesis mode "
" download failed \n " , dev - > name ) ;
ret = - EIO ;
goto out ;
}
out :
local - > hw_downloading = 0 ;
return ret ;
}
# ifdef PRISM2_NON_VOLATILE_DOWNLOAD
/* Note! Non-volatile downloading functionality has not yet been tested
* thoroughly and it may corrupt flash image and effectively kill the card that
* is being updated . You have been warned . */
static inline int prism2_download_block ( struct net_device * dev ,
u32 addr , u8 * data ,
u32 bufaddr , int rest_len )
{
u16 param0 , param1 ;
int block_len ;
block_len = rest_len < 4096 ? rest_len : 4096 ;
param0 = addr & 0xffff ;
param1 = addr > > 16 ;
HFA384X_OUTW ( block_len , HFA384X_PARAM2_OFF ) ;
HFA384X_OUTW ( param1 , HFA384X_PARAM1_OFF ) ;
if ( hfa384x_cmd_wait ( dev , HFA384X_CMDCODE_DOWNLOAD |
( HFA384X_PROGMODE_ENABLE_NON_VOLATILE < < 8 ) ,
param0 ) ) {
printk ( KERN_WARNING " %s: Flash download command execution "
" failed \n " , dev - > name ) ;
return - 1 ;
}
if ( hfa384x_to_aux ( dev , bufaddr , block_len , data ) ) {
printk ( KERN_WARNING " %s: flash download at 0x%08x "
" (len=%d) failed \n " , dev - > name , addr , block_len ) ;
return - 1 ;
}
HFA384X_OUTW ( 0 , HFA384X_PARAM2_OFF ) ;
HFA384X_OUTW ( 0 , HFA384X_PARAM1_OFF ) ;
if ( hfa384x_cmd_wait ( dev , HFA384X_CMDCODE_DOWNLOAD |
( HFA384X_PROGMODE_PROGRAM_NON_VOLATILE < < 8 ) ,
0 ) ) {
printk ( KERN_WARNING " %s: Flash write command execution "
" failed \n " , dev - > name ) ;
return - 1 ;
}
return block_len ;
}
static int prism2_download_nonvolatile ( local_info_t * local ,
struct prism2_download_data * dl )
{
struct net_device * dev = local - > dev ;
int ret = 0 , i ;
struct {
2007-12-21 11:30:16 +03:00
__le16 page ;
__le16 offset ;
__le16 len ;
2005-05-13 06:54:16 +04:00
} dlbuffer ;
u32 bufaddr ;
if ( local - > hw_downloading ) {
printk ( KERN_WARNING " %s: Already downloading - aborting new "
" request \n " , dev - > name ) ;
return - 1 ;
}
ret = local - > func - > get_rid ( dev , HFA384X_RID_DOWNLOADBUFFER ,
& dlbuffer , 6 , 0 ) ;
if ( ret < 0 ) {
printk ( KERN_WARNING " %s: Could not read download buffer "
" parameters \n " , dev - > name ) ;
goto out ;
}
printk ( KERN_DEBUG " Download buffer: %d bytes at 0x%04x:0x%04x \n " ,
2007-12-21 11:30:16 +03:00
le16_to_cpu ( dlbuffer . len ) ,
le16_to_cpu ( dlbuffer . page ) ,
le16_to_cpu ( dlbuffer . offset ) ) ;
2005-05-13 06:54:16 +04:00
2007-12-21 11:30:16 +03:00
bufaddr = ( le16_to_cpu ( dlbuffer . page ) < < 7 ) + le16_to_cpu ( dlbuffer . offset ) ;
2005-05-13 06:54:16 +04:00
local - > hw_downloading = 1 ;
if ( ! local - > pri_only ) {
prism2_hw_shutdown ( dev , 0 ) ;
if ( prism2_hw_init ( dev , 0 ) ) {
printk ( KERN_WARNING " %s: Could not initialize card for "
" download \n " , dev - > name ) ;
ret = - 1 ;
goto out ;
}
}
hfa384x_disable_interrupts ( dev ) ;
if ( prism2_enable_aux_port ( dev , 1 ) ) {
printk ( KERN_WARNING " %s: Could not enable AUX port \n " ,
dev - > name ) ;
ret = - 1 ;
goto out ;
}
printk ( KERN_DEBUG " %s: starting flash download \n " , dev - > name ) ;
for ( i = 0 ; i < dl - > num_areas ; i + + ) {
int rest_len = dl - > data [ i ] . len ;
int data_off = 0 ;
while ( rest_len > 0 ) {
int block_len ;
block_len = prism2_download_block (
dev , dl - > data [ i ] . addr + data_off ,
dl - > data [ i ] . data + data_off , bufaddr ,
rest_len ) ;
if ( block_len < 0 ) {
ret = - 1 ;
goto out ;
}
rest_len - = block_len ;
data_off + = block_len ;
}
}
HFA384X_OUTW ( 0 , HFA384X_PARAM1_OFF ) ;
HFA384X_OUTW ( 0 , HFA384X_PARAM2_OFF ) ;
if ( hfa384x_cmd_wait ( dev , HFA384X_CMDCODE_DOWNLOAD |
( HFA384X_PROGMODE_DISABLE < < 8 ) , 0 ) ) {
printk ( KERN_WARNING " %s: Download command execution failed \n " ,
dev - > name ) ;
ret = - 1 ;
goto out ;
}
if ( prism2_enable_aux_port ( dev , 0 ) ) {
printk ( KERN_DEBUG " %s: Disabling AUX port failed \n " ,
dev - > name ) ;
/* continue anyway.. restart should have taken care of this */
}
mdelay ( 5 ) ;
local - > func - > hw_reset ( dev ) ;
local - > hw_downloading = 0 ;
if ( prism2_hw_config ( dev , 2 ) ) {
printk ( KERN_WARNING " %s: Card configuration after flash "
" download failed \n " , dev - > name ) ;
ret = - 1 ;
} else {
printk ( KERN_INFO " %s: Card initialized successfully after "
" flash download \n " , dev - > name ) ;
}
out :
local - > hw_downloading = 0 ;
return ret ;
}
# endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
static void prism2_download_free_data ( struct prism2_download_data * dl )
{
int i ;
if ( dl = = NULL )
return ;
for ( i = 0 ; i < dl - > num_areas ; i + + )
kfree ( dl - > data [ i ] . data ) ;
kfree ( dl ) ;
}
static int prism2_download ( local_info_t * local ,
struct prism2_download_param * param )
{
int ret = 0 ;
int i ;
u32 total_len = 0 ;
struct prism2_download_data * dl = NULL ;
printk ( KERN_DEBUG " prism2_download: dl_cmd=%d start_addr=0x%08x "
" num_areas=%d \n " ,
param - > dl_cmd , param - > start_addr , param - > num_areas ) ;
if ( param - > num_areas > 100 ) {
ret = - EINVAL ;
goto out ;
}
2006-12-02 14:33:40 +03:00
dl = kzalloc ( sizeof ( * dl ) + param - > num_areas *
2005-05-13 06:54:16 +04:00
sizeof ( struct prism2_download_data_area ) , GFP_KERNEL ) ;
if ( dl = = NULL ) {
ret = - ENOMEM ;
goto out ;
}
dl - > dl_cmd = param - > dl_cmd ;
dl - > start_addr = param - > start_addr ;
dl - > num_areas = param - > num_areas ;
for ( i = 0 ; i < param - > num_areas ; i + + ) {
PDEBUG ( DEBUG_EXTRA2 ,
" area %d: addr=0x%08x len=%d ptr=0x%p \n " ,
i , param - > data [ i ] . addr , param - > data [ i ] . len ,
param - > data [ i ] . ptr ) ;
dl - > data [ i ] . addr = param - > data [ i ] . addr ;
dl - > data [ i ] . len = param - > data [ i ] . len ;
total_len + = param - > data [ i ] . len ;
if ( param - > data [ i ] . len > PRISM2_MAX_DOWNLOAD_AREA_LEN | |
total_len > PRISM2_MAX_DOWNLOAD_LEN ) {
ret = - E2BIG ;
goto out ;
}
dl - > data [ i ] . data = kmalloc ( dl - > data [ i ] . len , GFP_KERNEL ) ;
if ( dl - > data [ i ] . data = = NULL ) {
ret = - ENOMEM ;
goto out ;
}
if ( copy_from_user ( dl - > data [ i ] . data , param - > data [ i ] . ptr ,
param - > data [ i ] . len ) ) {
ret = - EFAULT ;
goto out ;
}
}
switch ( param - > dl_cmd ) {
case PRISM2_DOWNLOAD_VOLATILE :
case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT :
ret = prism2_download_volatile ( local , dl ) ;
break ;
case PRISM2_DOWNLOAD_VOLATILE_GENESIS :
case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT :
ret = prism2_download_genesis ( local , dl ) ;
break ;
case PRISM2_DOWNLOAD_NON_VOLATILE :
# ifdef PRISM2_NON_VOLATILE_DOWNLOAD
ret = prism2_download_nonvolatile ( local , dl ) ;
# else /* PRISM2_NON_VOLATILE_DOWNLOAD */
printk ( KERN_INFO " %s: non-volatile downloading not enabled \n " ,
local - > dev - > name ) ;
ret = - EOPNOTSUPP ;
# endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
break ;
default :
printk ( KERN_DEBUG " %s: unsupported download command %d \n " ,
local - > dev - > name , param - > dl_cmd ) ;
ret = - EINVAL ;
break ;
2010-05-18 09:47:34 +04:00
}
2005-05-13 06:54:16 +04:00
out :
if ( ret = = 0 & & dl & &
param - > dl_cmd = = PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT ) {
prism2_download_free_data ( local - > dl_pri ) ;
local - > dl_pri = dl ;
} else if ( ret = = 0 & & dl & &
param - > dl_cmd = = PRISM2_DOWNLOAD_VOLATILE_PERSISTENT ) {
prism2_download_free_data ( local - > dl_sec ) ;
local - > dl_sec = dl ;
} else
prism2_download_free_data ( dl ) ;
return ret ;
}