2005-05-12 22:54:16 -04:00
/*
* Host AP ( software wireless LAN access point ) driver for
* Intersil Prism2 / 2.5 / 3.
*
* Copyright ( c ) 2001 - 2002 , SSH Communications Security Corp and Jouni Malinen
* < jkmaline @ cc . hut . fi >
2005-07-30 20:43:20 -07:00
* Copyright ( c ) 2002 - 2005 , Jouni Malinen < jkmaline @ cc . hut . fi >
2005-05-12 22:54:16 -04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation . See README and COPYING for
* more details .
*
* FIX :
* - there is currently no way of associating TX packets to correct wds device
* when TX Exc / OK event occurs , so all tx_packets and some
* tx_errors / tx_dropped are added to the main netdevice ; using sw_support
* field in txdesc might be used to fix this ( using Alloc event to increment
* tx_packets would need some further info in txfid table )
*
* Buffer Access Path ( BAP ) usage :
* Prism2 cards have two separate BAPs for accessing the card memory . These
* should allow concurrent access to two different frames and the driver
* previously used BAP0 for sending data and BAP1 for receiving data .
* However , there seems to be number of issues with concurrent access and at
* least one know hardware bug in using BAP0 and BAP1 concurrently with PCI
* Prism2 .5 . Therefore , the driver now only uses BAP0 for moving data between
* host and card memories . BAP0 accesses are protected with local - > baplock
* ( spin_lock_bh ) to prevent concurrent use .
*/
# include <linux/config.h>
# include <linux/version.h>
# include <asm/delay.h>
# include <asm/uaccess.h>
# include <linux/slab.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/proc_fs.h>
# include <linux/if_arp.h>
# include <linux/delay.h>
# include <linux/random.h>
# include <linux/wait.h>
# include <linux/sched.h>
# include <linux/rtnetlink.h>
# include <linux/wireless.h>
# include <net/iw_handler.h>
2005-07-30 20:43:19 -07:00
# include <net/ieee80211.h>
# include <net/ieee80211_crypt.h>
2005-05-12 22:54:16 -04:00
# include <asm/irq.h>
# include "hostap_80211.h"
# include "hostap.h"
# include "hostap_ap.h"
/* #define final_version */
static int mtu = 1500 ;
module_param ( mtu , int , 0444 ) ;
MODULE_PARM_DESC ( mtu , " Maximum transfer unit " ) ;
static int channel [ MAX_PARM_DEVICES ] = { 3 , DEF_INTS } ;
module_param_array ( channel , int , NULL , 0444 ) ;
MODULE_PARM_DESC ( channel , " Initial channel " ) ;
static char essid [ 33 ] = " test " ;
module_param_string ( essid , essid , sizeof ( essid ) , 0444 ) ;
MODULE_PARM_DESC ( essid , " Host AP's ESSID " ) ;
static int iw_mode [ MAX_PARM_DEVICES ] = { IW_MODE_MASTER , DEF_INTS } ;
module_param_array ( iw_mode , int , NULL , 0444 ) ;
MODULE_PARM_DESC ( iw_mode , " Initial operation mode " ) ;
static int beacon_int [ MAX_PARM_DEVICES ] = { 100 , DEF_INTS } ;
module_param_array ( beacon_int , int , NULL , 0444 ) ;
MODULE_PARM_DESC ( beacon_int , " Beacon interval (1 = 1024 usec) " ) ;
static int dtim_period [ MAX_PARM_DEVICES ] = { 1 , DEF_INTS } ;
module_param_array ( dtim_period , int , NULL , 0444 ) ;
MODULE_PARM_DESC ( dtim_period , " DTIM period " ) ;
static char dev_template [ 16 ] = " wlan%d " ;
module_param_string ( dev_template , dev_template , sizeof ( dev_template ) , 0444 ) ;
MODULE_PARM_DESC ( dev_template , " Prefix for network device name (default: "
" wlan%d) " ) ;
# ifdef final_version
# define EXTRA_EVENTS_WTERR 0
# else
/* check WTERR events (Wait Time-out) in development versions */
# define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR
# endif
/* Events that will be using BAP0 */
# define HFA384X_BAP0_EVENTS \
( HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX )
/* event mask, i.e., events that will result in an interrupt */
# define HFA384X_EVENT_MASK \
( HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \
HFA384X_EV_CMD | HFA384X_EV_TICK | \
2005-08-14 19:08:40 -07:00
EXTRA_EVENTS_WTERR )
2005-05-12 22:54:16 -04:00
/* Default TX control flags: use 802.11 headers and request interrupt for
* failed transmits . Frames that request ACK callback , will add
* _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy .
*/
# define HFA384X_TX_CTRL_FLAGS \
( HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX )
/* ca. 1 usec */
# define HFA384X_CMD_BUSY_TIMEOUT 5000
# define HFA384X_BAP_BUSY_TIMEOUT 50000
/* ca. 10 usec */
# define HFA384X_CMD_COMPL_TIMEOUT 20000
# define HFA384X_DL_COMPL_TIMEOUT 1000000
/* Wait times for initialization; yield to other processes to avoid busy
* waiting for long time . */
# define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */
# define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */
static void prism2_hw_reset ( struct net_device * dev ) ;
static void prism2_check_sta_fw_version ( local_info_t * local ) ;
# ifdef PRISM2_DOWNLOAD_SUPPORT
/* hostap_download.c */
static int prism2_download_aux_dump ( struct net_device * dev ,
unsigned int addr , int len , u8 * buf ) ;
static u8 * prism2_read_pda ( struct net_device * dev ) ;
static int prism2_download ( local_info_t * local ,
struct prism2_download_param * param ) ;
static void prism2_download_free_data ( struct prism2_download_data * dl ) ;
static int prism2_download_volatile ( local_info_t * local ,
struct prism2_download_data * param ) ;
static int prism2_download_genesis ( local_info_t * local ,
struct prism2_download_data * param ) ;
static int prism2_get_ram_size ( local_info_t * local ) ;
# endif /* PRISM2_DOWNLOAD_SUPPORT */
# ifndef final_version
/* magic value written to SWSUPPORT0 reg. for detecting whether card is still
* present */
# define HFA384X_MAGIC 0x8A32
# endif
static u16 hfa384x_read_reg ( struct net_device * dev , u16 reg )
{
return HFA384X_INW ( reg ) ;
}
static void hfa384x_read_regs ( struct net_device * dev ,
struct hfa384x_regs * regs )
{
regs - > cmd = HFA384X_INW ( HFA384X_CMD_OFF ) ;
regs - > evstat = HFA384X_INW ( HFA384X_EVSTAT_OFF ) ;
regs - > offset0 = HFA384X_INW ( HFA384X_OFFSET0_OFF ) ;
regs - > offset1 = HFA384X_INW ( HFA384X_OFFSET1_OFF ) ;
regs - > swsupport0 = HFA384X_INW ( HFA384X_SWSUPPORT0_OFF ) ;
}
/**
* __hostap_cmd_queue_free - Free Prism2 command queue entry ( private )
* @ local : pointer to private Host AP driver data
* @ entry : Prism2 command queue entry to be freed
* @ del_req : request the entry to be removed
*
* Internal helper function for freeing Prism2 command queue entries .
* Caller must have acquired local - > cmdlock before calling this function .
*/
static inline void __hostap_cmd_queue_free ( local_info_t * local ,
struct hostap_cmd_queue * entry ,
int del_req )
{
if ( del_req ) {
entry - > del_req = 1 ;
if ( ! list_empty ( & entry - > list ) ) {
list_del_init ( & entry - > list ) ;
local - > cmd_queue_len - - ;
}
}
if ( atomic_dec_and_test ( & entry - > usecnt ) & & entry - > del_req )
kfree ( entry ) ;
}
/**
* hostap_cmd_queue_free - Free Prism2 command queue entry
* @ local : pointer to private Host AP driver data
* @ entry : Prism2 command queue entry to be freed
* @ del_req : request the entry to be removed
*
* Free a Prism2 command queue entry .
*/
static inline void hostap_cmd_queue_free ( local_info_t * local ,
struct hostap_cmd_queue * entry ,
int del_req )
{
unsigned long flags ;
spin_lock_irqsave ( & local - > cmdlock , flags ) ;
__hostap_cmd_queue_free ( local , entry , del_req ) ;
spin_unlock_irqrestore ( & local - > cmdlock , flags ) ;
}
/**
* prism2_clear_cmd_queue - Free all pending Prism2 command queue entries
* @ local : pointer to private Host AP driver data
*/
static void prism2_clear_cmd_queue ( local_info_t * local )
{
struct list_head * ptr , * n ;
unsigned long flags ;
struct hostap_cmd_queue * entry ;
spin_lock_irqsave ( & local - > cmdlock , flags ) ;
list_for_each_safe ( ptr , n , & local - > cmd_queue ) {
entry = list_entry ( ptr , struct hostap_cmd_queue , list ) ;
atomic_inc ( & entry - > usecnt ) ;
printk ( KERN_DEBUG " %s: removed pending cmd_queue entry "
" (type=%d, cmd=0x%04x, param0=0x%04x) \n " ,
local - > dev - > name , entry - > type , entry - > cmd ,
entry - > param0 ) ;
__hostap_cmd_queue_free ( local , entry , 1 ) ;
}
if ( local - > cmd_queue_len ) {
/* This should not happen; print debug message and clear
* queue length . */
printk ( KERN_DEBUG " %s: cmd_queue_len (%d) not zero after "
" flush \n " , local - > dev - > name , local - > cmd_queue_len ) ;
local - > cmd_queue_len = 0 ;
}
spin_unlock_irqrestore ( & local - > cmdlock , flags ) ;
}
/**
* hfa384x_cmd_issue - Issue a Prism2 command to the hardware
* @ dev : pointer to net_device
* @ entry : Prism2 command queue entry to be issued
*/
static inline int hfa384x_cmd_issue ( struct net_device * dev ,
struct hostap_cmd_queue * entry )
{
struct hostap_interface * iface ;
local_info_t * local ;
int tries ;
u16 reg ;
unsigned long flags ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( local - > func - > card_present & & ! local - > func - > card_present ( local ) )
return - ENODEV ;
if ( entry - > issued ) {
printk ( KERN_DEBUG " %s: driver bug - re-issuing command @%p \n " ,
dev - > name , entry ) ;
}
/* wait until busy bit is clear; this should always be clear since the
* commands are serialized */
tries = HFA384X_CMD_BUSY_TIMEOUT ;
while ( HFA384X_INW ( HFA384X_CMD_OFF ) & HFA384X_CMD_BUSY & & tries > 0 ) {
tries - - ;
udelay ( 1 ) ;
}
# ifndef final_version
if ( tries ! = HFA384X_CMD_BUSY_TIMEOUT ) {
prism2_io_debug_error ( dev , 1 ) ;
printk ( KERN_DEBUG " %s: hfa384x_cmd_issue: cmd reg was busy "
" for %d usec \n " , dev - > name ,
HFA384X_CMD_BUSY_TIMEOUT - tries ) ;
}
# endif
if ( tries = = 0 ) {
reg = HFA384X_INW ( HFA384X_CMD_OFF ) ;
prism2_io_debug_error ( dev , 2 ) ;
printk ( KERN_DEBUG " %s: hfa384x_cmd_issue - timeout - "
" reg=0x%04x \n " , dev - > name , reg ) ;
return - ETIMEDOUT ;
}
/* write command */
spin_lock_irqsave ( & local - > cmdlock , flags ) ;
HFA384X_OUTW ( entry - > param0 , HFA384X_PARAM0_OFF ) ;
HFA384X_OUTW ( entry - > param1 , HFA384X_PARAM1_OFF ) ;
HFA384X_OUTW ( entry - > cmd , HFA384X_CMD_OFF ) ;
entry - > issued = 1 ;
spin_unlock_irqrestore ( & local - > cmdlock , flags ) ;
return 0 ;
}
/**
* hfa384x_cmd - Issue a Prism2 command and wait ( sleep ) for completion
* @ dev : pointer to net_device
* @ cmd : Prism2 command code ( HFA384X_CMD_CODE_ * )
* @ param0 : value for Param0 register
* @ param1 : value for Param1 register ( pointer ; % NULL if not used )
* @ resp0 : pointer for Resp0 data or % NULL if Resp0 is not needed
*
* Issue given command ( possibly after waiting in command queue ) and sleep
* until the command is completed ( or timed out or interrupted ) . This can be
* called only from user process context .
*/
static int hfa384x_cmd ( struct net_device * dev , u16 cmd , u16 param0 ,
u16 * param1 , u16 * resp0 )
{
struct hostap_interface * iface ;
local_info_t * local ;
int err , res , issue , issued = 0 ;
unsigned long flags ;
struct hostap_cmd_queue * entry ;
DECLARE_WAITQUEUE ( wait , current ) ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( in_interrupt ( ) ) {
printk ( KERN_DEBUG " %s: hfa384x_cmd called from interrupt "
" context \n " , dev - > name ) ;
return - 1 ;
}
if ( local - > cmd_queue_len > = HOSTAP_CMD_QUEUE_MAX_LEN ) {
printk ( KERN_DEBUG " %s: hfa384x_cmd: cmd_queue full \n " ,
dev - > name ) ;
return - 1 ;
}
if ( signal_pending ( current ) )
return - EINTR ;
entry = ( struct hostap_cmd_queue * )
kmalloc ( sizeof ( * entry ) , GFP_ATOMIC ) ;
if ( entry = = NULL ) {
printk ( KERN_DEBUG " %s: hfa384x_cmd - kmalloc failed \n " ,
dev - > name ) ;
return - ENOMEM ;
}
memset ( entry , 0 , sizeof ( * entry ) ) ;
atomic_set ( & entry - > usecnt , 1 ) ;
entry - > type = CMD_SLEEP ;
entry - > cmd = cmd ;
entry - > param0 = param0 ;
if ( param1 )
entry - > param1 = * param1 ;
init_waitqueue_head ( & entry - > compl ) ;
/* prepare to wait for command completion event, but do not sleep yet
*/
add_wait_queue ( & entry - > compl , & wait ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
spin_lock_irqsave ( & local - > cmdlock , flags ) ;
issue = list_empty ( & local - > cmd_queue ) ;
if ( issue )
entry - > issuing = 1 ;
list_add_tail ( & entry - > list , & local - > cmd_queue ) ;
local - > cmd_queue_len + + ;
spin_unlock_irqrestore ( & local - > cmdlock , flags ) ;
err = 0 ;
if ( ! issue )
goto wait_completion ;
if ( signal_pending ( current ) )
err = - EINTR ;
if ( ! err ) {
if ( hfa384x_cmd_issue ( dev , entry ) )
err = - ETIMEDOUT ;
else
issued = 1 ;
}
wait_completion :
if ( ! err & & entry - > type ! = CMD_COMPLETED ) {
/* sleep until command is completed or timed out */
res = schedule_timeout ( 2 * HZ ) ;
} else
res = - 1 ;
if ( ! err & & signal_pending ( current ) )
err = - EINTR ;
if ( err & & issued ) {
/* the command was issued, so a CmdCompl event should occur
* soon ; however , there ' s a pending signal and
* schedule_timeout ( ) would be interrupted ; wait a short period
* of time to avoid removing entry from the list before
* CmdCompl event */
udelay ( 300 ) ;
}
set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( & entry - > compl , & wait ) ;
/* If entry->list is still in the list, it must be removed
* first and in this case prism2_cmd_ev ( ) does not yet have
* local reference to it , and the data can be kfree ( ) ' d
* here . If the command completion event is still generated ,
* it will be assigned to next ( possibly ) pending command , but
* the driver will reset the card anyway due to timeout
*
* If the entry is not in the list prism2_cmd_ev ( ) has a local
* reference to it , but keeps cmdlock as long as the data is
* needed , so the data can be kfree ( ) ' d here . */
/* FIX: if the entry->list is in the list, it has not been completed
* yet , so removing it here is somewhat wrong . . this could cause
* references to freed memory and next list_del ( ) causing NULL pointer
* dereference . . it would probably be better to leave the entry in the
* list and the list should be emptied during hw reset */
spin_lock_irqsave ( & local - > cmdlock , flags ) ;
if ( ! list_empty ( & entry - > list ) ) {
printk ( KERN_DEBUG " %s: hfa384x_cmd: entry still in list? "
" (entry=%p, type=%d, res=%d) \n " , dev - > name , entry ,
entry - > type , res ) ;
list_del_init ( & entry - > list ) ;
local - > cmd_queue_len - - ;
}
spin_unlock_irqrestore ( & local - > cmdlock , flags ) ;
if ( err ) {
printk ( KERN_DEBUG " %s: hfa384x_cmd: interrupted; err=%d \n " ,
dev - > name , err ) ;
res = err ;
goto done ;
}
if ( entry - > type ! = CMD_COMPLETED ) {
u16 reg = HFA384X_INW ( HFA384X_EVSTAT_OFF ) ;
printk ( KERN_DEBUG " %s: hfa384x_cmd: command was not "
" completed (res=%d, entry=%p, type=%d, cmd=0x%04x, "
" param0=0x%04x, EVSTAT=%04x INTEN=%04x) \n " , dev - > name ,
res , entry , entry - > type , entry - > cmd , entry - > param0 , reg ,
HFA384X_INW ( HFA384X_INTEN_OFF ) ) ;
if ( reg & HFA384X_EV_CMD ) {
/* Command completion event is pending, but the
* interrupt was not delivered - probably an issue
* with pcmcia - cs configuration . */
printk ( KERN_WARNING " %s: interrupt delivery does not "
" seem to work \n " , dev - > name ) ;
}
prism2_io_debug_error ( dev , 3 ) ;
res = - ETIMEDOUT ;
goto done ;
}
if ( resp0 ! = NULL )
* resp0 = entry - > resp0 ;
# ifndef final_version
if ( entry - > res ) {
printk ( KERN_DEBUG " %s: CMD=0x%04x => res=0x%02x, "
" resp0=0x%04x \n " ,
dev - > name , cmd , entry - > res , entry - > resp0 ) ;
}
# endif /* final_version */
res = entry - > res ;
done :
hostap_cmd_queue_free ( local , entry , 1 ) ;
return res ;
}
/**
* hfa384x_cmd_callback - Issue a Prism2 command ; callback when completed
* @ dev : pointer to net_device
* @ cmd : Prism2 command code ( HFA384X_CMD_CODE_ * )
* @ param0 : value for Param0 register
* @ callback : command completion callback function ( % NULL = no callback )
2005-07-30 12:50:05 -07:00
* @ context : context data to be given to the callback function
2005-05-12 22:54:16 -04:00
*
* Issue given command ( possibly after waiting in command queue ) and use
* callback function to indicate command completion . This can be called both
* from user and interrupt context . The callback function will be called in
* hardware IRQ context . It can be % NULL , when no function is called when
* command is completed .
*/
static int hfa384x_cmd_callback ( struct net_device * dev , u16 cmd , u16 param0 ,
void ( * callback ) ( struct net_device * dev ,
2005-07-30 12:50:05 -07:00
long context , u16 resp0 ,
2005-05-12 22:54:16 -04:00
u16 status ) ,
2005-07-30 12:50:05 -07:00
long context )
2005-05-12 22:54:16 -04:00
{
struct hostap_interface * iface ;
local_info_t * local ;
int issue , ret ;
unsigned long flags ;
struct hostap_cmd_queue * entry ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( local - > cmd_queue_len > = HOSTAP_CMD_QUEUE_MAX_LEN + 2 ) {
printk ( KERN_DEBUG " %s: hfa384x_cmd: cmd_queue full \n " ,
dev - > name ) ;
return - 1 ;
}
entry = ( struct hostap_cmd_queue * )
kmalloc ( sizeof ( * entry ) , GFP_ATOMIC ) ;
if ( entry = = NULL ) {
printk ( KERN_DEBUG " %s: hfa384x_cmd_callback - kmalloc "
" failed \n " , dev - > name ) ;
return - ENOMEM ;
}
memset ( entry , 0 , sizeof ( * entry ) ) ;
atomic_set ( & entry - > usecnt , 1 ) ;
entry - > type = CMD_CALLBACK ;
entry - > cmd = cmd ;
entry - > param0 = param0 ;
entry - > callback = callback ;
entry - > context = context ;
spin_lock_irqsave ( & local - > cmdlock , flags ) ;
issue = list_empty ( & local - > cmd_queue ) ;
if ( issue )
entry - > issuing = 1 ;
list_add_tail ( & entry - > list , & local - > cmd_queue ) ;
local - > cmd_queue_len + + ;
spin_unlock_irqrestore ( & local - > cmdlock , flags ) ;
if ( issue & & hfa384x_cmd_issue ( dev , entry ) )
ret = - ETIMEDOUT ;
else
ret = 0 ;
hostap_cmd_queue_free ( local , entry , ret ) ;
return ret ;
}
/**
* __hfa384x_cmd_no_wait - Issue a Prism2 command ( private )
* @ dev : pointer to net_device
* @ cmd : Prism2 command code ( HFA384X_CMD_CODE_ * )
* @ param0 : value for Param0 register
* @ io_debug_num : I / O debug error number
*
* Shared helper function for hfa384x_cmd_wait ( ) and hfa384x_cmd_no_wait ( ) .
*/
static int __hfa384x_cmd_no_wait ( struct net_device * dev , u16 cmd , u16 param0 ,
int io_debug_num )
{
int tries ;
u16 reg ;
/* wait until busy bit is clear; this should always be clear since the
* commands are serialized */
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 ) ;
prism2_io_debug_error ( dev , io_debug_num ) ;
printk ( KERN_DEBUG " %s: __hfa384x_cmd_no_wait(%d) - timeout - "
" reg=0x%04x \n " , dev - > name , io_debug_num , reg ) ;
return - ETIMEDOUT ;
}
/* write command */
HFA384X_OUTW ( param0 , HFA384X_PARAM0_OFF ) ;
HFA384X_OUTW ( cmd , HFA384X_CMD_OFF ) ;
return 0 ;
}
/**
* hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion
* @ dev : pointer to net_device
* @ cmd : Prism2 command code ( HFA384X_CMD_CODE_ * )
* @ param0 : value for Param0 register
*/
static int hfa384x_cmd_wait ( struct net_device * dev , u16 cmd , u16 param0 )
{
int res , tries ;
u16 reg ;
res = __hfa384x_cmd_no_wait ( dev , cmd , param0 , 4 ) ;
if ( res )
return res ;
/* wait for command completion */
if ( ( cmd & HFA384X_CMDCODE_MASK ) = = HFA384X_CMDCODE_DOWNLOAD )
tries = HFA384X_DL_COMPL_TIMEOUT ;
else
tries = HFA384X_CMD_COMPL_TIMEOUT ;
while ( ! ( HFA384X_INW ( HFA384X_EVSTAT_OFF ) & HFA384X_EV_CMD ) & &
tries > 0 ) {
tries - - ;
udelay ( 10 ) ;
}
if ( tries = = 0 ) {
reg = HFA384X_INW ( HFA384X_EVSTAT_OFF ) ;
prism2_io_debug_error ( dev , 5 ) ;
printk ( KERN_DEBUG " %s: hfa384x_cmd_wait - timeout2 - "
" reg=0x%04x \n " , dev - > name , reg ) ;
return - ETIMEDOUT ;
}
res = ( HFA384X_INW ( HFA384X_STATUS_OFF ) &
( BIT ( 14 ) | BIT ( 13 ) | BIT ( 12 ) | BIT ( 11 ) | BIT ( 10 ) | BIT ( 9 ) |
BIT ( 8 ) ) ) > > 8 ;
# ifndef final_version
if ( res ) {
printk ( KERN_DEBUG " %s: CMD=0x%04x => res=0x%02x \n " ,
dev - > name , cmd , res ) ;
}
# endif
HFA384X_OUTW ( HFA384X_EV_CMD , HFA384X_EVACK_OFF ) ;
return res ;
}
/**
* hfa384x_cmd_no_wait - Issue a Prism2 command ; do not wait for completion
* @ dev : pointer to net_device
* @ cmd : Prism2 command code ( HFA384X_CMD_CODE_ * )
* @ param0 : value for Param0 register
*/
static inline int hfa384x_cmd_no_wait ( struct net_device * dev , u16 cmd ,
u16 param0 )
{
return __hfa384x_cmd_no_wait ( dev , cmd , param0 , 6 ) ;
}
/**
* prism2_cmd_ev - Prism2 command completion event handler
* @ dev : pointer to net_device
*
* Interrupt handler for command completion events . Called by the main
* interrupt handler in hardware IRQ context . Read Resp0 and status registers
* from the hardware and ACK the event . Depending on the issued command type
* either wake up the sleeping process that is waiting for command completion
* or call the callback function . Issue the next command , if one is pending .
*/
static void prism2_cmd_ev ( struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
struct hostap_cmd_queue * entry = NULL ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
spin_lock ( & local - > cmdlock ) ;
if ( ! list_empty ( & local - > cmd_queue ) ) {
entry = list_entry ( local - > cmd_queue . next ,
struct hostap_cmd_queue , list ) ;
atomic_inc ( & entry - > usecnt ) ;
list_del_init ( & entry - > list ) ;
local - > cmd_queue_len - - ;
if ( ! entry - > issued ) {
printk ( KERN_DEBUG " %s: Command completion event, but "
" cmd not issued \n " , dev - > name ) ;
__hostap_cmd_queue_free ( local , entry , 1 ) ;
entry = NULL ;
}
}
spin_unlock ( & local - > cmdlock ) ;
if ( ! entry ) {
HFA384X_OUTW ( HFA384X_EV_CMD , HFA384X_EVACK_OFF ) ;
printk ( KERN_DEBUG " %s: Command completion event, but no "
" pending commands \n " , dev - > name ) ;
return ;
}
entry - > resp0 = HFA384X_INW ( HFA384X_RESP0_OFF ) ;
entry - > res = ( HFA384X_INW ( HFA384X_STATUS_OFF ) &
( BIT ( 14 ) | BIT ( 13 ) | BIT ( 12 ) | BIT ( 11 ) | BIT ( 10 ) |
BIT ( 9 ) | BIT ( 8 ) ) ) > > 8 ;
HFA384X_OUTW ( HFA384X_EV_CMD , HFA384X_EVACK_OFF ) ;
/* TODO: rest of the CmdEv handling could be moved to tasklet */
if ( entry - > type = = CMD_SLEEP ) {
entry - > type = CMD_COMPLETED ;
wake_up_interruptible ( & entry - > compl ) ;
} else if ( entry - > type = = CMD_CALLBACK ) {
if ( entry - > callback )
entry - > callback ( dev , entry - > context , entry - > resp0 ,
entry - > res ) ;
} else {
printk ( KERN_DEBUG " %s: Invalid command completion type %d \n " ,
dev - > name , entry - > type ) ;
}
hostap_cmd_queue_free ( local , entry , 1 ) ;
/* issue next command, if pending */
entry = NULL ;
spin_lock ( & local - > cmdlock ) ;
if ( ! list_empty ( & local - > cmd_queue ) ) {
entry = list_entry ( local - > cmd_queue . next ,
struct hostap_cmd_queue , list ) ;
if ( entry - > issuing ) {
/* hfa384x_cmd() has already started issuing this
* command , so do not start here */
entry = NULL ;
}
if ( entry )
atomic_inc ( & entry - > usecnt ) ;
}
spin_unlock ( & local - > cmdlock ) ;
if ( entry ) {
/* issue next command; if command issuing fails, remove the
* entry from cmd_queue */
int res = hfa384x_cmd_issue ( dev , entry ) ;
spin_lock ( & local - > cmdlock ) ;
__hostap_cmd_queue_free ( local , entry , res ) ;
spin_unlock ( & local - > cmdlock ) ;
}
}
static inline int hfa384x_wait_offset ( struct net_device * dev , u16 o_off )
{
int tries = HFA384X_BAP_BUSY_TIMEOUT ;
int res = HFA384X_INW ( o_off ) & HFA384X_OFFSET_BUSY ;
while ( res & & tries > 0 ) {
tries - - ;
udelay ( 1 ) ;
res = HFA384X_INW ( o_off ) & HFA384X_OFFSET_BUSY ;
}
return res ;
}
/* Offset must be even */
static int hfa384x_setup_bap ( struct net_device * dev , u16 bap , u16 id ,
int offset )
{
u16 o_off , s_off ;
int ret = 0 ;
if ( offset % 2 | | bap > 1 )
return - EINVAL ;
if ( bap = = BAP1 ) {
o_off = HFA384X_OFFSET1_OFF ;
s_off = HFA384X_SELECT1_OFF ;
} else {
o_off = HFA384X_OFFSET0_OFF ;
s_off = HFA384X_SELECT0_OFF ;
}
if ( hfa384x_wait_offset ( dev , o_off ) ) {
prism2_io_debug_error ( dev , 7 ) ;
printk ( KERN_DEBUG " %s: hfa384x_setup_bap - timeout before \n " ,
dev - > name ) ;
ret = - ETIMEDOUT ;
goto out ;
}
HFA384X_OUTW ( id , s_off ) ;
HFA384X_OUTW ( offset , o_off ) ;
if ( hfa384x_wait_offset ( dev , o_off ) ) {
prism2_io_debug_error ( dev , 8 ) ;
printk ( KERN_DEBUG " %s: hfa384x_setup_bap - timeout after \n " ,
dev - > name ) ;
ret = - ETIMEDOUT ;
goto out ;
}
# ifndef final_version
if ( HFA384X_INW ( o_off ) & HFA384X_OFFSET_ERR ) {
prism2_io_debug_error ( dev , 9 ) ;
printk ( KERN_DEBUG " %s: hfa384x_setup_bap - offset error "
" (%d,0x04%x,%d); reg=0x%04x \n " ,
dev - > name , bap , id , offset , HFA384X_INW ( o_off ) ) ;
ret = - EINVAL ;
}
# endif
out :
return ret ;
}
static int hfa384x_get_rid ( struct net_device * dev , u16 rid , void * buf , int len ,
int exact_len )
{
struct hostap_interface * iface ;
local_info_t * local ;
int res , rlen = 0 ;
struct hfa384x_rid_hdr rec ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( local - > no_pri ) {
printk ( KERN_DEBUG " %s: cannot get RID %04x (len=%d) - no PRI "
" f/w \n " , dev - > name , rid , len ) ;
return - ENOTTY ; /* Well.. not really correct, but return
* something unique enough . . */
}
if ( ( local - > func - > card_present & & ! local - > func - > card_present ( local ) ) | |
local - > hw_downloading )
return - ENODEV ;
res = down_interruptible ( & local - > rid_bap_sem ) ;
if ( res )
return res ;
res = hfa384x_cmd ( dev , HFA384X_CMDCODE_ACCESS , rid , NULL , NULL ) ;
if ( res ) {
printk ( KERN_DEBUG " %s: hfa384x_get_rid: CMDCODE_ACCESS failed "
" (res=%d, rid=%04x, len=%d) \n " ,
dev - > name , res , rid , len ) ;
up ( & local - > rid_bap_sem ) ;
return res ;
}
spin_lock_bh ( & local - > baplock ) ;
res = hfa384x_setup_bap ( dev , BAP0 , rid , 0 ) ;
if ( ! res )
res = hfa384x_from_bap ( dev , BAP0 , & rec , sizeof ( rec ) ) ;
if ( le16_to_cpu ( rec . len ) = = 0 ) {
/* RID not available */
res = - ENODATA ;
}
rlen = ( le16_to_cpu ( rec . len ) - 1 ) * 2 ;
if ( ! res & & exact_len & & rlen ! = len ) {
printk ( KERN_DEBUG " %s: hfa384x_get_rid - RID len mismatch: "
" rid=0x%04x, len=%d (expected %d) \n " ,
dev - > name , rid , rlen , len ) ;
res = - ENODATA ;
}
if ( ! res )
res = hfa384x_from_bap ( dev , BAP0 , buf , len ) ;
spin_unlock_bh ( & local - > baplock ) ;
up ( & local - > rid_bap_sem ) ;
if ( res ) {
if ( res ! = - ENODATA )
printk ( KERN_DEBUG " %s: hfa384x_get_rid (rid=%04x, "
" len=%d) - failed - res=%d \n " , dev - > name , rid ,
len , res ) ;
if ( res = = - ETIMEDOUT )
prism2_hw_reset ( dev ) ;
return res ;
}
return rlen ;
}
static int hfa384x_set_rid ( struct net_device * dev , u16 rid , void * buf , int len )
{
struct hostap_interface * iface ;
local_info_t * local ;
struct hfa384x_rid_hdr rec ;
int res ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( local - > no_pri ) {
printk ( KERN_DEBUG " %s: cannot set RID %04x (len=%d) - no PRI "
" f/w \n " , dev - > name , rid , len ) ;
return - ENOTTY ; /* Well.. not really correct, but return
* something unique enough . . */
}
if ( ( local - > func - > card_present & & ! local - > func - > card_present ( local ) ) | |
local - > hw_downloading )
return - ENODEV ;
rec . rid = cpu_to_le16 ( rid ) ;
/* RID len in words and +1 for rec.rid */
rec . len = cpu_to_le16 ( len / 2 + len % 2 + 1 ) ;
res = down_interruptible ( & local - > rid_bap_sem ) ;
if ( res )
return res ;
spin_lock_bh ( & local - > baplock ) ;
res = hfa384x_setup_bap ( dev , BAP0 , rid , 0 ) ;
if ( ! res )
res = hfa384x_to_bap ( dev , BAP0 , & rec , sizeof ( rec ) ) ;
if ( ! res )
res = hfa384x_to_bap ( dev , BAP0 , buf , len ) ;
spin_unlock_bh ( & local - > baplock ) ;
if ( res ) {
printk ( KERN_DEBUG " %s: hfa384x_set_rid (rid=%04x, len=%d) - "
" failed - res=%d \n " , dev - > name , rid , len , res ) ;
up ( & local - > rid_bap_sem ) ;
return res ;
}
res = hfa384x_cmd ( dev , HFA384X_CMDCODE_ACCESS_WRITE , rid , NULL , NULL ) ;
up ( & local - > rid_bap_sem ) ;
if ( res ) {
printk ( KERN_DEBUG " %s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
" failed (res=%d, rid=%04x, len=%d) \n " ,
dev - > name , res , rid , len ) ;
return res ;
}
if ( res = = - ETIMEDOUT )
prism2_hw_reset ( dev ) ;
return res ;
}
static void hfa384x_disable_interrupts ( struct net_device * dev )
{
/* disable interrupts and clear event status */
HFA384X_OUTW ( 0 , HFA384X_INTEN_OFF ) ;
HFA384X_OUTW ( 0xffff , HFA384X_EVACK_OFF ) ;
}
static void hfa384x_enable_interrupts ( struct net_device * dev )
{
/* ack pending events and enable interrupts from selected events */
HFA384X_OUTW ( 0xffff , HFA384X_EVACK_OFF ) ;
HFA384X_OUTW ( HFA384X_EVENT_MASK , HFA384X_INTEN_OFF ) ;
}
static void hfa384x_events_no_bap0 ( struct net_device * dev )
{
HFA384X_OUTW ( HFA384X_EVENT_MASK & ~ HFA384X_BAP0_EVENTS ,
HFA384X_INTEN_OFF ) ;
}
static void hfa384x_events_all ( struct net_device * dev )
{
HFA384X_OUTW ( HFA384X_EVENT_MASK , HFA384X_INTEN_OFF ) ;
}
static void hfa384x_events_only_cmd ( struct net_device * dev )
{
HFA384X_OUTW ( HFA384X_EV_CMD , HFA384X_INTEN_OFF ) ;
}
static u16 hfa384x_allocate_fid ( struct net_device * dev , int len )
{
u16 fid ;
unsigned long delay ;
/* FIX: this could be replace with hfa384x_cmd() if the Alloc event
* below would be handled like CmdCompl event ( sleep here , wake up from
* interrupt handler */
if ( hfa384x_cmd_wait ( dev , HFA384X_CMDCODE_ALLOC , len ) ) {
printk ( KERN_DEBUG " %s: cannot allocate fid, len=%d \n " ,
dev - > name , len ) ;
return 0xffff ;
}
delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT ;
while ( ! ( HFA384X_INW ( HFA384X_EVSTAT_OFF ) & HFA384X_EV_ALLOC ) & &
time_before ( jiffies , delay ) )
yield ( ) ;
if ( ! ( HFA384X_INW ( HFA384X_EVSTAT_OFF ) & HFA384X_EV_ALLOC ) ) {
printk ( " %s: fid allocate, len=%d - timeout \n " , dev - > name , len ) ;
return 0xffff ;
}
fid = HFA384X_INW ( HFA384X_ALLOCFID_OFF ) ;
HFA384X_OUTW ( HFA384X_EV_ALLOC , HFA384X_EVACK_OFF ) ;
return fid ;
}
static int prism2_reset_port ( struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
int res ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( ! local - > dev_enabled )
return 0 ;
res = hfa384x_cmd ( dev , HFA384X_CMDCODE_DISABLE , 0 ,
NULL , NULL ) ;
if ( res )
printk ( KERN_DEBUG " %s: reset port failed to disable port \n " ,
dev - > name ) ;
else {
res = hfa384x_cmd ( dev , HFA384X_CMDCODE_ENABLE , 0 ,
NULL , NULL ) ;
if ( res )
printk ( KERN_DEBUG " %s: reset port failed to enable "
" port \n " , dev - > name ) ;
}
/* It looks like at least some STA firmware versions reset
* fragmentation threshold back to 2346 after enable command . Restore
* the configured value , if it differs from this default . */
if ( local - > fragm_threshold ! = 2346 & &
hostap_set_word ( dev , HFA384X_RID_FRAGMENTATIONTHRESHOLD ,
local - > fragm_threshold ) ) {
printk ( KERN_DEBUG " %s: failed to restore fragmentation "
" threshold (%d) after Port0 enable \n " ,
dev - > name , local - > fragm_threshold ) ;
}
return res ;
}
static int prism2_get_version_info ( struct net_device * dev , u16 rid ,
const char * txt )
{
struct hfa384x_comp_ident comp ;
struct hostap_interface * iface ;
local_info_t * local ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( local - > no_pri ) {
/* PRI f/w not yet available - cannot read RIDs */
return - 1 ;
}
if ( hfa384x_get_rid ( dev , rid , & comp , sizeof ( comp ) , 1 ) < 0 ) {
printk ( KERN_DEBUG " Could not get RID for component %s \n " , txt ) ;
return - 1 ;
}
printk ( KERN_INFO " %s: %s: id=0x%02x v%d.%d.%d \n " , dev - > name , txt ,
__le16_to_cpu ( comp . id ) , __le16_to_cpu ( comp . major ) ,
__le16_to_cpu ( comp . minor ) , __le16_to_cpu ( comp . variant ) ) ;
return 0 ;
}
static int prism2_setup_rids ( struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
u16 tmp ;
int ret = 0 ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
hostap_set_word ( dev , HFA384X_RID_TICKTIME , 2000 ) ;
if ( ! local - > fw_ap ) {
tmp = hostap_get_porttype ( local ) ;
ret = hostap_set_word ( dev , HFA384X_RID_CNFPORTTYPE , tmp ) ;
if ( ret ) {
printk ( " %s: Port type setting to %d failed \n " ,
dev - > name , tmp ) ;
goto fail ;
}
}
/* Setting SSID to empty string seems to kill the card in Host AP mode
*/
if ( local - > iw_mode ! = IW_MODE_MASTER | | local - > essid [ 0 ] ! = ' \0 ' ) {
ret = hostap_set_string ( dev , HFA384X_RID_CNFOWNSSID ,
local - > essid ) ;
if ( ret ) {
printk ( " %s: AP own SSID setting failed \n " , dev - > name ) ;
goto fail ;
}
}
ret = hostap_set_word ( dev , HFA384X_RID_CNFMAXDATALEN ,
PRISM2_DATA_MAXLEN ) ;
if ( ret ) {
printk ( " %s: MAC data length setting to %d failed \n " ,
dev - > name , PRISM2_DATA_MAXLEN ) ;
goto fail ;
}
if ( hfa384x_get_rid ( dev , HFA384X_RID_CHANNELLIST , & tmp , 2 , 1 ) < 0 ) {
printk ( " %s: Channel list read failed \n " , dev - > name ) ;
ret = - EINVAL ;
goto fail ;
}
local - > channel_mask = __le16_to_cpu ( tmp ) ;
if ( local - > channel < 1 | | local - > channel > 14 | |
! ( local - > channel_mask & ( 1 < < ( local - > channel - 1 ) ) ) ) {
printk ( KERN_WARNING " %s: Channel setting out of range "
" (%d)! \n " , dev - > name , local - > channel ) ;
ret = - EBUSY ;
goto fail ;
}
ret = hostap_set_word ( dev , HFA384X_RID_CNFOWNCHANNEL , local - > channel ) ;
if ( ret ) {
printk ( " %s: Channel setting to %d failed \n " ,
dev - > name , local - > channel ) ;
goto fail ;
}
ret = hostap_set_word ( dev , HFA384X_RID_CNFBEACONINT ,
local - > beacon_int ) ;
if ( ret ) {
printk ( " %s: Beacon interval setting to %d failed \n " ,
dev - > name , local - > beacon_int ) ;
/* this may fail with Symbol/Lucent firmware */
if ( ret = = - ETIMEDOUT )
goto fail ;
}
ret = hostap_set_word ( dev , HFA384X_RID_CNFOWNDTIMPERIOD ,
local - > dtim_period ) ;
if ( ret ) {
printk ( " %s: DTIM period setting to %d failed \n " ,
dev - > name , local - > dtim_period ) ;
/* this may fail with Symbol/Lucent firmware */
if ( ret = = - ETIMEDOUT )
goto fail ;
}
ret = hostap_set_word ( dev , HFA384X_RID_PROMISCUOUSMODE ,
local - > is_promisc ) ;
if ( ret )
printk ( KERN_INFO " %s: Setting promiscuous mode (%d) failed \n " ,
dev - > name , local - > is_promisc ) ;
if ( ! local - > fw_ap ) {
ret = hostap_set_string ( dev , HFA384X_RID_CNFDESIREDSSID ,
local - > essid ) ;
if ( ret ) {
printk ( " %s: Desired SSID setting failed \n " , dev - > name ) ;
goto fail ;
}
}
/* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and
* 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic
* rates */
if ( local - > tx_rate_control = = 0 ) {
local - > tx_rate_control =
HFA384X_RATES_1MBPS |
HFA384X_RATES_2MBPS |
HFA384X_RATES_5MBPS |
HFA384X_RATES_11MBPS ;
}
if ( local - > basic_rates = = 0 )
local - > basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS ;
if ( ! local - > fw_ap ) {
ret = hostap_set_word ( dev , HFA384X_RID_TXRATECONTROL ,
local - > tx_rate_control ) ;
if ( ret ) {
printk ( " %s: TXRateControl setting to %d failed \n " ,
dev - > name , local - > tx_rate_control ) ;
goto fail ;
}
ret = hostap_set_word ( dev , HFA384X_RID_CNFSUPPORTEDRATES ,
local - > tx_rate_control ) ;
if ( ret ) {
printk ( " %s: cnfSupportedRates setting to %d failed \n " ,
dev - > name , local - > tx_rate_control ) ;
}
ret = hostap_set_word ( dev , HFA384X_RID_CNFBASICRATES ,
local - > basic_rates ) ;
if ( ret ) {
printk ( " %s: cnfBasicRates setting to %d failed \n " ,
dev - > name , local - > basic_rates ) ;
}
ret = hostap_set_word ( dev , HFA384X_RID_CREATEIBSS , 1 ) ;
if ( ret ) {
printk ( " %s: Create IBSS setting to 1 failed \n " ,
dev - > name ) ;
}
}
if ( local - > name_set )
( void ) hostap_set_string ( dev , HFA384X_RID_CNFOWNNAME ,
local - > name ) ;
if ( hostap_set_encryption ( local ) ) {
printk ( KERN_INFO " %s: could not configure encryption \n " ,
dev - > name ) ;
}
( void ) hostap_set_antsel ( local ) ;
if ( hostap_set_roaming ( local ) ) {
printk ( KERN_INFO " %s: could not set host roaming \n " ,
dev - > name ) ;
}
if ( local - > sta_fw_ver > = PRISM2_FW_VER ( 1 , 6 , 3 ) & &
hostap_set_word ( dev , HFA384X_RID_CNFENHSECURITY , local - > enh_sec ) )
printk ( KERN_INFO " %s: cnfEnhSecurity setting to 0x%x failed \n " ,
dev - > name , local - > enh_sec ) ;
/* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently
* not working correctly ( last seven counters report bogus values ) .
* This has been fixed in 0.8 .2 , so enable 32 - bit tallies only
* beginning with that firmware version . Another bug fix for 32 - bit
* tallies in 1.4 .0 ; should 16 - bit tallies be used for some other
* versions , too ? */
if ( local - > sta_fw_ver > = PRISM2_FW_VER ( 0 , 8 , 2 ) ) {
if ( hostap_set_word ( dev , HFA384X_RID_CNFTHIRTY2TALLY , 1 ) ) {
printk ( KERN_INFO " %s: cnfThirty2Tally setting "
" failed \n " , dev - > name ) ;
local - > tallies32 = 0 ;
} else
local - > tallies32 = 1 ;
} else
local - > tallies32 = 0 ;
hostap_set_auth_algs ( local ) ;
if ( hostap_set_word ( dev , HFA384X_RID_FRAGMENTATIONTHRESHOLD ,
local - > fragm_threshold ) ) {
printk ( KERN_INFO " %s: setting FragmentationThreshold to %d "
" failed \n " , dev - > name , local - > fragm_threshold ) ;
}
if ( hostap_set_word ( dev , HFA384X_RID_RTSTHRESHOLD ,
local - > rts_threshold ) ) {
printk ( KERN_INFO " %s: setting RTSThreshold to %d failed \n " ,
dev - > name , local - > rts_threshold ) ;
}
if ( local - > manual_retry_count > = 0 & &
hostap_set_word ( dev , HFA384X_RID_CNFALTRETRYCOUNT ,
local - > manual_retry_count ) ) {
printk ( KERN_INFO " %s: setting cnfAltRetryCount to %d failed \n " ,
dev - > name , local - > manual_retry_count ) ;
}
if ( local - > sta_fw_ver > = PRISM2_FW_VER ( 1 , 3 , 1 ) & &
hfa384x_get_rid ( dev , HFA384X_RID_CNFDBMADJUST , & tmp , 2 , 1 ) = = 2 ) {
local - > rssi_to_dBm = le16_to_cpu ( tmp ) ;
}
if ( local - > sta_fw_ver > = PRISM2_FW_VER ( 1 , 7 , 0 ) & & local - > wpa & &
hostap_set_word ( dev , HFA384X_RID_SSNHANDLINGMODE , 1 ) ) {
printk ( KERN_INFO " %s: setting ssnHandlingMode to 1 failed \n " ,
dev - > name ) ;
}
if ( local - > sta_fw_ver > = PRISM2_FW_VER ( 1 , 7 , 0 ) & & local - > generic_elem & &
hfa384x_set_rid ( dev , HFA384X_RID_GENERICELEMENT ,
local - > generic_elem , local - > generic_elem_len ) ) {
printk ( KERN_INFO " %s: setting genericElement failed \n " ,
dev - > name ) ;
}
fail :
return ret ;
}
static int prism2_hw_init ( struct net_device * dev , int initial )
{
struct hostap_interface * iface ;
local_info_t * local ;
int ret , first = 1 ;
unsigned long start , delay ;
PDEBUG ( DEBUG_FLOW , " prism2_hw_init() \n " ) ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
clear_bit ( HOSTAP_BITS_TRANSMIT , & local - > bits ) ;
init :
/* initialize HFA 384x */
ret = hfa384x_cmd_no_wait ( dev , HFA384X_CMDCODE_INIT , 0 ) ;
if ( ret ) {
printk ( KERN_INFO " %s: first command failed - assuming card "
" does not have primary firmware \n " , dev_info ) ;
}
if ( first & & ( HFA384X_INW ( HFA384X_EVSTAT_OFF ) & HFA384X_EV_CMD ) ) {
/* EvStat has Cmd bit set in some cases, so retry once if no
* wait was needed */
HFA384X_OUTW ( HFA384X_EV_CMD , HFA384X_EVACK_OFF ) ;
printk ( KERN_DEBUG " %s: init command completed too quickly - "
" retrying \n " , dev - > name ) ;
first = 0 ;
goto init ;
}
start = jiffies ;
delay = jiffies + HFA384X_INIT_TIMEOUT ;
while ( ! ( HFA384X_INW ( HFA384X_EVSTAT_OFF ) & HFA384X_EV_CMD ) & &
time_before ( jiffies , delay ) )
yield ( ) ;
if ( ! ( HFA384X_INW ( HFA384X_EVSTAT_OFF ) & HFA384X_EV_CMD ) ) {
printk ( KERN_DEBUG " %s: assuming no Primary image in "
" flash - card initialization not completed \n " ,
dev_info ) ;
local - > no_pri = 1 ;
# ifdef PRISM2_DOWNLOAD_SUPPORT
if ( local - > sram_type = = - 1 )
local - > sram_type = prism2_get_ram_size ( local ) ;
# endif /* PRISM2_DOWNLOAD_SUPPORT */
return 1 ;
}
local - > no_pri = 0 ;
printk ( KERN_DEBUG " prism2_hw_init: initialized in %lu ms \n " ,
( jiffies - start ) * 1000 / HZ ) ;
HFA384X_OUTW ( HFA384X_EV_CMD , HFA384X_EVACK_OFF ) ;
return 0 ;
}
static int prism2_hw_init2 ( struct net_device * dev , int initial )
{
struct hostap_interface * iface ;
local_info_t * local ;
int i ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
# ifdef PRISM2_DOWNLOAD_SUPPORT
kfree ( local - > pda ) ;
if ( local - > no_pri )
local - > pda = NULL ;
else
local - > pda = prism2_read_pda ( dev ) ;
# endif /* PRISM2_DOWNLOAD_SUPPORT */
hfa384x_disable_interrupts ( dev ) ;
# ifndef final_version
HFA384X_OUTW ( HFA384X_MAGIC , HFA384X_SWSUPPORT0_OFF ) ;
if ( HFA384X_INW ( HFA384X_SWSUPPORT0_OFF ) ! = HFA384X_MAGIC ) {
printk ( " SWSUPPORT0 write/read failed: %04X != %04X \n " ,
HFA384X_INW ( HFA384X_SWSUPPORT0_OFF ) , HFA384X_MAGIC ) ;
goto failed ;
}
# endif
if ( initial | | local - > pri_only ) {
hfa384x_events_only_cmd ( dev ) ;
/* get card version information */
if ( prism2_get_version_info ( dev , HFA384X_RID_NICID , " NIC " ) | |
prism2_get_version_info ( dev , HFA384X_RID_PRIID , " PRI " ) ) {
hfa384x_disable_interrupts ( dev ) ;
goto failed ;
}
if ( prism2_get_version_info ( dev , HFA384X_RID_STAID , " STA " ) ) {
printk ( KERN_DEBUG " %s: Failed to read STA f/w version "
" - only Primary f/w present \n " , dev - > name ) ;
local - > pri_only = 1 ;
return 0 ;
}
local - > pri_only = 0 ;
hfa384x_disable_interrupts ( dev ) ;
}
/* FIX: could convert allocate_fid to use sleeping CmdCompl wait and
* enable interrupts before this . This would also require some sort of
* sleeping AllocEv waiting */
/* allocate TX FIDs */
local - > txfid_len = PRISM2_TXFID_LEN ;
for ( i = 0 ; i < PRISM2_TXFID_COUNT ; i + + ) {
local - > txfid [ i ] = hfa384x_allocate_fid ( dev , local - > txfid_len ) ;
if ( local - > txfid [ i ] = = 0xffff & & local - > txfid_len > 1600 ) {
local - > txfid [ i ] = hfa384x_allocate_fid ( dev , 1600 ) ;
if ( local - > txfid [ i ] ! = 0xffff ) {
printk ( KERN_DEBUG " %s: Using shorter TX FID "
" (1600 bytes) \n " , dev - > name ) ;
local - > txfid_len = 1600 ;
}
}
if ( local - > txfid [ i ] = = 0xffff )
goto failed ;
local - > intransmitfid [ i ] = PRISM2_TXFID_EMPTY ;
}
hfa384x_events_only_cmd ( dev ) ;
if ( initial ) {
struct list_head * ptr ;
prism2_check_sta_fw_version ( local ) ;
if ( hfa384x_get_rid ( dev , HFA384X_RID_CNFOWNMACADDR ,
& dev - > dev_addr , 6 , 1 ) < 0 ) {
printk ( " %s: could not get own MAC address \n " ,
dev - > name ) ;
}
list_for_each ( ptr , & local - > hostap_interfaces ) {
iface = list_entry ( ptr , struct hostap_interface , list ) ;
memcpy ( iface - > dev - > dev_addr , dev - > dev_addr , ETH_ALEN ) ;
}
} else if ( local - > fw_ap )
prism2_check_sta_fw_version ( local ) ;
prism2_setup_rids ( dev ) ;
/* MAC is now configured, but port 0 is not yet enabled */
return 0 ;
failed :
if ( ! local - > no_pri )
printk ( KERN_WARNING " %s: Initialization failed \n " , dev_info ) ;
return 1 ;
}
static int prism2_hw_enable ( struct net_device * dev , int initial )
{
struct hostap_interface * iface ;
local_info_t * local ;
int was_resetting ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
was_resetting = local - > hw_resetting ;
if ( hfa384x_cmd ( dev , HFA384X_CMDCODE_ENABLE , 0 , NULL , NULL ) ) {
printk ( " %s: MAC port 0 enabling failed \n " , dev - > name ) ;
return 1 ;
}
local - > hw_ready = 1 ;
local - > hw_reset_tries = 0 ;
local - > hw_resetting = 0 ;
hfa384x_enable_interrupts ( dev ) ;
/* at least D-Link DWL-650 seems to require additional port reset
* before it starts acting as an AP , so reset port automatically
* here just in case */
if ( initial & & prism2_reset_port ( dev ) ) {
printk ( " %s: MAC port 0 reseting failed \n " , dev - > name ) ;
return 1 ;
}
if ( was_resetting & & netif_queue_stopped ( dev ) ) {
/* If hw_reset() was called during pending transmit, netif
* queue was stopped . Wake it up now since the wlan card has
* been resetted . */
netif_wake_queue ( dev ) ;
}
return 0 ;
}
static int prism2_hw_config ( struct net_device * dev , int initial )
{
struct hostap_interface * iface ;
local_info_t * local ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( local - > hw_downloading )
return 1 ;
if ( prism2_hw_init ( dev , initial ) ) {
return local - > no_pri ? 0 : 1 ;
}
if ( prism2_hw_init2 ( dev , initial ) )
return 1 ;
/* Enable firmware if secondary image is loaded and at least one of the
* netdevices is up . */
if ( ! local - > pri_only & &
( initial = = 0 | | ( initial = = 2 & & local - > num_dev_open > 0 ) ) ) {
if ( ! local - > dev_enabled )
prism2_callback ( local , PRISM2_CALLBACK_ENABLE ) ;
local - > dev_enabled = 1 ;
return prism2_hw_enable ( dev , initial ) ;
}
return 0 ;
}
static void prism2_hw_shutdown ( struct net_device * dev , int no_disable )
{
struct hostap_interface * iface ;
local_info_t * local ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
/* Allow only command completion events during disable */
hfa384x_events_only_cmd ( dev ) ;
local - > hw_ready = 0 ;
if ( local - > dev_enabled )
prism2_callback ( local , PRISM2_CALLBACK_DISABLE ) ;
local - > dev_enabled = 0 ;
if ( local - > func - > card_present & & ! local - > func - > card_present ( local ) ) {
printk ( KERN_DEBUG " %s: card already removed or not configured "
" during shutdown \n " , dev - > name ) ;
return ;
}
if ( ( no_disable & HOSTAP_HW_NO_DISABLE ) = = 0 & &
hfa384x_cmd ( dev , HFA384X_CMDCODE_DISABLE , 0 , NULL , NULL ) )
printk ( KERN_WARNING " %s: Shutdown failed \n " , dev_info ) ;
hfa384x_disable_interrupts ( dev ) ;
if ( no_disable & HOSTAP_HW_ENABLE_CMDCOMPL )
hfa384x_events_only_cmd ( dev ) ;
else
prism2_clear_cmd_queue ( local ) ;
}
static void prism2_hw_reset ( struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
#if 0
static long last_reset = 0 ;
/* do not reset card more than once per second to avoid ending up in a
* busy loop reseting the card */
if ( time_before_eq ( jiffies , last_reset + HZ ) )
return ;
last_reset = jiffies ;
# endif
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( in_interrupt ( ) ) {
printk ( KERN_DEBUG " %s: driver bug - prism2_hw_reset() called "
" in interrupt context \n " , dev - > name ) ;
return ;
}
if ( local - > hw_downloading )
return ;
if ( local - > hw_resetting ) {
printk ( KERN_WARNING " %s: %s: already resetting card - "
" ignoring reset request \n " , dev_info , dev - > name ) ;
return ;
}
local - > hw_reset_tries + + ;
if ( local - > hw_reset_tries > 10 ) {
printk ( KERN_WARNING " %s: too many reset tries, skipping \n " ,
dev - > name ) ;
return ;
}
printk ( KERN_WARNING " %s: %s: resetting card \n " , dev_info , dev - > name ) ;
hfa384x_disable_interrupts ( dev ) ;
local - > hw_resetting = 1 ;
if ( local - > func - > cor_sreset ) {
/* Host system seems to hang in some cases with high traffic
* load or shared interrupts during COR sreset . Disable shared
* interrupts during reset to avoid these crashes . COS sreset
* takes quite a long time , so it is unfortunate that this
* seems to be needed . Anyway , I do not know of any better way
* of avoiding the crash . */
disable_irq ( dev - > irq ) ;
local - > func - > cor_sreset ( local ) ;
enable_irq ( dev - > irq ) ;
}
prism2_hw_shutdown ( dev , 1 ) ;
prism2_hw_config ( dev , 0 ) ;
local - > hw_resetting = 0 ;
# ifdef PRISM2_DOWNLOAD_SUPPORT
if ( local - > dl_pri ) {
printk ( KERN_DEBUG " %s: persistent download of primary "
" firmware \n " , dev - > name ) ;
if ( prism2_download_genesis ( local , local - > dl_pri ) < 0 )
printk ( KERN_WARNING " %s: download (PRI) failed \n " ,
dev - > name ) ;
}
if ( local - > dl_sec ) {
printk ( KERN_DEBUG " %s: persistent download of secondary "
" firmware \n " , dev - > name ) ;
if ( prism2_download_volatile ( local , local - > dl_sec ) < 0 )
printk ( KERN_WARNING " %s: download (SEC) failed \n " ,
dev - > name ) ;
}
# endif /* PRISM2_DOWNLOAD_SUPPORT */
/* TODO: restore beacon TIM bits for STAs that have buffered frames */
}
static void prism2_schedule_reset ( local_info_t * local )
{
schedule_work ( & local - > reset_queue ) ;
}
/* Called only as scheduled task after noticing card timeout in interrupt
* context */
static void handle_reset_queue ( void * data )
{
local_info_t * local = ( local_info_t * ) data ;
printk ( KERN_DEBUG " %s: scheduled card reset \n " , local - > dev - > name ) ;
prism2_hw_reset ( local - > dev ) ;
if ( netif_queue_stopped ( local - > dev ) ) {
int i ;
for ( i = 0 ; i < PRISM2_TXFID_COUNT ; i + + )
if ( local - > intransmitfid [ i ] = = PRISM2_TXFID_EMPTY ) {
PDEBUG ( DEBUG_EXTRA , " prism2_tx_timeout: "
" wake up queue \n " ) ;
netif_wake_queue ( local - > dev ) ;
break ;
}
}
}
static int prism2_get_txfid_idx ( local_info_t * local )
{
int idx , end ;
unsigned long flags ;
spin_lock_irqsave ( & local - > txfidlock , flags ) ;
end = idx = local - > next_txfid ;
do {
if ( local - > intransmitfid [ idx ] = = PRISM2_TXFID_EMPTY ) {
local - > intransmitfid [ idx ] = PRISM2_TXFID_RESERVED ;
spin_unlock_irqrestore ( & local - > txfidlock , flags ) ;
return idx ;
}
idx + + ;
if ( idx > = PRISM2_TXFID_COUNT )
idx = 0 ;
} while ( idx ! = end ) ;
spin_unlock_irqrestore ( & local - > txfidlock , flags ) ;
PDEBUG ( DEBUG_EXTRA2 , " prism2_get_txfid_idx: no room in txfid buf: "
" packet dropped \n " ) ;
local - > stats . tx_dropped + + ;
return - 1 ;
}
/* Called only from hardware IRQ */
2005-07-30 12:50:05 -07:00
static void prism2_transmit_cb ( struct net_device * dev , long context ,
2005-05-12 22:54:16 -04:00
u16 resp0 , u16 res )
{
struct hostap_interface * iface ;
local_info_t * local ;
int idx = ( int ) context ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( res ) {
printk ( KERN_DEBUG " %s: prism2_transmit_cb - res=0x%02x \n " ,
dev - > name , res ) ;
return ;
}
if ( idx < 0 | | idx > = PRISM2_TXFID_COUNT ) {
printk ( KERN_DEBUG " %s: prism2_transmit_cb called with invalid "
" idx=%d \n " , dev - > name , idx ) ;
return ;
}
if ( ! test_and_clear_bit ( HOSTAP_BITS_TRANSMIT , & local - > bits ) ) {
printk ( KERN_DEBUG " %s: driver bug: prism2_transmit_cb called "
" with no pending transmit \n " , dev - > name ) ;
}
if ( netif_queue_stopped ( dev ) ) {
/* ready for next TX, so wake up queue that was stopped in
* prism2_transmit ( ) */
netif_wake_queue ( dev ) ;
}
spin_lock ( & local - > txfidlock ) ;
/* With reclaim, Resp0 contains new txfid for transmit; the old txfid
* will be automatically allocated for the next TX frame */
local - > intransmitfid [ idx ] = resp0 ;
PDEBUG ( DEBUG_FID , " %s: prism2_transmit_cb: txfid[%d]=0x%04x, "
" resp0=0x%04x, transmit_txfid=0x%04x \n " ,
dev - > name , idx , local - > txfid [ idx ] ,
resp0 , local - > intransmitfid [ local - > next_txfid ] ) ;
idx + + ;
if ( idx > = PRISM2_TXFID_COUNT )
idx = 0 ;
local - > next_txfid = idx ;
/* check if all TX buffers are occupied */
do {
if ( local - > intransmitfid [ idx ] = = PRISM2_TXFID_EMPTY ) {
spin_unlock ( & local - > txfidlock ) ;
return ;
}
idx + + ;
if ( idx > = PRISM2_TXFID_COUNT )
idx = 0 ;
} while ( idx ! = local - > next_txfid ) ;
spin_unlock ( & local - > txfidlock ) ;
/* no empty TX buffers, stop queue */
netif_stop_queue ( dev ) ;
}
/* Called only from software IRQ if PCI bus master is not used (with bus master
* this can be called both from software and hardware IRQ ) */
static int prism2_transmit ( struct net_device * dev , int idx )
{
struct hostap_interface * iface ;
local_info_t * local ;
int res ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
/* The driver tries to stop netif queue so that there would not be
* more than one attempt to transmit frames going on ; check that this
* is really the case */
if ( test_and_set_bit ( HOSTAP_BITS_TRANSMIT , & local - > bits ) ) {
printk ( KERN_DEBUG " %s: driver bug - prism2_transmit() called "
" when previous TX was pending \n " , dev - > name ) ;
return - 1 ;
}
/* stop the queue for the time that transmit is pending */
netif_stop_queue ( dev ) ;
/* transmit packet */
res = hfa384x_cmd_callback (
dev ,
HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM ,
local - > txfid [ idx ] ,
2005-07-30 12:50:05 -07:00
prism2_transmit_cb , ( long ) idx ) ;
2005-05-12 22:54:16 -04:00
if ( res ) {
struct net_device_stats * stats ;
printk ( KERN_DEBUG " %s: prism2_transmit: CMDCODE_TRANSMIT "
" failed (res=%d) \n " , dev - > name , res ) ;
stats = hostap_get_stats ( dev ) ;
stats - > tx_dropped + + ;
netif_wake_queue ( dev ) ;
return - 1 ;
}
dev - > trans_start = jiffies ;
/* Since we did not wait for command completion, the card continues
* to process on the background and we will finish handling when
* command completion event is handled ( prism2_cmd_ev ( ) function ) */
return 0 ;
}
/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and
* send the payload with this descriptor ) */
/* Called only from software IRQ */
static int prism2_tx_80211 ( struct sk_buff * skb , struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
struct hfa384x_tx_frame txdesc ;
struct hostap_skb_tx_data * meta ;
int hdr_len , data_len , idx , res , ret = - 1 ;
u16 tx_control , fc ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
meta = ( struct hostap_skb_tx_data * ) skb - > cb ;
prism2_callback ( local , PRISM2_CALLBACK_TX_START ) ;
if ( ( local - > func - > card_present & & ! local - > func - > card_present ( local ) ) | |
! local - > hw_ready | | local - > hw_downloading | | local - > pri_only ) {
if ( net_ratelimit ( ) ) {
printk ( KERN_DEBUG " %s: prism2_tx_80211: hw not ready - "
" skipping \n " , dev - > name ) ;
}
goto fail ;
}
memset ( & txdesc , 0 , sizeof ( txdesc ) ) ;
/* skb->data starts with txdesc->frame_control */
hdr_len = 24 ;
memcpy ( & txdesc . frame_control , skb - > data , hdr_len ) ;
fc = le16_to_cpu ( txdesc . frame_control ) ;
2005-08-14 19:08:44 -07:00
if ( WLAN_FC_GET_TYPE ( fc ) = = IEEE80211_FTYPE_DATA & &
2005-05-12 22:54:16 -04:00
( fc & WLAN_FC_FROMDS ) & & ( fc & WLAN_FC_TODS ) & & skb - > len > = 30 ) {
/* Addr4 */
memcpy ( txdesc . addr4 , skb - > data + hdr_len , ETH_ALEN ) ;
hdr_len + = ETH_ALEN ;
}
tx_control = local - > tx_control ;
if ( meta - > tx_cb_idx ) {
tx_control | = HFA384X_TX_CTRL_TX_OK ;
txdesc . sw_support = cpu_to_le16 ( meta - > tx_cb_idx ) ;
}
txdesc . tx_control = cpu_to_le16 ( tx_control ) ;
txdesc . tx_rate = meta - > rate ;
data_len = skb - > len - hdr_len ;
txdesc . data_len = cpu_to_le16 ( data_len ) ;
txdesc . len = cpu_to_be16 ( data_len ) ;
idx = prism2_get_txfid_idx ( local ) ;
if ( idx < 0 )
goto fail ;
if ( local - > frame_dump & PRISM2_DUMP_TX_HDR )
hostap_dump_tx_header ( dev - > name , & txdesc ) ;
spin_lock ( & local - > baplock ) ;
res = hfa384x_setup_bap ( dev , BAP0 , local - > txfid [ idx ] , 0 ) ;
if ( ! res )
res = hfa384x_to_bap ( dev , BAP0 , & txdesc , sizeof ( txdesc ) ) ;
if ( ! res )
res = hfa384x_to_bap ( dev , BAP0 , skb - > data + hdr_len ,
skb - > len - hdr_len ) ;
spin_unlock ( & local - > baplock ) ;
if ( ! res )
res = prism2_transmit ( dev , idx ) ;
if ( res ) {
printk ( KERN_DEBUG " %s: prism2_tx_80211 - to BAP0 failed \n " ,
dev - > name ) ;
local - > intransmitfid [ idx ] = PRISM2_TXFID_EMPTY ;
schedule_work ( & local - > reset_queue ) ;
goto fail ;
}
ret = 0 ;
fail :
prism2_callback ( local , PRISM2_CALLBACK_TX_END ) ;
return ret ;
}
/* Some SMP systems have reported number of odd errors with hostap_pci. fid
* register has changed values between consecutive reads for an unknown reason .
* This should really not happen , so more debugging is needed . This test
* version is a big slower , but it will detect most of such register changes
* and will try to get the correct fid eventually . */
# define EXTRA_FID_READ_TESTS
static inline u16 prism2_read_fid_reg ( struct net_device * dev , u16 reg )
{
# ifdef EXTRA_FID_READ_TESTS
u16 val , val2 , val3 ;
int i ;
for ( i = 0 ; i < 10 ; i + + ) {
val = HFA384X_INW ( reg ) ;
val2 = HFA384X_INW ( reg ) ;
val3 = HFA384X_INW ( reg ) ;
if ( val = = val2 & & val = = val3 )
return val ;
printk ( KERN_DEBUG " %s: detected fid change (try=%d, reg=%04x): "
" %04x %04x %04x \n " ,
dev - > name , i , reg , val , val2 , val3 ) ;
if ( ( val = = val2 | | val = = val3 ) & & val ! = 0 )
return val ;
if ( val2 = = val3 & & val2 ! = 0 )
return val2 ;
}
printk ( KERN_WARNING " %s: Uhhuh.. could not read good fid from reg "
" %04x (%04x %04x %04x) \n " , dev - > name , reg , val , val2 , val3 ) ;
return val ;
# else /* EXTRA_FID_READ_TESTS */
return HFA384X_INW ( reg ) ;
# endif /* EXTRA_FID_READ_TESTS */
}
/* Called only as a tasklet (software IRQ) */
static void prism2_rx ( local_info_t * local )
{
struct net_device * dev = local - > dev ;
int res , rx_pending = 0 ;
u16 len , hdr_len , rxfid , status , macport ;
struct net_device_stats * stats ;
struct hfa384x_rx_frame rxdesc ;
struct sk_buff * skb = NULL ;
prism2_callback ( local , PRISM2_CALLBACK_RX_START ) ;
stats = hostap_get_stats ( dev ) ;
rxfid = prism2_read_fid_reg ( dev , HFA384X_RXFID_OFF ) ;
# ifndef final_version
if ( rxfid = = 0 ) {
rxfid = HFA384X_INW ( HFA384X_RXFID_OFF ) ;
printk ( KERN_DEBUG " prism2_rx: rxfid=0 (next 0x%04x) \n " ,
rxfid ) ;
if ( rxfid = = 0 ) {
schedule_work ( & local - > reset_queue ) ;
goto rx_dropped ;
}
/* try to continue with the new rxfid value */
}
# endif
spin_lock ( & local - > baplock ) ;
res = hfa384x_setup_bap ( dev , BAP0 , rxfid , 0 ) ;
if ( ! res )
res = hfa384x_from_bap ( dev , BAP0 , & rxdesc , sizeof ( rxdesc ) ) ;
if ( res ) {
spin_unlock ( & local - > baplock ) ;
printk ( KERN_DEBUG " %s: copy from BAP0 failed %d \n " , dev - > name ,
res ) ;
if ( res = = - ETIMEDOUT ) {
schedule_work ( & local - > reset_queue ) ;
}
goto rx_dropped ;
}
len = le16_to_cpu ( rxdesc . data_len ) ;
hdr_len = sizeof ( rxdesc ) ;
status = le16_to_cpu ( rxdesc . status ) ;
macport = ( status > > 8 ) & 0x07 ;
/* Drop frames with too large reported payload length. Monitor mode
* seems to sometimes pass frames ( e . g . , ctrl : : ack ) with signed and
* negative value , so allow also values 65522 . . 65534 ( - 14 . . - 2 ) for
* macport 7 */
if ( len > PRISM2_DATA_MAXLEN + 8 /* WEP */ ) {
if ( macport = = 7 & & local - > iw_mode = = IW_MODE_MONITOR ) {
if ( len > = ( u16 ) - 14 ) {
hdr_len - = 65535 - len ;
hdr_len - - ;
}
len = 0 ;
} else {
spin_unlock ( & local - > baplock ) ;
printk ( KERN_DEBUG " %s: Received frame with invalid "
" length 0x%04x \n " , dev - > name , len ) ;
hostap_dump_rx_header ( dev - > name , & rxdesc ) ;
goto rx_dropped ;
}
}
skb = dev_alloc_skb ( len + hdr_len ) ;
if ( ! skb ) {
spin_unlock ( & local - > baplock ) ;
printk ( KERN_DEBUG " %s: RX failed to allocate skb \n " ,
dev - > name ) ;
goto rx_dropped ;
}
skb - > dev = dev ;
memcpy ( skb_put ( skb , hdr_len ) , & rxdesc , hdr_len ) ;
2005-08-14 19:08:40 -07:00
if ( len > 0 )
res = hfa384x_from_bap ( dev , BAP0 , skb_put ( skb , len ) , len ) ;
spin_unlock ( & local - > baplock ) ;
if ( res ) {
printk ( KERN_DEBUG " %s: RX failed to read "
" frame data \n " , dev - > name ) ;
goto rx_dropped ;
2005-05-12 22:54:16 -04:00
}
2005-08-14 19:08:40 -07:00
skb_queue_tail ( & local - > rx_list , skb ) ;
tasklet_schedule ( & local - > rx_tasklet ) ;
2005-05-12 22:54:16 -04:00
rx_exit :
prism2_callback ( local , PRISM2_CALLBACK_RX_END ) ;
if ( ! rx_pending ) {
HFA384X_OUTW ( HFA384X_EV_RX , HFA384X_EVACK_OFF ) ;
}
return ;
rx_dropped :
stats - > rx_dropped + + ;
if ( skb )
dev_kfree_skb ( skb ) ;
goto rx_exit ;
}
/* Called only as a tasklet (software IRQ) */
static void hostap_rx_skb ( local_info_t * local , struct sk_buff * skb )
{
struct hfa384x_rx_frame * rxdesc ;
struct net_device * dev = skb - > dev ;
struct hostap_80211_rx_status stats ;
int hdrlen , rx_hdrlen ;
rx_hdrlen = sizeof ( * rxdesc ) ;
if ( skb - > len < sizeof ( * rxdesc ) ) {
/* Allow monitor mode to receive shorter frames */
if ( local - > iw_mode = = IW_MODE_MONITOR & &
skb - > len > = sizeof ( * rxdesc ) - 30 ) {
rx_hdrlen = skb - > len ;
} else {
dev_kfree_skb ( skb ) ;
return ;
}
}
rxdesc = ( struct hfa384x_rx_frame * ) skb - > data ;
if ( local - > frame_dump & PRISM2_DUMP_RX_HDR & &
skb - > len > = sizeof ( * rxdesc ) )
hostap_dump_rx_header ( dev - > name , rxdesc ) ;
if ( le16_to_cpu ( rxdesc - > status ) & HFA384X_RX_STATUS_FCSERR & &
( ! local - > monitor_allow_fcserr | |
local - > iw_mode ! = IW_MODE_MONITOR ) )
goto drop ;
if ( skb - > len > PRISM2_DATA_MAXLEN ) {
printk ( KERN_DEBUG " %s: RX: len(%d) > MAX(%d) \n " ,
dev - > name , skb - > len , PRISM2_DATA_MAXLEN ) ;
goto drop ;
}
stats . mac_time = le32_to_cpu ( rxdesc - > time ) ;
stats . signal = rxdesc - > signal - local - > rssi_to_dBm ;
stats . noise = rxdesc - > silence - local - > rssi_to_dBm ;
stats . rate = rxdesc - > rate ;
/* Convert Prism2 RX structure into IEEE 802.11 header */
hdrlen = hostap_80211_get_hdrlen ( le16_to_cpu ( rxdesc - > frame_control ) ) ;
if ( hdrlen > rx_hdrlen )
hdrlen = rx_hdrlen ;
memmove ( skb_pull ( skb , rx_hdrlen - hdrlen ) ,
& rxdesc - > frame_control , hdrlen ) ;
hostap_80211_rx ( dev , skb , & stats ) ;
return ;
drop :
dev_kfree_skb ( skb ) ;
}
/* Called only as a tasklet (software IRQ) */
static void hostap_rx_tasklet ( unsigned long data )
{
local_info_t * local = ( local_info_t * ) data ;
struct sk_buff * skb ;
while ( ( skb = skb_dequeue ( & local - > rx_list ) ) ! = NULL )
hostap_rx_skb ( local , skb ) ;
}
/* Called only from hardware IRQ */
static void prism2_alloc_ev ( struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
int idx ;
u16 fid ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
fid = prism2_read_fid_reg ( dev , HFA384X_ALLOCFID_OFF ) ;
PDEBUG ( DEBUG_FID , " FID: interrupt: ALLOC - fid=0x%04x \n " , fid ) ;
spin_lock ( & local - > txfidlock ) ;
idx = local - > next_alloc ;
do {
if ( local - > txfid [ idx ] = = fid ) {
PDEBUG ( DEBUG_FID , " FID: found matching txfid[%d] \n " ,
idx ) ;
# ifndef final_version
if ( local - > intransmitfid [ idx ] = = PRISM2_TXFID_EMPTY )
printk ( " Already released txfid found at idx "
" %d \n " , idx ) ;
if ( local - > intransmitfid [ idx ] = = PRISM2_TXFID_RESERVED )
printk ( " Already reserved txfid found at idx "
" %d \n " , idx ) ;
# endif
local - > intransmitfid [ idx ] = PRISM2_TXFID_EMPTY ;
idx + + ;
local - > next_alloc = idx > = PRISM2_TXFID_COUNT ? 0 :
idx ;
if ( ! test_bit ( HOSTAP_BITS_TRANSMIT , & local - > bits ) & &
netif_queue_stopped ( dev ) )
netif_wake_queue ( dev ) ;
spin_unlock ( & local - > txfidlock ) ;
return ;
}
idx + + ;
if ( idx > = PRISM2_TXFID_COUNT )
idx = 0 ;
} while ( idx ! = local - > next_alloc ) ;
printk ( KERN_WARNING " %s: could not find matching txfid (0x%04x, new "
" read 0x%04x) for alloc event \n " , dev - > name , fid ,
HFA384X_INW ( HFA384X_ALLOCFID_OFF ) ) ;
printk ( KERN_DEBUG " TXFIDs: " ) ;
for ( idx = 0 ; idx < PRISM2_TXFID_COUNT ; idx + + )
printk ( " %04x[%04x] " , local - > txfid [ idx ] ,
local - > intransmitfid [ idx ] ) ;
printk ( " \n " ) ;
spin_unlock ( & local - > txfidlock ) ;
/* FIX: should probably schedule reset; reference to one txfid was lost
* completely . . Bad things will happen if we run out of txfids
* Actually , this will cause netdev watchdog to notice TX timeout and
* then card reset after all txfids have been leaked . */
}
/* Called only as a tasklet (software IRQ) */
static void hostap_tx_callback ( local_info_t * local ,
struct hfa384x_tx_frame * txdesc , int ok ,
char * payload )
{
u16 sw_support , hdrlen , len ;
struct sk_buff * skb ;
struct hostap_tx_callback_info * cb ;
/* Make sure that frame was from us. */
if ( memcmp ( txdesc - > addr2 , local - > dev - > dev_addr , ETH_ALEN ) ) {
printk ( KERN_DEBUG " %s: TX callback - foreign frame \n " ,
local - > dev - > name ) ;
return ;
}
sw_support = le16_to_cpu ( txdesc - > sw_support ) ;
spin_lock ( & local - > lock ) ;
cb = local - > tx_callback ;
while ( cb ! = NULL & & cb - > idx ! = sw_support )
cb = cb - > next ;
spin_unlock ( & local - > lock ) ;
if ( cb = = NULL ) {
printk ( KERN_DEBUG " %s: could not find TX callback (idx %d) \n " ,
local - > dev - > name , sw_support ) ;
return ;
}
hdrlen = hostap_80211_get_hdrlen ( le16_to_cpu ( txdesc - > frame_control ) ) ;
len = le16_to_cpu ( txdesc - > data_len ) ;
skb = dev_alloc_skb ( hdrlen + len ) ;
if ( skb = = NULL ) {
printk ( KERN_DEBUG " %s: hostap_tx_callback failed to allocate "
" skb \n " , local - > dev - > name ) ;
return ;
}
memcpy ( skb_put ( skb , hdrlen ) , ( void * ) & txdesc - > frame_control , hdrlen ) ;
if ( payload )
memcpy ( skb_put ( skb , len ) , payload , len ) ;
skb - > dev = local - > dev ;
skb - > mac . raw = skb - > data ;
cb - > func ( skb , ok , cb - > data ) ;
}
/* Called only as a tasklet (software IRQ) */
static int hostap_tx_compl_read ( local_info_t * local , int error ,
struct hfa384x_tx_frame * txdesc ,
char * * payload )
{
u16 fid , len ;
int res , ret = 0 ;
struct net_device * dev = local - > dev ;
fid = prism2_read_fid_reg ( dev , HFA384X_TXCOMPLFID_OFF ) ;
PDEBUG ( DEBUG_FID , " interrupt: TX (err=%d) - fid=0x%04x \n " , fid , error ) ;
spin_lock ( & local - > baplock ) ;
res = hfa384x_setup_bap ( dev , BAP0 , fid , 0 ) ;
if ( ! res )
res = hfa384x_from_bap ( dev , BAP0 , txdesc , sizeof ( * txdesc ) ) ;
if ( res ) {
PDEBUG ( DEBUG_EXTRA , " %s: TX (err=%d) - fid=0x%04x - could not "
" read txdesc \n " , dev - > name , error , fid ) ;
if ( res = = - ETIMEDOUT ) {
schedule_work ( & local - > reset_queue ) ;
}
ret = - 1 ;
goto fail ;
}
if ( txdesc - > sw_support ) {
len = le16_to_cpu ( txdesc - > data_len ) ;
if ( len < PRISM2_DATA_MAXLEN ) {
* payload = ( char * ) kmalloc ( len , GFP_ATOMIC ) ;
if ( * payload = = NULL | |
hfa384x_from_bap ( dev , BAP0 , * payload , len ) ) {
PDEBUG ( DEBUG_EXTRA , " %s: could not read TX "
" frame payload \n " , dev - > name ) ;
kfree ( * payload ) ;
* payload = NULL ;
ret = - 1 ;
goto fail ;
}
}
}
fail :
spin_unlock ( & local - > baplock ) ;
return ret ;
}
/* Called only as a tasklet (software IRQ) */
static void prism2_tx_ev ( local_info_t * local )
{
struct net_device * dev = local - > dev ;
char * payload = NULL ;
struct hfa384x_tx_frame txdesc ;
if ( hostap_tx_compl_read ( local , 0 , & txdesc , & payload ) )
goto fail ;
if ( local - > frame_dump & PRISM2_DUMP_TX_HDR ) {
PDEBUG ( DEBUG_EXTRA , " %s: TX - status=0x%04x "
" retry_count=%d tx_rate=%d seq_ctrl=%d "
" duration_id=%d \n " ,
dev - > name , le16_to_cpu ( txdesc . status ) ,
txdesc . retry_count , txdesc . tx_rate ,
le16_to_cpu ( txdesc . seq_ctrl ) ,
le16_to_cpu ( txdesc . duration_id ) ) ;
}
if ( txdesc . sw_support )
hostap_tx_callback ( local , & txdesc , 1 , payload ) ;
kfree ( payload ) ;
fail :
HFA384X_OUTW ( HFA384X_EV_TX , HFA384X_EVACK_OFF ) ;
}
/* Called only as a tasklet (software IRQ) */
static void hostap_sta_tx_exc_tasklet ( unsigned long data )
{
local_info_t * local = ( local_info_t * ) data ;
struct sk_buff * skb ;
while ( ( skb = skb_dequeue ( & local - > sta_tx_exc_list ) ) ! = NULL ) {
struct hfa384x_tx_frame * txdesc =
( struct hfa384x_tx_frame * ) skb - > data ;
if ( skb - > len > = sizeof ( * txdesc ) ) {
/* Convert Prism2 RX structure into IEEE 802.11 header
*/
u16 fc = le16_to_cpu ( txdesc - > frame_control ) ;
int hdrlen = hostap_80211_get_hdrlen ( fc ) ;
memmove ( skb_pull ( skb , sizeof ( * txdesc ) - hdrlen ) ,
& txdesc - > frame_control , hdrlen ) ;
hostap_handle_sta_tx_exc ( local , skb ) ;
}
dev_kfree_skb ( skb ) ;
}
}
/* Called only as a tasklet (software IRQ) */
static void prism2_txexc ( local_info_t * local )
{
struct net_device * dev = local - > dev ;
u16 status , fc ;
int show_dump , res ;
char * payload = NULL ;
struct hfa384x_tx_frame txdesc ;
show_dump = local - > frame_dump & PRISM2_DUMP_TXEXC_HDR ;
local - > stats . tx_errors + + ;
res = hostap_tx_compl_read ( local , 1 , & txdesc , & payload ) ;
HFA384X_OUTW ( HFA384X_EV_TXEXC , HFA384X_EVACK_OFF ) ;
if ( res )
return ;
status = le16_to_cpu ( txdesc . status ) ;
/* We produce a TXDROP event only for retry or lifetime
* exceeded , because that ' s the only status that really mean
* that this particular node went away .
* Other errors means that * we * screwed up . - Jean II */
if ( status & ( HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR ) )
{
union iwreq_data wrqu ;
/* Copy 802.11 dest address. */
memcpy ( wrqu . addr . sa_data , txdesc . addr1 , ETH_ALEN ) ;
wrqu . addr . sa_family = ARPHRD_ETHER ;
wireless_send_event ( dev , IWEVTXDROP , & wrqu , NULL ) ;
} else
show_dump = 1 ;
if ( local - > iw_mode = = IW_MODE_MASTER | |
local - > iw_mode = = IW_MODE_REPEAT | |
local - > wds_type & HOSTAP_WDS_AP_CLIENT ) {
struct sk_buff * skb ;
skb = dev_alloc_skb ( sizeof ( txdesc ) ) ;
if ( skb ) {
memcpy ( skb_put ( skb , sizeof ( txdesc ) ) , & txdesc ,
sizeof ( txdesc ) ) ;
skb_queue_tail ( & local - > sta_tx_exc_list , skb ) ;
tasklet_schedule ( & local - > sta_tx_exc_tasklet ) ;
}
}
if ( txdesc . sw_support )
hostap_tx_callback ( local , & txdesc , 0 , payload ) ;
kfree ( payload ) ;
if ( ! show_dump )
return ;
PDEBUG ( DEBUG_EXTRA , " %s: TXEXC - status=0x%04x (%s%s%s%s) "
" tx_control=%04x \n " ,
dev - > name , status ,
status & HFA384X_TX_STATUS_RETRYERR ? " [RetryErr] " : " " ,
status & HFA384X_TX_STATUS_AGEDERR ? " [AgedErr] " : " " ,
status & HFA384X_TX_STATUS_DISCON ? " [Discon] " : " " ,
status & HFA384X_TX_STATUS_FORMERR ? " [FormErr] " : " " ,
le16_to_cpu ( txdesc . tx_control ) ) ;
fc = le16_to_cpu ( txdesc . frame_control ) ;
PDEBUG ( DEBUG_EXTRA , " retry_count=%d tx_rate=%d fc=0x%04x "
" (%s%s%s::%d%s%s) \n " ,
txdesc . retry_count , txdesc . tx_rate , fc ,
2005-08-14 19:08:44 -07:00
WLAN_FC_GET_TYPE ( fc ) = = IEEE80211_FTYPE_MGMT ? " Mgmt " : " " ,
WLAN_FC_GET_TYPE ( fc ) = = IEEE80211_FTYPE_CTL ? " Ctrl " : " " ,
WLAN_FC_GET_TYPE ( fc ) = = IEEE80211_FTYPE_DATA ? " Data " : " " ,
WLAN_FC_GET_STYPE ( fc ) > > 4 ,
2005-05-12 22:54:16 -04:00
fc & WLAN_FC_TODS ? " ToDS " : " " ,
fc & WLAN_FC_FROMDS ? " FromDS " : " " ) ;
PDEBUG ( DEBUG_EXTRA , " A1= " MACSTR " A2= " MACSTR " A3= "
MACSTR " A4= " MACSTR " \n " ,
MAC2STR ( txdesc . addr1 ) , MAC2STR ( txdesc . addr2 ) ,
MAC2STR ( txdesc . addr3 ) , MAC2STR ( txdesc . addr4 ) ) ;
}
/* Called only as a tasklet (software IRQ) */
static void hostap_info_tasklet ( unsigned long data )
{
local_info_t * local = ( local_info_t * ) data ;
struct sk_buff * skb ;
while ( ( skb = skb_dequeue ( & local - > info_list ) ) ! = NULL ) {
hostap_info_process ( local , skb ) ;
dev_kfree_skb ( skb ) ;
}
}
/* Called only as a tasklet (software IRQ) */
static void prism2_info ( local_info_t * local )
{
struct net_device * dev = local - > dev ;
u16 fid ;
int res , left ;
struct hfa384x_info_frame info ;
struct sk_buff * skb ;
fid = HFA384X_INW ( HFA384X_INFOFID_OFF ) ;
spin_lock ( & local - > baplock ) ;
res = hfa384x_setup_bap ( dev , BAP0 , fid , 0 ) ;
if ( ! res )
res = hfa384x_from_bap ( dev , BAP0 , & info , sizeof ( info ) ) ;
if ( res ) {
spin_unlock ( & local - > baplock ) ;
printk ( KERN_DEBUG " Could not get info frame (fid=0x%04x) \n " ,
fid ) ;
if ( res = = - ETIMEDOUT ) {
schedule_work ( & local - > reset_queue ) ;
}
goto out ;
}
le16_to_cpus ( & info . len ) ;
le16_to_cpus ( & info . type ) ;
left = ( info . len - 1 ) * 2 ;
if ( info . len & 0x8000 | | info . len = = 0 | | left > 2060 ) {
/* data register seems to give 0x8000 in some error cases even
* though busy bit is not set in offset register ;
* in addition , length must be at least 1 due to type field */
spin_unlock ( & local - > baplock ) ;
printk ( KERN_DEBUG " %s: Received info frame with invalid "
" length 0x%04x (type 0x%04x) \n " , dev - > name , info . len ,
info . type ) ;
goto out ;
}
skb = dev_alloc_skb ( sizeof ( info ) + left ) ;
if ( skb = = NULL ) {
spin_unlock ( & local - > baplock ) ;
printk ( KERN_DEBUG " %s: Could not allocate skb for info "
" frame \n " , dev - > name ) ;
goto out ;
}
memcpy ( skb_put ( skb , sizeof ( info ) ) , & info , sizeof ( info ) ) ;
if ( left > 0 & & hfa384x_from_bap ( dev , BAP0 , skb_put ( skb , left ) , left ) )
{
spin_unlock ( & local - > baplock ) ;
printk ( KERN_WARNING " %s: Info frame read failed (fid=0x%04x, "
" len=0x%04x, type=0x%04x \n " ,
dev - > name , fid , info . len , info . type ) ;
dev_kfree_skb ( skb ) ;
goto out ;
}
spin_unlock ( & local - > baplock ) ;
skb_queue_tail ( & local - > info_list , skb ) ;
tasklet_schedule ( & local - > info_tasklet ) ;
out :
HFA384X_OUTW ( HFA384X_EV_INFO , HFA384X_EVACK_OFF ) ;
}
/* Called only as a tasklet (software IRQ) */
static void hostap_bap_tasklet ( unsigned long data )
{
local_info_t * local = ( local_info_t * ) data ;
struct net_device * dev = local - > dev ;
u16 ev ;
int frames = 30 ;
if ( local - > func - > card_present & & ! local - > func - > card_present ( local ) )
return ;
set_bit ( HOSTAP_BITS_BAP_TASKLET , & local - > bits ) ;
/* Process all pending BAP events without generating new interrupts
* for them */
while ( frames - - > 0 ) {
ev = HFA384X_INW ( HFA384X_EVSTAT_OFF ) ;
if ( ev = = 0xffff | | ! ( ev & HFA384X_BAP0_EVENTS ) )
break ;
if ( ev & HFA384X_EV_RX )
prism2_rx ( local ) ;
if ( ev & HFA384X_EV_INFO )
prism2_info ( local ) ;
if ( ev & HFA384X_EV_TX )
prism2_tx_ev ( local ) ;
if ( ev & HFA384X_EV_TXEXC )
prism2_txexc ( local ) ;
}
set_bit ( HOSTAP_BITS_BAP_TASKLET2 , & local - > bits ) ;
clear_bit ( HOSTAP_BITS_BAP_TASKLET , & local - > bits ) ;
/* Enable interrupts for new BAP events */
hfa384x_events_all ( dev ) ;
clear_bit ( HOSTAP_BITS_BAP_TASKLET2 , & local - > bits ) ;
}
/* Called only from hardware IRQ */
static void prism2_infdrop ( struct net_device * dev )
{
static unsigned long last_inquire = 0 ;
PDEBUG ( DEBUG_EXTRA , " %s: INFDROP event \n " , dev - > name ) ;
/* some firmware versions seem to get stuck with
* full CommTallies in high traffic load cases ; every
* packet will then cause INFDROP event and CommTallies
* info frame will not be sent automatically . Try to
* get out of this state by inquiring CommTallies . */
if ( ! last_inquire | | time_after ( jiffies , last_inquire + HZ ) ) {
hfa384x_cmd_callback ( dev , HFA384X_CMDCODE_INQUIRE ,
2005-07-30 12:50:05 -07:00
HFA384X_INFO_COMMTALLIES , NULL , 0 ) ;
2005-05-12 22:54:16 -04:00
last_inquire = jiffies ;
}
}
/* Called only from hardware IRQ */
static void prism2_ev_tick ( struct net_device * dev )
{
struct hostap_interface * iface ;
local_info_t * local ;
u16 evstat , inten ;
static int prev_stuck = 0 ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
if ( time_after ( jiffies , local - > last_tick_timer + 5 * HZ ) & &
local - > last_tick_timer ) {
evstat = HFA384X_INW ( HFA384X_EVSTAT_OFF ) ;
inten = HFA384X_INW ( HFA384X_INTEN_OFF ) ;
if ( ! prev_stuck ) {
printk ( KERN_INFO " %s: SW TICK stuck? "
" bits=0x%lx EvStat=%04x IntEn=%04x \n " ,
dev - > name , local - > bits , evstat , inten ) ;
}
local - > sw_tick_stuck + + ;
if ( ( evstat & HFA384X_BAP0_EVENTS ) & &
( inten & HFA384X_BAP0_EVENTS ) ) {
printk ( KERN_INFO " %s: trying to recover from IRQ "
" hang \n " , dev - > name ) ;
hfa384x_events_no_bap0 ( dev ) ;
}
prev_stuck = 1 ;
} else
prev_stuck = 0 ;
}
/* Called only from hardware IRQ */
static inline void prism2_check_magic ( local_info_t * local )
{
/* at least PCI Prism2.5 with bus mastering seems to sometimes
* return 0x0000 in SWSUPPORT0 for unknown reason , but re - reading the
* register once or twice seems to get the correct value . . PCI cards
* cannot anyway be removed during normal operation , so there is not
* really any need for this verification with them . */
# ifndef PRISM2_PCI
# ifndef final_version
static unsigned long last_magic_err = 0 ;
struct net_device * dev = local - > dev ;
if ( HFA384X_INW ( HFA384X_SWSUPPORT0_OFF ) ! = HFA384X_MAGIC ) {
if ( ! local - > hw_ready )
return ;
HFA384X_OUTW ( 0xffff , HFA384X_EVACK_OFF ) ;
if ( time_after ( jiffies , last_magic_err + 10 * HZ ) ) {
printk ( " %s: Interrupt, but SWSUPPORT0 does not match: "
" %04X != %04X - card removed? \n " , dev - > name ,
HFA384X_INW ( HFA384X_SWSUPPORT0_OFF ) ,
HFA384X_MAGIC ) ;
last_magic_err = jiffies ;
} else if ( net_ratelimit ( ) ) {
printk ( KERN_DEBUG " %s: interrupt - SWSUPPORT0=%04x "
" MAGIC=%04x \n " , dev - > name ,
HFA384X_INW ( HFA384X_SWSUPPORT0_OFF ) ,
HFA384X_MAGIC ) ;
}
if ( HFA384X_INW ( HFA384X_SWSUPPORT0_OFF ) ! = 0xffff )
schedule_work ( & local - > reset_queue ) ;
return ;
}
# endif /* final_version */
# endif /* !PRISM2_PCI */
}
/* Called only from hardware IRQ */
static irqreturn_t prism2_interrupt ( int irq , void * dev_id , struct pt_regs * regs )
{
struct net_device * dev = ( struct net_device * ) dev_id ;
struct hostap_interface * iface ;
local_info_t * local ;
int events = 0 ;
u16 ev ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
prism2_io_debug_add ( dev , PRISM2_IO_DEBUG_CMD_INTERRUPT , 0 , 0 ) ;
if ( local - > func - > card_present & & ! local - > func - > card_present ( local ) ) {
if ( net_ratelimit ( ) ) {
printk ( KERN_DEBUG " %s: Interrupt, but dev not OK \n " ,
dev - > name ) ;
}
return IRQ_HANDLED ;
}
prism2_check_magic ( local ) ;
for ( ; ; ) {
ev = HFA384X_INW ( HFA384X_EVSTAT_OFF ) ;
if ( ev = = 0xffff ) {
if ( local - > shutdown )
return IRQ_HANDLED ;
HFA384X_OUTW ( 0xffff , HFA384X_EVACK_OFF ) ;
printk ( KERN_DEBUG " %s: prism2_interrupt: ev=0xffff \n " ,
dev - > name ) ;
return IRQ_HANDLED ;
}
ev & = HFA384X_INW ( HFA384X_INTEN_OFF ) ;
if ( ev = = 0 )
break ;
if ( ev & HFA384X_EV_CMD ) {
prism2_cmd_ev ( dev ) ;
}
/* Above events are needed even before hw is ready, but other
* events should be skipped during initialization . This may
* change for AllocEv if allocate_fid is implemented without
* busy waiting . */
if ( ! local - > hw_ready | | local - > hw_resetting | |
! local - > dev_enabled ) {
ev = HFA384X_INW ( HFA384X_EVSTAT_OFF ) ;
if ( ev & HFA384X_EV_CMD )
goto next_event ;
if ( ( ev & HFA384X_EVENT_MASK ) = = 0 )
return IRQ_HANDLED ;
if ( local - > dev_enabled & & ( ev & ~ HFA384X_EV_TICK ) & &
net_ratelimit ( ) ) {
printk ( KERN_DEBUG " %s: prism2_interrupt: hw "
" not ready; skipping events 0x%04x "
" (IntEn=0x%04x)%s%s%s \n " ,
dev - > name , ev ,
HFA384X_INW ( HFA384X_INTEN_OFF ) ,
! local - > hw_ready ? " (!hw_ready) " : " " ,
local - > hw_resetting ?
" (hw_resetting) " : " " ,
! local - > dev_enabled ?
" (!dev_enabled) " : " " ) ;
}
HFA384X_OUTW ( ev , HFA384X_EVACK_OFF ) ;
return IRQ_HANDLED ;
}
if ( ev & HFA384X_EV_TICK ) {
prism2_ev_tick ( dev ) ;
HFA384X_OUTW ( HFA384X_EV_TICK , HFA384X_EVACK_OFF ) ;
}
if ( ev & HFA384X_EV_ALLOC ) {
prism2_alloc_ev ( dev ) ;
HFA384X_OUTW ( HFA384X_EV_ALLOC , HFA384X_EVACK_OFF ) ;
}
/* Reading data from the card is quite time consuming, so do it
* in tasklets . TX , TXEXC , RX , and INFO events will be ACKed
* and unmasked after needed data has been read completely . */
if ( ev & HFA384X_BAP0_EVENTS ) {
hfa384x_events_no_bap0 ( dev ) ;
tasklet_schedule ( & local - > bap_tasklet ) ;
}
# ifndef final_version
if ( ev & HFA384X_EV_WTERR ) {
PDEBUG ( DEBUG_EXTRA , " %s: WTERR event \n " , dev - > name ) ;
HFA384X_OUTW ( HFA384X_EV_WTERR , HFA384X_EVACK_OFF ) ;
}
# endif /* final_version */
if ( ev & HFA384X_EV_INFDROP ) {
prism2_infdrop ( dev ) ;
HFA384X_OUTW ( HFA384X_EV_INFDROP , HFA384X_EVACK_OFF ) ;
}
next_event :
events + + ;
if ( events > = PRISM2_MAX_INTERRUPT_EVENTS ) {
PDEBUG ( DEBUG_EXTRA , " prism2_interrupt: >%d events "
" (EvStat=0x%04x) \n " ,
PRISM2_MAX_INTERRUPT_EVENTS ,
HFA384X_INW ( HFA384X_EVSTAT_OFF ) ) ;
break ;
}
}
prism2_io_debug_add ( dev , PRISM2_IO_DEBUG_CMD_INTERRUPT , 0 , 1 ) ;
return IRQ_RETVAL ( events ) ;
}
static void prism2_check_sta_fw_version ( local_info_t * local )
{
struct hfa384x_comp_ident comp ;
int id , variant , major , minor ;
if ( hfa384x_get_rid ( local - > dev , HFA384X_RID_STAID ,
& comp , sizeof ( comp ) , 1 ) < 0 )
return ;
local - > fw_ap = 0 ;
id = le16_to_cpu ( comp . id ) ;
if ( id ! = HFA384X_COMP_ID_STA ) {
if ( id = = HFA384X_COMP_ID_FW_AP )
local - > fw_ap = 1 ;
return ;
}
major = __le16_to_cpu ( comp . major ) ;
minor = __le16_to_cpu ( comp . minor ) ;
variant = __le16_to_cpu ( comp . variant ) ;
local - > sta_fw_ver = PRISM2_FW_VER ( major , minor , variant ) ;
/* Station firmware versions before 1.4.x seem to have a bug in
* firmware - based WEP encryption when using Host AP mode , so use
* host_encrypt as a default for them . Firmware version 1.4 .9 is the
* first one that has been seen to produce correct encryption , but the
* bug might be fixed before that ( although , at least 1.4 .2 is broken ) .
*/
local - > fw_encrypt_ok = local - > sta_fw_ver > = PRISM2_FW_VER ( 1 , 4 , 9 ) ;
if ( local - > iw_mode = = IW_MODE_MASTER & & ! local - > host_encrypt & &
! local - > fw_encrypt_ok ) {
printk ( KERN_DEBUG " %s: defaulting to host-based encryption as "
" a workaround for firmware bug in Host AP mode WEP \n " ,
local - > dev - > name ) ;
local - > host_encrypt = 1 ;
}
/* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken
* in station firmware versions before 1.5 . x . With these versions , the
* driver uses a workaround with bogus frame format ( 4 th address after
* the payload ) . This is not compatible with other AP devices . Since
* the firmware bug is fixed in the latest station firmware versions ,
* automatically enable standard compliant mode for cards using station
* firmware version 1.5 .0 or newer . */
if ( local - > sta_fw_ver > = PRISM2_FW_VER ( 1 , 5 , 0 ) )
local - > wds_type | = HOSTAP_WDS_STANDARD_FRAME ;
else {
printk ( KERN_DEBUG " %s: defaulting to bogus WDS frame as a "
" workaround for firmware bug in Host AP mode WDS \n " ,
local - > dev - > name ) ;
}
hostap_check_sta_fw_version ( local - > ap , local - > sta_fw_ver ) ;
}
static void prism2_crypt_deinit_entries ( local_info_t * local , int force )
{
struct list_head * ptr , * n ;
2005-07-30 20:43:20 -07:00
struct ieee80211_crypt_data * entry ;
2005-05-12 22:54:16 -04:00
for ( ptr = local - > crypt_deinit_list . next , n = ptr - > next ;
ptr ! = & local - > crypt_deinit_list ; ptr = n , n = ptr - > next ) {
2005-07-30 20:43:20 -07:00
entry = list_entry ( ptr , struct ieee80211_crypt_data , list ) ;
2005-05-12 22:54:16 -04:00
if ( atomic_read ( & entry - > refcnt ) ! = 0 & & ! force )
continue ;
list_del ( ptr ) ;
if ( entry - > ops )
entry - > ops - > deinit ( entry - > priv ) ;
kfree ( entry ) ;
}
}
static void prism2_crypt_deinit_handler ( unsigned long data )
{
local_info_t * local = ( local_info_t * ) data ;
unsigned long flags ;
spin_lock_irqsave ( & local - > lock , flags ) ;
prism2_crypt_deinit_entries ( local , 0 ) ;
if ( ! list_empty ( & local - > crypt_deinit_list ) ) {
printk ( KERN_DEBUG " %s: entries remaining in delayed crypt "
" deletion list \n " , local - > dev - > name ) ;
local - > crypt_deinit_timer . expires = jiffies + HZ ;
add_timer ( & local - > crypt_deinit_timer ) ;
}
spin_unlock_irqrestore ( & local - > lock , flags ) ;
}
static void hostap_passive_scan ( unsigned long data )
{
local_info_t * local = ( local_info_t * ) data ;
struct net_device * dev = local - > dev ;
u16 channel ;
if ( local - > passive_scan_interval < = 0 )
return ;
if ( local - > passive_scan_state = = PASSIVE_SCAN_LISTEN ) {
int max_tries = 16 ;
/* Even though host system does not really know when the WLAN
* MAC is sending frames , try to avoid changing channels for
* passive scanning when a host - generated frame is being
* transmitted */
if ( test_bit ( HOSTAP_BITS_TRANSMIT , & local - > bits ) ) {
printk ( KERN_DEBUG " %s: passive scan detected pending "
" TX - delaying \n " , dev - > name ) ;
local - > passive_scan_timer . expires = jiffies + HZ / 10 ;
add_timer ( & local - > passive_scan_timer ) ;
return ;
}
do {
local - > passive_scan_channel + + ;
if ( local - > passive_scan_channel > 14 )
local - > passive_scan_channel = 1 ;
max_tries - - ;
} while ( ! ( local - > channel_mask &
( 1 < < ( local - > passive_scan_channel - 1 ) ) ) & &
max_tries > 0 ) ;
if ( max_tries = = 0 ) {
printk ( KERN_INFO " %s: no allowed passive scan channels "
" found \n " , dev - > name ) ;
return ;
}
printk ( KERN_DEBUG " %s: passive scan channel %d \n " ,
dev - > name , local - > passive_scan_channel ) ;
channel = local - > passive_scan_channel ;
local - > passive_scan_state = PASSIVE_SCAN_WAIT ;
local - > passive_scan_timer . expires = jiffies + HZ / 10 ;
} else {
channel = local - > channel ;
local - > passive_scan_state = PASSIVE_SCAN_LISTEN ;
local - > passive_scan_timer . expires = jiffies +
local - > passive_scan_interval * HZ ;
}
if ( hfa384x_cmd_callback ( dev , HFA384X_CMDCODE_TEST |
( HFA384X_TEST_CHANGE_CHANNEL < < 8 ) ,
2005-07-30 12:50:05 -07:00
channel , NULL , 0 ) )
2005-05-12 22:54:16 -04:00
printk ( KERN_ERR " %s: passive scan channel set %d "
" failed \n " , dev - > name , channel ) ;
add_timer ( & local - > passive_scan_timer ) ;
}
/* Called only as a scheduled task when communications quality values should
* be updated . */
static void handle_comms_qual_update ( void * data )
{
local_info_t * local = data ;
prism2_update_comms_qual ( local - > dev ) ;
}
/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is
* used to monitor that local - > last_tick_timer is being updated . If not ,
* interrupt busy - loop is assumed and driver tries to recover by masking out
* some events . */
static void hostap_tick_timer ( unsigned long data )
{
static unsigned long last_inquire = 0 ;
local_info_t * local = ( local_info_t * ) data ;
local - > last_tick_timer = jiffies ;
/* Inquire CommTallies every 10 seconds to keep the statistics updated
* more often during low load and when using 32 - bit tallies . */
if ( ( ! last_inquire | | time_after ( jiffies , last_inquire + 10 * HZ ) ) & &
! local - > hw_downloading & & local - > hw_ready & &
! local - > hw_resetting & & local - > dev_enabled ) {
hfa384x_cmd_callback ( local - > dev , HFA384X_CMDCODE_INQUIRE ,
2005-07-30 12:50:05 -07:00
HFA384X_INFO_COMMTALLIES , NULL , 0 ) ;
2005-05-12 22:54:16 -04:00
last_inquire = jiffies ;
}
if ( ( local - > last_comms_qual_update = = 0 | |
time_after ( jiffies , local - > last_comms_qual_update + 10 * HZ ) ) & &
( local - > iw_mode = = IW_MODE_INFRA | |
local - > iw_mode = = IW_MODE_ADHOC ) ) {
schedule_work ( & local - > comms_qual_update ) ;
}
local - > tick_timer . expires = jiffies + 2 * HZ ;
add_timer ( & local - > tick_timer ) ;
}
# ifndef PRISM2_NO_PROCFS_DEBUG
static int prism2_registers_proc_read ( char * page , char * * start , off_t off ,
int count , int * eof , void * data )
{
char * p = page ;
local_info_t * local = ( local_info_t * ) data ;
if ( off ! = 0 ) {
* eof = 1 ;
return 0 ;
}
# define SHOW_REG(n) \
p + = sprintf ( p , # n " =%04x \n " , hfa384x_read_reg ( local - > dev , HFA384X_ # # n # # _OFF ) )
SHOW_REG ( CMD ) ;
SHOW_REG ( PARAM0 ) ;
SHOW_REG ( PARAM1 ) ;
SHOW_REG ( PARAM2 ) ;
SHOW_REG ( STATUS ) ;
SHOW_REG ( RESP0 ) ;
SHOW_REG ( RESP1 ) ;
SHOW_REG ( RESP2 ) ;
SHOW_REG ( INFOFID ) ;
SHOW_REG ( CONTROL ) ;
SHOW_REG ( SELECT0 ) ;
SHOW_REG ( SELECT1 ) ;
SHOW_REG ( OFFSET0 ) ;
SHOW_REG ( OFFSET1 ) ;
SHOW_REG ( RXFID ) ;
SHOW_REG ( ALLOCFID ) ;
SHOW_REG ( TXCOMPLFID ) ;
SHOW_REG ( SWSUPPORT0 ) ;
SHOW_REG ( SWSUPPORT1 ) ;
SHOW_REG ( SWSUPPORT2 ) ;
SHOW_REG ( EVSTAT ) ;
SHOW_REG ( INTEN ) ;
SHOW_REG ( EVACK ) ;
/* Do not read data registers, because they change the state of the
* MAC ( offset + = 2 ) */
/* SHOW_REG(DATA0); */
/* SHOW_REG(DATA1); */
SHOW_REG ( AUXPAGE ) ;
SHOW_REG ( AUXOFFSET ) ;
/* SHOW_REG(AUXDATA); */
# ifdef PRISM2_PCI
SHOW_REG ( PCICOR ) ;
SHOW_REG ( PCIHCR ) ;
SHOW_REG ( PCI_M0_ADDRH ) ;
SHOW_REG ( PCI_M0_ADDRL ) ;
SHOW_REG ( PCI_M0_LEN ) ;
SHOW_REG ( PCI_M0_CTL ) ;
SHOW_REG ( PCI_STATUS ) ;
SHOW_REG ( PCI_M1_ADDRH ) ;
SHOW_REG ( PCI_M1_ADDRL ) ;
SHOW_REG ( PCI_M1_LEN ) ;
SHOW_REG ( PCI_M1_CTL ) ;
# endif /* PRISM2_PCI */
return ( p - page ) ;
}
# endif /* PRISM2_NO_PROCFS_DEBUG */
struct set_tim_data {
struct list_head list ;
int aid ;
int set ;
} ;
static int prism2_set_tim ( struct net_device * dev , int aid , int set )
{
struct list_head * ptr ;
struct set_tim_data * new_entry ;
struct hostap_interface * iface ;
local_info_t * local ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
new_entry = ( struct set_tim_data * )
kmalloc ( sizeof ( * new_entry ) , GFP_ATOMIC ) ;
if ( new_entry = = NULL ) {
printk ( KERN_DEBUG " %s: prism2_set_tim: kmalloc failed \n " ,
local - > dev - > name ) ;
return - ENOMEM ;
}
memset ( new_entry , 0 , sizeof ( * new_entry ) ) ;
new_entry - > aid = aid ;
new_entry - > set = set ;
spin_lock_bh ( & local - > set_tim_lock ) ;
list_for_each ( ptr , & local - > set_tim_list ) {
struct set_tim_data * entry =
list_entry ( ptr , struct set_tim_data , list ) ;
if ( entry - > aid = = aid ) {
PDEBUG ( DEBUG_PS2 , " %s: prism2_set_tim: aid=%d "
" set=%d ==> %d \n " ,
local - > dev - > name , aid , entry - > set , set ) ;
entry - > set = set ;
kfree ( new_entry ) ;
new_entry = NULL ;
break ;
}
}
if ( new_entry )
list_add_tail ( & new_entry - > list , & local - > set_tim_list ) ;
spin_unlock_bh ( & local - > set_tim_lock ) ;
schedule_work ( & local - > set_tim_queue ) ;
return 0 ;
}
static void handle_set_tim_queue ( void * data )
{
local_info_t * local = ( local_info_t * ) data ;
struct set_tim_data * entry ;
u16 val ;
for ( ; ; ) {
entry = NULL ;
spin_lock_bh ( & local - > set_tim_lock ) ;
if ( ! list_empty ( & local - > set_tim_list ) ) {
entry = list_entry ( local - > set_tim_list . next ,
struct set_tim_data , list ) ;
list_del ( & entry - > list ) ;
}
spin_unlock_bh ( & local - > set_tim_lock ) ;
if ( ! entry )
break ;
PDEBUG ( DEBUG_PS2 , " %s: handle_set_tim_queue: aid=%d set=%d \n " ,
local - > dev - > name , entry - > aid , entry - > set ) ;
val = entry - > aid ;
if ( entry - > set )
val | = 0x8000 ;
if ( hostap_set_word ( local - > dev , HFA384X_RID_CNFTIMCTRL , val ) ) {
printk ( KERN_DEBUG " %s: set_tim failed (aid=%d "
" set=%d) \n " ,
local - > dev - > name , entry - > aid , entry - > set ) ;
}
kfree ( entry ) ;
}
}
static void prism2_clear_set_tim_queue ( local_info_t * local )
{
struct list_head * ptr , * n ;
list_for_each_safe ( ptr , n , & local - > set_tim_list ) {
struct set_tim_data * entry ;
entry = list_entry ( ptr , struct set_tim_data , list ) ;
list_del ( & entry - > list ) ;
kfree ( entry ) ;
}
}
static struct net_device *
2005-07-30 12:49:58 -07:00
prism2_init_local_data ( struct prism2_helper_functions * funcs , int card_idx ,
struct device * sdev )
2005-05-12 22:54:16 -04:00
{
struct net_device * dev ;
struct hostap_interface * iface ;
struct local_info * local ;
int len , i , ret ;
if ( funcs = = NULL )
return NULL ;
len = strlen ( dev_template ) ;
if ( len > = IFNAMSIZ | | strstr ( dev_template , " %d " ) = = NULL ) {
printk ( KERN_WARNING " hostap: Invalid dev_template='%s' \n " ,
dev_template ) ;
return NULL ;
}
len = sizeof ( struct hostap_interface ) +
3 + sizeof ( struct local_info ) +
3 + sizeof ( struct ap_data ) ;
dev = alloc_etherdev ( len ) ;
if ( dev = = NULL )
return NULL ;
iface = netdev_priv ( dev ) ;
local = ( struct local_info * ) ( ( ( ( long ) ( iface + 1 ) ) + 3 ) & ~ 3 ) ;
local - > ap = ( struct ap_data * ) ( ( ( ( long ) ( local + 1 ) ) + 3 ) & ~ 3 ) ;
local - > dev = iface - > dev = dev ;
iface - > local = local ;
iface - > type = HOSTAP_INTERFACE_MASTER ;
INIT_LIST_HEAD ( & local - > hostap_interfaces ) ;
local - > hw_module = THIS_MODULE ;
# ifdef PRISM2_IO_DEBUG
local - > io_debug_enabled = 1 ;
# endif /* PRISM2_IO_DEBUG */
local - > func = funcs ;
local - > func - > cmd = hfa384x_cmd ;
local - > func - > read_regs = hfa384x_read_regs ;
local - > func - > get_rid = hfa384x_get_rid ;
local - > func - > set_rid = hfa384x_set_rid ;
local - > func - > hw_enable = prism2_hw_enable ;
local - > func - > hw_config = prism2_hw_config ;
local - > func - > hw_reset = prism2_hw_reset ;
local - > func - > hw_shutdown = prism2_hw_shutdown ;
local - > func - > reset_port = prism2_reset_port ;
local - > func - > schedule_reset = prism2_schedule_reset ;
# ifdef PRISM2_DOWNLOAD_SUPPORT
local - > func - > read_aux = prism2_download_aux_dump ;
local - > func - > download = prism2_download ;
# endif /* PRISM2_DOWNLOAD_SUPPORT */
local - > func - > tx = prism2_tx_80211 ;
local - > func - > set_tim = prism2_set_tim ;
local - > func - > need_tx_headroom = 0 ; /* no need to add txdesc in
* skb - > data ( FIX : maybe for DMA bus
* mastering ? */
local - > mtu = mtu ;
rwlock_init ( & local - > iface_lock ) ;
spin_lock_init ( & local - > txfidlock ) ;
spin_lock_init ( & local - > cmdlock ) ;
spin_lock_init ( & local - > baplock ) ;
spin_lock_init ( & local - > lock ) ;
init_MUTEX ( & local - > rid_bap_sem ) ;
if ( card_idx < 0 | | card_idx > = MAX_PARM_DEVICES )
card_idx = 0 ;
local - > card_idx = card_idx ;
len = strlen ( essid ) ;
memcpy ( local - > essid , essid ,
len > MAX_SSID_LEN ? MAX_SSID_LEN : len ) ;
local - > essid [ MAX_SSID_LEN ] = ' \0 ' ;
i = GET_INT_PARM ( iw_mode , card_idx ) ;
if ( ( i > = IW_MODE_ADHOC & & i < = IW_MODE_REPEAT ) | |
i = = IW_MODE_MONITOR ) {
local - > iw_mode = i ;
} else {
printk ( KERN_WARNING " prism2: Unknown iw_mode %d; using "
" IW_MODE_MASTER \n " , i ) ;
local - > iw_mode = IW_MODE_MASTER ;
}
local - > channel = GET_INT_PARM ( channel , card_idx ) ;
local - > beacon_int = GET_INT_PARM ( beacon_int , card_idx ) ;
local - > dtim_period = GET_INT_PARM ( dtim_period , card_idx ) ;
local - > wds_max_connections = 16 ;
local - > tx_control = HFA384X_TX_CTRL_FLAGS ;
local - > manual_retry_count = - 1 ;
local - > rts_threshold = 2347 ;
local - > fragm_threshold = 2346 ;
local - > rssi_to_dBm = 100 ; /* default; to be overriden by
* cnfDbmAdjust , if available */
local - > auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY ;
local - > sram_type = - 1 ;
2005-07-30 12:50:01 -07:00
local - > scan_channel_mask = 0xffff ;
2005-05-12 22:54:16 -04:00
/* Initialize task queue structures */
INIT_WORK ( & local - > reset_queue , handle_reset_queue , local ) ;
INIT_WORK ( & local - > set_multicast_list_queue ,
hostap_set_multicast_list_queue , local - > dev ) ;
INIT_WORK ( & local - > set_tim_queue , handle_set_tim_queue , local ) ;
INIT_LIST_HEAD ( & local - > set_tim_list ) ;
spin_lock_init ( & local - > set_tim_lock ) ;
INIT_WORK ( & local - > comms_qual_update , handle_comms_qual_update , local ) ;
/* Initialize tasklets for handling hardware IRQ related operations
* outside hw IRQ handler */
# define HOSTAP_TASKLET_INIT(q, f, d) \
do { memset ( ( q ) , 0 , sizeof ( * ( q ) ) ) ; ( q ) - > func = ( f ) ; ( q ) - > data = ( d ) ; } \
while ( 0 )
HOSTAP_TASKLET_INIT ( & local - > bap_tasklet , hostap_bap_tasklet ,
( unsigned long ) local ) ;
HOSTAP_TASKLET_INIT ( & local - > info_tasklet , hostap_info_tasklet ,
( unsigned long ) local ) ;
hostap_info_init ( local ) ;
HOSTAP_TASKLET_INIT ( & local - > rx_tasklet ,
hostap_rx_tasklet , ( unsigned long ) local ) ;
skb_queue_head_init ( & local - > rx_list ) ;
HOSTAP_TASKLET_INIT ( & local - > sta_tx_exc_tasklet ,
hostap_sta_tx_exc_tasklet , ( unsigned long ) local ) ;
skb_queue_head_init ( & local - > sta_tx_exc_list ) ;
INIT_LIST_HEAD ( & local - > cmd_queue ) ;
init_waitqueue_head ( & local - > hostscan_wq ) ;
INIT_LIST_HEAD ( & local - > crypt_deinit_list ) ;
init_timer ( & local - > crypt_deinit_timer ) ;
local - > crypt_deinit_timer . data = ( unsigned long ) local ;
local - > crypt_deinit_timer . function = prism2_crypt_deinit_handler ;
init_timer ( & local - > passive_scan_timer ) ;
local - > passive_scan_timer . data = ( unsigned long ) local ;
local - > passive_scan_timer . function = hostap_passive_scan ;
init_timer ( & local - > tick_timer ) ;
local - > tick_timer . data = ( unsigned long ) local ;
local - > tick_timer . function = hostap_tick_timer ;
local - > tick_timer . expires = jiffies + 2 * HZ ;
add_timer ( & local - > tick_timer ) ;
INIT_LIST_HEAD ( & local - > bss_list ) ;
hostap_setup_dev ( dev , local , 1 ) ;
local - > saved_eth_header_parse = dev - > hard_header_parse ;
dev - > hard_start_xmit = hostap_master_start_xmit ;
dev - > type = ARPHRD_IEEE80211 ;
dev - > hard_header_parse = hostap_80211_header_parse ;
rtnl_lock ( ) ;
ret = dev_alloc_name ( dev , " wifi%d " ) ;
2005-07-30 12:49:58 -07:00
SET_NETDEV_DEV ( dev , sdev ) ;
2005-05-12 22:54:16 -04:00
if ( ret > = 0 )
ret = register_netdevice ( dev ) ;
rtnl_unlock ( ) ;
if ( ret < 0 ) {
printk ( KERN_WARNING " %s: register netdevice failed! \n " ,
dev_info ) ;
goto fail ;
}
printk ( KERN_INFO " %s: Registered netdevice %s \n " , dev_info , dev - > name ) ;
# ifndef PRISM2_NO_PROCFS_DEBUG
create_proc_read_entry ( " registers " , 0 , local - > proc ,
prism2_registers_proc_read , local ) ;
# endif /* PRISM2_NO_PROCFS_DEBUG */
hostap_init_data ( local ) ;
return dev ;
fail :
free_netdev ( dev ) ;
return NULL ;
}
static int hostap_hw_ready ( struct net_device * dev )
{
struct hostap_interface * iface ;
struct local_info * local ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
local - > ddev = hostap_add_interface ( local , HOSTAP_INTERFACE_MAIN , 0 ,
" " , dev_template ) ;
if ( local - > ddev ) {
if ( local - > iw_mode = = IW_MODE_INFRA | |
local - > iw_mode = = IW_MODE_ADHOC ) {
netif_carrier_off ( local - > dev ) ;
netif_carrier_off ( local - > ddev ) ;
}
hostap_init_proc ( local ) ;
hostap_init_ap_proc ( local ) ;
return 0 ;
}
return - 1 ;
}
static void prism2_free_local_data ( struct net_device * dev )
{
struct hostap_tx_callback_info * tx_cb , * tx_cb_prev ;
int i ;
struct hostap_interface * iface ;
struct local_info * local ;
struct list_head * ptr , * n ;
if ( dev = = NULL )
return ;
iface = netdev_priv ( dev ) ;
local = iface - > local ;
flush_scheduled_work ( ) ;
if ( timer_pending ( & local - > crypt_deinit_timer ) )
del_timer ( & local - > crypt_deinit_timer ) ;
prism2_crypt_deinit_entries ( local , 1 ) ;
if ( timer_pending ( & local - > passive_scan_timer ) )
del_timer ( & local - > passive_scan_timer ) ;
if ( timer_pending ( & local - > tick_timer ) )
del_timer ( & local - > tick_timer ) ;
prism2_clear_cmd_queue ( local ) ;
skb_queue_purge ( & local - > info_list ) ;
skb_queue_purge ( & local - > rx_list ) ;
skb_queue_purge ( & local - > sta_tx_exc_list ) ;
if ( local - > dev_enabled )
prism2_callback ( local , PRISM2_CALLBACK_DISABLE ) ;
for ( i = 0 ; i < WEP_KEYS ; i + + ) {
2005-07-30 20:43:20 -07:00
struct ieee80211_crypt_data * crypt = local - > crypt [ i ] ;
2005-05-12 22:54:16 -04:00
if ( crypt ) {
if ( crypt - > ops )
crypt - > ops - > deinit ( crypt - > priv ) ;
kfree ( crypt ) ;
local - > crypt [ i ] = NULL ;
}
}
if ( local - > ap ! = NULL )
hostap_free_data ( local - > ap ) ;
# ifndef PRISM2_NO_PROCFS_DEBUG
if ( local - > proc ! = NULL )
remove_proc_entry ( " registers " , local - > proc ) ;
# endif /* PRISM2_NO_PROCFS_DEBUG */
hostap_remove_proc ( local ) ;
tx_cb = local - > tx_callback ;
while ( tx_cb ! = NULL ) {
tx_cb_prev = tx_cb ;
tx_cb = tx_cb - > next ;
kfree ( tx_cb_prev ) ;
}
hostap_set_hostapd ( local , 0 , 0 ) ;
hostap_set_hostapd_sta ( local , 0 , 0 ) ;
for ( i = 0 ; i < PRISM2_FRAG_CACHE_LEN ; i + + ) {
if ( local - > frag_cache [ i ] . skb ! = NULL )
dev_kfree_skb ( local - > frag_cache [ i ] . skb ) ;
}
# ifdef PRISM2_DOWNLOAD_SUPPORT
prism2_download_free_data ( local - > dl_pri ) ;
prism2_download_free_data ( local - > dl_sec ) ;
# endif /* PRISM2_DOWNLOAD_SUPPORT */
list_for_each_safe ( ptr , n , & local - > hostap_interfaces ) {
iface = list_entry ( ptr , struct hostap_interface , list ) ;
if ( iface - > type = = HOSTAP_INTERFACE_MASTER ) {
/* special handling for this interface below */
continue ;
}
hostap_remove_interface ( iface - > dev , 0 , 1 ) ;
}
prism2_clear_set_tim_queue ( local ) ;
list_for_each_safe ( ptr , n , & local - > bss_list ) {
struct hostap_bss_info * bss =
list_entry ( ptr , struct hostap_bss_info , list ) ;
kfree ( bss ) ;
}
kfree ( local - > pda ) ;
kfree ( local - > last_scan_results ) ;
kfree ( local - > generic_elem ) ;
unregister_netdev ( local - > dev ) ;
free_netdev ( local - > dev ) ;
}
# ifndef PRISM2_PLX
static void prism2_suspend ( struct net_device * dev )
{
struct hostap_interface * iface ;
struct local_info * local ;
union iwreq_data wrqu ;
iface = dev - > priv ;
local = iface - > local ;
/* Send disconnect event, e.g., to trigger reassociation after resume
* if wpa_supplicant is used . */
memset ( & wrqu , 0 , sizeof ( wrqu ) ) ;
wrqu . ap_addr . sa_family = ARPHRD_ETHER ;
wireless_send_event ( local - > dev , SIOCGIWAP , & wrqu , NULL ) ;
/* Disable hardware and firmware */
prism2_hw_shutdown ( dev , 0 ) ;
}
# endif /* PRISM2_PLX */
/* These might at some point be compiled separately and used as separate
* kernel modules or linked into one */
# ifdef PRISM2_DOWNLOAD_SUPPORT
# include "hostap_download.c"
# endif /* PRISM2_DOWNLOAD_SUPPORT */
# ifdef PRISM2_CALLBACK
/* External hostap_callback.c file can be used to, e.g., blink activity led.
* This can use platform specific code and must define prism2_callback ( )
* function ( if PRISM2_CALLBACK is not defined , these function calls are not
* used . */
# include "hostap_callback.c"
# endif /* PRISM2_CALLBACK */