2010-03-17 14:25:25 +05:30
/*
2011-05-17 13:36:18 +05:30
* Copyright ( c ) 2010 - 2011 Atheros Communications Inc .
2010-03-17 14:25:25 +05:30
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*/
2011-07-15 19:06:33 -04:00
# include <asm/unaligned.h>
2010-03-17 14:25:25 +05:30
# include "htc.h"
2010-06-23 14:20:45 -04:00
/* identify firmware images */
2011-04-13 11:22:42 +05:30
# define FIRMWARE_AR7010_1_1 "htc_7010.fw"
# define FIRMWARE_AR9271 "htc_9271.fw"
2010-06-23 14:20:45 -04:00
MODULE_FIRMWARE ( FIRMWARE_AR7010_1_1 ) ;
MODULE_FIRMWARE ( FIRMWARE_AR9271 ) ;
2010-03-17 14:25:25 +05:30
static struct usb_device_id ath9k_hif_usb_ids [ ] = {
2010-06-17 10:29:01 +05:30
{ USB_DEVICE ( 0x0cf3 , 0x9271 ) } , /* Atheros */
{ USB_DEVICE ( 0x0cf3 , 0x1006 ) } , /* Atheros */
{ USB_DEVICE ( 0x0846 , 0x9030 ) } , /* Netgear N150 */
{ USB_DEVICE ( 0x07D1 , 0x3A10 ) } , /* Dlink Wireless 150 */
{ USB_DEVICE ( 0x13D3 , 0x3327 ) } , /* Azurewave */
{ USB_DEVICE ( 0x13D3 , 0x3328 ) } , /* Azurewave */
2010-11-07 12:50:24 +08:00
{ USB_DEVICE ( 0x13D3 , 0x3346 ) } , /* IMC Networks */
2010-11-10 17:51:24 +05:30
{ USB_DEVICE ( 0x13D3 , 0x3348 ) } , /* Azurewave */
{ USB_DEVICE ( 0x13D3 , 0x3349 ) } , /* Azurewave */
{ USB_DEVICE ( 0x13D3 , 0x3350 ) } , /* Azurewave */
2010-06-17 10:29:01 +05:30
{ USB_DEVICE ( 0x04CA , 0x4605 ) } , /* Liteon */
2010-11-10 17:51:24 +05:30
{ USB_DEVICE ( 0x040D , 0x3801 ) } , /* VIA */
2010-12-13 07:39:32 +05:30
{ USB_DEVICE ( 0x0cf3 , 0xb003 ) } , /* Ubiquiti WifiStation Ext */
2011-09-29 10:42:19 -07:00
{ USB_DEVICE ( 0x057c , 0x8403 ) } , /* AVM FRITZ!WLAN 11N v2 USB */
2010-12-07 16:31:38 +05:30
{ USB_DEVICE ( 0x0cf3 , 0x7015 ) ,
. driver_info = AR9287_USB } , /* Atheros */
2010-11-19 16:53:20 +05:30
{ USB_DEVICE ( 0x1668 , 0x1200 ) ,
2010-12-07 16:31:38 +05:30
. driver_info = AR9287_USB } , /* Verizon */
{ USB_DEVICE ( 0x0cf3 , 0x7010 ) ,
. driver_info = AR9280_USB } , /* Atheros */
{ USB_DEVICE ( 0x0846 , 0x9018 ) ,
. driver_info = AR9280_USB } , /* Netgear WNDA3200 */
{ USB_DEVICE ( 0x083A , 0xA704 ) ,
. driver_info = AR9280_USB } , /* SMC Networks */
2011-06-28 20:13:41 +05:30
{ USB_DEVICE ( 0x0411 , 0x017f ) ,
. driver_info = AR9280_USB } , /* Sony UWA-BR100 */
2010-12-07 16:31:38 +05:30
2011-02-21 07:47:52 +05:30
{ USB_DEVICE ( 0x0cf3 , 0x20ff ) ,
. driver_info = STORAGE_DEVICE } ,
2010-03-17 14:25:25 +05:30
{ } ,
} ;
MODULE_DEVICE_TABLE ( usb , ath9k_hif_usb_ids ) ;
static int __hif_usb_tx ( struct hif_device_usb * hif_dev ) ;
static void hif_usb_regout_cb ( struct urb * urb )
{
struct cmd_buf * cmd = ( struct cmd_buf * ) urb - > context ;
switch ( urb - > status ) {
case 0 :
break ;
case - ENOENT :
case - ECONNRESET :
case - ENODEV :
case - ESHUTDOWN :
2010-04-06 15:28:17 +05:30
goto free ;
2010-03-17 14:25:25 +05:30
default :
break ;
}
if ( cmd ) {
ath9k_htc_txcompletion_cb ( cmd - > hif_dev - > htc_handle ,
2011-04-13 11:26:46 +05:30
cmd - > skb , true ) ;
2010-03-17 14:25:25 +05:30
kfree ( cmd ) ;
}
2010-04-06 15:28:17 +05:30
return ;
free :
2010-04-13 00:29:15 +08:00
kfree_skb ( cmd - > skb ) ;
2010-04-06 15:28:17 +05:30
kfree ( cmd ) ;
2010-03-17 14:25:25 +05:30
}
static int hif_usb_send_regout ( struct hif_device_usb * hif_dev ,
struct sk_buff * skb )
{
struct urb * urb ;
struct cmd_buf * cmd ;
int ret = 0 ;
urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( urb = = NULL )
return - ENOMEM ;
cmd = kzalloc ( sizeof ( * cmd ) , GFP_KERNEL ) ;
if ( cmd = = NULL ) {
usb_free_urb ( urb ) ;
return - ENOMEM ;
}
cmd - > skb = skb ;
cmd - > hif_dev = hif_dev ;
2010-09-14 14:35:55 +05:30
usb_fill_bulk_urb ( urb , hif_dev - > udev ,
usb_sndbulkpipe ( hif_dev - > udev , USB_REG_OUT_PIPE ) ,
2010-03-17 14:25:25 +05:30
skb - > data , skb - > len ,
2010-09-14 14:35:55 +05:30
hif_usb_regout_cb , cmd ) ;
2010-03-17 14:25:25 +05:30
2010-04-06 15:28:17 +05:30
usb_anchor_urb ( urb , & hif_dev - > regout_submitted ) ;
2010-03-17 14:25:25 +05:30
ret = usb_submit_urb ( urb , GFP_KERNEL ) ;
if ( ret ) {
2010-04-06 15:28:17 +05:30
usb_unanchor_urb ( urb ) ;
2010-03-17 14:25:25 +05:30
kfree ( cmd ) ;
}
2010-04-06 15:28:17 +05:30
usb_free_urb ( urb ) ;
2010-03-17 14:25:25 +05:30
return ret ;
}
2011-04-13 11:26:46 +05:30
static void hif_usb_mgmt_cb ( struct urb * urb )
{
struct cmd_buf * cmd = ( struct cmd_buf * ) urb - > context ;
2011-07-17 11:38:49 +05:30
struct hif_device_usb * hif_dev ;
2011-04-13 11:26:46 +05:30
bool txok = true ;
if ( ! cmd | | ! cmd - > skb | | ! cmd - > hif_dev )
return ;
2011-07-17 11:38:49 +05:30
hif_dev = cmd - > hif_dev ;
2011-04-13 11:26:46 +05:30
switch ( urb - > status ) {
case 0 :
break ;
case - ENOENT :
case - ECONNRESET :
case - ENODEV :
case - ESHUTDOWN :
txok = false ;
/*
* If the URBs are being flushed , no need to complete
* this packet .
*/
spin_lock ( & hif_dev - > tx . tx_lock ) ;
if ( hif_dev - > tx . flags & HIF_USB_TX_FLUSH ) {
spin_unlock ( & hif_dev - > tx . tx_lock ) ;
dev_kfree_skb_any ( cmd - > skb ) ;
kfree ( cmd ) ;
return ;
}
spin_unlock ( & hif_dev - > tx . tx_lock ) ;
break ;
default :
txok = false ;
break ;
}
skb_pull ( cmd - > skb , 4 ) ;
ath9k_htc_txcompletion_cb ( cmd - > hif_dev - > htc_handle ,
cmd - > skb , txok ) ;
kfree ( cmd ) ;
}
static int hif_usb_send_mgmt ( struct hif_device_usb * hif_dev ,
struct sk_buff * skb )
{
struct urb * urb ;
struct cmd_buf * cmd ;
int ret = 0 ;
__le16 * hdr ;
urb = usb_alloc_urb ( 0 , GFP_ATOMIC ) ;
if ( urb = = NULL )
return - ENOMEM ;
cmd = kzalloc ( sizeof ( * cmd ) , GFP_ATOMIC ) ;
if ( cmd = = NULL ) {
usb_free_urb ( urb ) ;
return - ENOMEM ;
}
cmd - > skb = skb ;
cmd - > hif_dev = hif_dev ;
hdr = ( __le16 * ) skb_push ( skb , 4 ) ;
* hdr + + = cpu_to_le16 ( skb - > len - 4 ) ;
* hdr + + = cpu_to_le16 ( ATH_USB_TX_STREAM_MODE_TAG ) ;
usb_fill_bulk_urb ( urb , hif_dev - > udev ,
usb_sndbulkpipe ( hif_dev - > udev , USB_WLAN_TX_PIPE ) ,
skb - > data , skb - > len ,
hif_usb_mgmt_cb , cmd ) ;
usb_anchor_urb ( urb , & hif_dev - > mgmt_submitted ) ;
ret = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( ret ) {
usb_unanchor_urb ( urb ) ;
kfree ( cmd ) ;
}
usb_free_urb ( urb ) ;
return ret ;
}
2010-04-23 10:28:09 +05:30
static inline void ath9k_skb_queue_purge ( struct hif_device_usb * hif_dev ,
struct sk_buff_head * list )
{
struct sk_buff * skb ;
while ( ( skb = __skb_dequeue ( list ) ) ! = NULL ) {
dev_kfree_skb_any ( skb ) ;
2011-04-13 11:25:59 +05:30
}
}
static inline void ath9k_skb_queue_complete ( struct hif_device_usb * hif_dev ,
struct sk_buff_head * queue ,
bool txok )
{
struct sk_buff * skb ;
while ( ( skb = __skb_dequeue ( queue ) ) ! = NULL ) {
ath9k_htc_txcompletion_cb ( hif_dev - > htc_handle ,
skb , txok ) ;
2011-04-14 10:38:22 -04:00
if ( txok )
TX_STAT_INC ( skb_success ) ;
else
TX_STAT_INC ( skb_failed ) ;
2010-04-23 10:28:09 +05:30
}
}
2010-03-17 14:25:25 +05:30
static void hif_usb_tx_cb ( struct urb * urb )
{
struct tx_buf * tx_buf = ( struct tx_buf * ) urb - > context ;
2010-05-14 16:50:56 +02:00
struct hif_device_usb * hif_dev ;
2011-04-13 11:25:59 +05:30
bool txok = true ;
2010-03-17 14:25:25 +05:30
2010-05-14 16:50:56 +02:00
if ( ! tx_buf | | ! tx_buf - > hif_dev )
2010-03-17 14:25:25 +05:30
return ;
2010-05-14 16:50:56 +02:00
hif_dev = tx_buf - > hif_dev ;
2010-03-17 14:25:25 +05:30
switch ( urb - > status ) {
case 0 :
break ;
case - ENOENT :
case - ECONNRESET :
case - ENODEV :
case - ESHUTDOWN :
2011-04-13 11:25:59 +05:30
txok = false ;
2010-12-28 14:28:05 +05:30
/*
* If the URBs are being flushed , no need to add this
* URB to the free list .
*/
spin_lock ( & hif_dev - > tx . tx_lock ) ;
if ( hif_dev - > tx . flags & HIF_USB_TX_FLUSH ) {
spin_unlock ( & hif_dev - > tx . tx_lock ) ;
2011-04-13 11:25:59 +05:30
ath9k_skb_queue_purge ( hif_dev , & tx_buf - > skb_queue ) ;
2010-12-28 14:28:05 +05:30
return ;
}
spin_unlock ( & hif_dev - > tx . tx_lock ) ;
2011-04-13 11:25:59 +05:30
break ;
2010-03-17 14:25:25 +05:30
default :
2011-04-13 11:25:59 +05:30
txok = false ;
2010-03-17 14:25:25 +05:30
break ;
}
2011-04-13 11:25:59 +05:30
ath9k_skb_queue_complete ( hif_dev , & tx_buf - > skb_queue , txok ) ;
2010-04-23 10:28:09 +05:30
/* Re-initialize the SKB queue */
tx_buf - > len = tx_buf - > offset = 0 ;
__skb_queue_head_init ( & tx_buf - > skb_queue ) ;
/* Add this TX buffer to the free list */
spin_lock ( & hif_dev - > tx . tx_lock ) ;
list_move_tail ( & tx_buf - > list , & hif_dev - > tx . tx_buf ) ;
hif_dev - > tx . tx_buf_cnt + + ;
if ( ! ( hif_dev - > tx . flags & HIF_USB_TX_STOP ) )
__hif_usb_tx ( hif_dev ) ; /* Check for pending SKBs */
TX_STAT_INC ( buf_completed ) ;
spin_unlock ( & hif_dev - > tx . tx_lock ) ;
2010-04-13 00:29:27 +08:00
}
2010-03-17 14:25:25 +05:30
/* TX lock has to be taken */
static int __hif_usb_tx ( struct hif_device_usb * hif_dev )
{
struct tx_buf * tx_buf = NULL ;
struct sk_buff * nskb = NULL ;
int ret = 0 , i ;
2011-02-27 09:23:52 +05:30
u16 tx_skb_cnt = 0 ;
2010-03-17 14:25:25 +05:30
u8 * buf ;
2011-02-27 09:23:52 +05:30
__le16 * hdr ;
2010-03-17 14:25:25 +05:30
if ( hif_dev - > tx . tx_skb_cnt = = 0 )
return 0 ;
/* Check if a free TX buffer is available */
if ( list_empty ( & hif_dev - > tx . tx_buf ) )
return 0 ;
tx_buf = list_first_entry ( & hif_dev - > tx . tx_buf , struct tx_buf , list ) ;
2010-04-23 10:28:09 +05:30
list_move_tail ( & tx_buf - > list , & hif_dev - > tx . tx_pending ) ;
2010-03-17 14:25:25 +05:30
hif_dev - > tx . tx_buf_cnt - - ;
tx_skb_cnt = min_t ( u16 , hif_dev - > tx . tx_skb_cnt , MAX_TX_AGGR_NUM ) ;
for ( i = 0 ; i < tx_skb_cnt ; i + + ) {
nskb = __skb_dequeue ( & hif_dev - > tx . tx_skb_queue ) ;
/* Should never be NULL */
BUG_ON ( ! nskb ) ;
hif_dev - > tx . tx_skb_cnt - - ;
buf = tx_buf - > buf ;
buf + = tx_buf - > offset ;
2011-02-27 09:23:52 +05:30
hdr = ( __le16 * ) buf ;
* hdr + + = cpu_to_le16 ( nskb - > len ) ;
* hdr + + = cpu_to_le16 ( ATH_USB_TX_STREAM_MODE_TAG ) ;
2010-03-17 14:25:25 +05:30
buf + = 4 ;
memcpy ( buf , nskb - > data , nskb - > len ) ;
tx_buf - > len = nskb - > len + 4 ;
if ( i < ( tx_skb_cnt - 1 ) )
tx_buf - > offset + = ( ( ( tx_buf - > len - 1 ) / 4 ) + 1 ) * 4 ;
if ( i = = ( tx_skb_cnt - 1 ) )
tx_buf - > len + = tx_buf - > offset ;
__skb_queue_tail ( & tx_buf - > skb_queue , nskb ) ;
TX_STAT_INC ( skb_queued ) ;
}
usb_fill_bulk_urb ( tx_buf - > urb , hif_dev - > udev ,
usb_sndbulkpipe ( hif_dev - > udev , USB_WLAN_TX_PIPE ) ,
tx_buf - > buf , tx_buf - > len ,
hif_usb_tx_cb , tx_buf ) ;
ret = usb_submit_urb ( tx_buf - > urb , GFP_ATOMIC ) ;
if ( ret ) {
tx_buf - > len = tx_buf - > offset = 0 ;
2011-04-13 11:25:59 +05:30
ath9k_skb_queue_complete ( hif_dev , & tx_buf - > skb_queue , false ) ;
2010-03-17 14:25:25 +05:30
__skb_queue_head_init ( & tx_buf - > skb_queue ) ;
list_move_tail ( & tx_buf - > list , & hif_dev - > tx . tx_buf ) ;
hif_dev - > tx . tx_buf_cnt + + ;
}
if ( ! ret )
TX_STAT_INC ( buf_queued ) ;
return ret ;
}
2011-04-13 11:24:31 +05:30
static int hif_usb_send_tx ( struct hif_device_usb * hif_dev , struct sk_buff * skb )
2010-03-17 14:25:25 +05:30
{
2011-04-13 11:24:31 +05:30
struct ath9k_htc_tx_ctl * tx_ctl ;
2010-03-17 14:25:25 +05:30
unsigned long flags ;
2011-04-13 11:26:46 +05:30
int ret = 0 ;
2010-03-17 14:25:25 +05:30
spin_lock_irqsave ( & hif_dev - > tx . tx_lock , flags ) ;
if ( hif_dev - > tx . flags & HIF_USB_TX_STOP ) {
spin_unlock_irqrestore ( & hif_dev - > tx . tx_lock , flags ) ;
return - ENODEV ;
}
/* Check if the max queue count has been reached */
if ( hif_dev - > tx . tx_skb_cnt > MAX_TX_BUF_NUM ) {
spin_unlock_irqrestore ( & hif_dev - > tx . tx_lock , flags ) ;
return - ENOMEM ;
}
2011-04-13 11:26:46 +05:30
spin_unlock_irqrestore ( & hif_dev - > tx . tx_lock , flags ) ;
2010-03-17 14:25:25 +05:30
2011-04-13 11:24:31 +05:30
tx_ctl = HTC_SKB_CB ( skb ) ;
2011-04-13 11:26:46 +05:30
/* Mgmt/Beacon frames don't use the TX buffer pool */
if ( ( tx_ctl - > type = = ATH9K_HTC_MGMT ) | |
( tx_ctl - > type = = ATH9K_HTC_BEACON ) ) {
ret = hif_usb_send_mgmt ( hif_dev , skb ) ;
}
spin_lock_irqsave ( & hif_dev - > tx . tx_lock , flags ) ;
if ( ( tx_ctl - > type = = ATH9K_HTC_NORMAL ) | |
( tx_ctl - > type = = ATH9K_HTC_AMPDU ) ) {
__skb_queue_tail ( & hif_dev - > tx . tx_skb_queue , skb ) ;
hif_dev - > tx . tx_skb_cnt + + ;
}
2010-03-17 14:25:25 +05:30
/* Check if AMPDUs have to be sent immediately */
2011-04-13 11:26:46 +05:30
if ( ( hif_dev - > tx . tx_buf_cnt = = MAX_TX_URB_NUM ) & &
2010-03-17 14:25:25 +05:30
( hif_dev - > tx . tx_skb_cnt < 2 ) ) {
__hif_usb_tx ( hif_dev ) ;
}
spin_unlock_irqrestore ( & hif_dev - > tx . tx_lock , flags ) ;
2011-04-13 11:26:46 +05:30
return ret ;
2010-03-17 14:25:25 +05:30
}
2011-04-13 11:26:06 +05:30
static void hif_usb_start ( void * hif_handle )
2010-03-17 14:25:25 +05:30
{
struct hif_device_usb * hif_dev = ( struct hif_device_usb * ) hif_handle ;
unsigned long flags ;
hif_dev - > flags | = HIF_USB_START ;
spin_lock_irqsave ( & hif_dev - > tx . tx_lock , flags ) ;
hif_dev - > tx . flags & = ~ HIF_USB_TX_STOP ;
spin_unlock_irqrestore ( & hif_dev - > tx . tx_lock , flags ) ;
}
2011-04-13 11:26:06 +05:30
static void hif_usb_stop ( void * hif_handle )
2010-03-17 14:25:25 +05:30
{
struct hif_device_usb * hif_dev = ( struct hif_device_usb * ) hif_handle ;
2010-12-28 14:28:05 +05:30
struct tx_buf * tx_buf = NULL , * tx_buf_tmp = NULL ;
2010-03-17 14:25:25 +05:30
unsigned long flags ;
spin_lock_irqsave ( & hif_dev - > tx . tx_lock , flags ) ;
2011-04-13 11:25:59 +05:30
ath9k_skb_queue_complete ( hif_dev , & hif_dev - > tx . tx_skb_queue , false ) ;
2010-03-17 14:25:25 +05:30
hif_dev - > tx . tx_skb_cnt = 0 ;
hif_dev - > tx . flags | = HIF_USB_TX_STOP ;
spin_unlock_irqrestore ( & hif_dev - > tx . tx_lock , flags ) ;
2010-12-28 14:28:05 +05:30
/* The pending URBs have to be canceled. */
list_for_each_entry_safe ( tx_buf , tx_buf_tmp ,
& hif_dev - > tx . tx_pending , list ) {
usb_kill_urb ( tx_buf - > urb ) ;
}
2011-04-13 11:26:46 +05:30
usb_kill_anchored_urbs ( & hif_dev - > mgmt_submitted ) ;
2010-03-17 14:25:25 +05:30
}
2011-04-13 11:24:31 +05:30
static int hif_usb_send ( void * hif_handle , u8 pipe_id , struct sk_buff * skb )
2010-03-17 14:25:25 +05:30
{
struct hif_device_usb * hif_dev = ( struct hif_device_usb * ) hif_handle ;
int ret = 0 ;
switch ( pipe_id ) {
case USB_WLAN_TX_PIPE :
2011-04-13 11:24:31 +05:30
ret = hif_usb_send_tx ( hif_dev , skb ) ;
2010-03-17 14:25:25 +05:30
break ;
case USB_REG_OUT_PIPE :
ret = hif_usb_send_regout ( hif_dev , skb ) ;
break ;
default :
2010-03-29 16:07:15 +05:30
dev_err ( & hif_dev - > udev - > dev ,
" ath9k_htc: Invalid TX pipe: %d \n " , pipe_id ) ;
2010-03-17 14:25:25 +05:30
ret = - EINVAL ;
break ;
}
return ret ;
}
2011-04-13 11:26:11 +05:30
static inline bool check_index ( struct sk_buff * skb , u8 idx )
{
struct ath9k_htc_tx_ctl * tx_ctl ;
tx_ctl = HTC_SKB_CB ( skb ) ;
if ( ( tx_ctl - > type = = ATH9K_HTC_AMPDU ) & &
( tx_ctl - > sta_idx = = idx ) )
return true ;
return false ;
}
static void hif_usb_sta_drain ( void * hif_handle , u8 idx )
{
struct hif_device_usb * hif_dev = ( struct hif_device_usb * ) hif_handle ;
struct sk_buff * skb , * tmp ;
unsigned long flags ;
spin_lock_irqsave ( & hif_dev - > tx . tx_lock , flags ) ;
skb_queue_walk_safe ( & hif_dev - > tx . tx_skb_queue , skb , tmp ) {
if ( check_index ( skb , idx ) ) {
__skb_unlink ( skb , & hif_dev - > tx . tx_skb_queue ) ;
ath9k_htc_txcompletion_cb ( hif_dev - > htc_handle ,
skb , false ) ;
hif_dev - > tx . tx_skb_cnt - - ;
TX_STAT_INC ( skb_failed ) ;
}
}
spin_unlock_irqrestore ( & hif_dev - > tx . tx_lock , flags ) ;
}
2010-03-17 14:25:25 +05:30
static struct ath9k_htc_hif hif_usb = {
. transport = ATH9K_HIF_USB ,
. name = " ath9k_hif_usb " ,
. control_ul_pipe = USB_REG_OUT_PIPE ,
. control_dl_pipe = USB_REG_IN_PIPE ,
. start = hif_usb_start ,
. stop = hif_usb_stop ,
2011-04-13 11:26:11 +05:30
. sta_drain = hif_usb_sta_drain ,
2010-03-17 14:25:25 +05:30
. send = hif_usb_send ,
} ;
static void ath9k_hif_usb_rx_stream ( struct hif_device_usb * hif_dev ,
struct sk_buff * skb )
{
2010-04-06 15:28:15 +05:30
struct sk_buff * nskb , * skb_pool [ MAX_PKT_NUM_IN_TRANSFER ] ;
2010-11-30 12:19:11 -08:00
int index = 0 , i = 0 , len = skb - > len ;
int rx_remain_len , rx_pkt_len ;
u16 pool_index = 0 ;
2010-03-17 14:25:25 +05:30
u8 * ptr ;
2010-04-06 15:28:11 +05:30
spin_lock ( & hif_dev - > rx_lock ) ;
2010-03-17 14:25:25 +05:30
rx_remain_len = hif_dev - > rx_remain_len ;
rx_pkt_len = hif_dev - > rx_transfer_len ;
if ( rx_remain_len ! = 0 ) {
struct sk_buff * remain_skb = hif_dev - > remain_skb ;
if ( remain_skb ) {
ptr = ( u8 * ) remain_skb - > data ;
index = rx_remain_len ;
rx_remain_len - = hif_dev - > rx_pad_len ;
ptr + = rx_pkt_len ;
memcpy ( ptr , skb - > data , rx_remain_len ) ;
rx_pkt_len + = rx_remain_len ;
hif_dev - > rx_remain_len = 0 ;
skb_put ( remain_skb , rx_pkt_len ) ;
skb_pool [ pool_index + + ] = remain_skb ;
} else {
index = rx_remain_len ;
}
}
2010-04-06 15:28:11 +05:30
spin_unlock ( & hif_dev - > rx_lock ) ;
2010-03-17 14:25:25 +05:30
while ( index < len ) {
2010-11-30 12:19:11 -08:00
u16 pkt_len ;
u16 pkt_tag ;
u16 pad_len ;
int chk_idx ;
2010-03-17 14:25:25 +05:30
ptr = ( u8 * ) skb - > data ;
2011-07-15 19:06:33 -04:00
pkt_len = get_unaligned_le16 ( ptr + index ) ;
pkt_tag = get_unaligned_le16 ( ptr + index + 2 ) ;
2010-03-17 14:25:25 +05:30
2010-11-30 12:19:11 -08:00
if ( pkt_tag ! = ATH_USB_RX_STREAM_MODE_TAG ) {
RX_STAT_INC ( skb_dropped ) ;
return ;
}
pad_len = 4 - ( pkt_len & 0x3 ) ;
if ( pad_len = = 4 )
pad_len = 0 ;
chk_idx = index ;
index = index + 4 + pkt_len + pad_len ;
if ( index > MAX_RX_BUF_SIZE ) {
spin_lock ( & hif_dev - > rx_lock ) ;
hif_dev - > rx_remain_len = index - MAX_RX_BUF_SIZE ;
hif_dev - > rx_transfer_len =
MAX_RX_BUF_SIZE - chk_idx - 4 ;
hif_dev - > rx_pad_len = pad_len ;
nskb = __dev_alloc_skb ( pkt_len + 32 , GFP_ATOMIC ) ;
if ( ! nskb ) {
dev_err ( & hif_dev - > udev - > dev ,
" ath9k_htc: RX memory allocation error \n " ) ;
2010-04-06 15:28:11 +05:30
spin_unlock ( & hif_dev - > rx_lock ) ;
2010-11-30 12:19:11 -08:00
goto err ;
2010-03-17 14:25:25 +05:30
}
2010-11-30 12:19:11 -08:00
skb_reserve ( nskb , 32 ) ;
RX_STAT_INC ( skb_allocated ) ;
memcpy ( nskb - > data , & ( skb - > data [ chk_idx + 4 ] ) ,
hif_dev - > rx_transfer_len ) ;
/* Record the buffer pointer */
hif_dev - > remain_skb = nskb ;
spin_unlock ( & hif_dev - > rx_lock ) ;
2010-03-17 14:25:25 +05:30
} else {
2010-11-30 12:19:11 -08:00
nskb = __dev_alloc_skb ( pkt_len + 32 , GFP_ATOMIC ) ;
if ( ! nskb ) {
dev_err ( & hif_dev - > udev - > dev ,
" ath9k_htc: RX memory allocation error \n " ) ;
goto err ;
}
skb_reserve ( nskb , 32 ) ;
RX_STAT_INC ( skb_allocated ) ;
memcpy ( nskb - > data , & ( skb - > data [ chk_idx + 4 ] ) , pkt_len ) ;
skb_put ( nskb , pkt_len ) ;
skb_pool [ pool_index + + ] = nskb ;
2010-03-17 14:25:25 +05:30
}
}
err :
for ( i = 0 ; i < pool_index ; i + + ) {
ath9k_htc_rx_msg ( hif_dev - > htc_handle , skb_pool [ i ] ,
skb_pool [ i ] - > len , USB_WLAN_RX_PIPE ) ;
RX_STAT_INC ( skb_completed ) ;
}
}
static void ath9k_hif_usb_rx_cb ( struct urb * urb )
{
struct sk_buff * skb = ( struct sk_buff * ) urb - > context ;
2010-11-30 13:42:08 -08:00
struct hif_device_usb * hif_dev =
2010-03-17 14:25:25 +05:30
usb_get_intfdata ( usb_ifnum_to_if ( urb - > dev , 0 ) ) ;
int ret ;
2010-03-29 16:07:15 +05:30
if ( ! skb )
return ;
2010-03-17 14:25:25 +05:30
if ( ! hif_dev )
goto free ;
switch ( urb - > status ) {
case 0 :
break ;
case - ENOENT :
case - ECONNRESET :
case - ENODEV :
case - ESHUTDOWN :
goto free ;
default :
goto resubmit ;
}
if ( likely ( urb - > actual_length ! = 0 ) ) {
skb_put ( skb , urb - > actual_length ) ;
ath9k_hif_usb_rx_stream ( hif_dev , skb ) ;
}
resubmit :
skb_reset_tail_pointer ( skb ) ;
skb_trim ( skb , 0 ) ;
2010-03-29 16:07:15 +05:30
usb_anchor_urb ( urb , & hif_dev - > rx_submitted ) ;
2010-03-17 14:25:25 +05:30
ret = usb_submit_urb ( urb , GFP_ATOMIC ) ;
2010-03-29 16:07:15 +05:30
if ( ret ) {
usb_unanchor_urb ( urb ) ;
2010-03-17 14:25:25 +05:30
goto free ;
2010-03-29 16:07:15 +05:30
}
2010-03-17 14:25:25 +05:30
return ;
free :
2010-04-13 00:28:53 +08:00
kfree_skb ( skb ) ;
2010-03-17 14:25:25 +05:30
}
static void ath9k_hif_usb_reg_in_cb ( struct urb * urb )
{
struct sk_buff * skb = ( struct sk_buff * ) urb - > context ;
struct sk_buff * nskb ;
2010-11-30 13:42:08 -08:00
struct hif_device_usb * hif_dev =
2010-03-17 14:25:25 +05:30
usb_get_intfdata ( usb_ifnum_to_if ( urb - > dev , 0 ) ) ;
int ret ;
2010-03-29 16:07:15 +05:30
if ( ! skb )
return ;
2010-03-17 14:25:25 +05:30
if ( ! hif_dev )
goto free ;
switch ( urb - > status ) {
case 0 :
break ;
case - ENOENT :
case - ECONNRESET :
case - ENODEV :
case - ESHUTDOWN :
goto free ;
default :
2011-04-13 11:25:23 +05:30
skb_reset_tail_pointer ( skb ) ;
skb_trim ( skb , 0 ) ;
2010-03-17 14:25:25 +05:30
goto resubmit ;
}
if ( likely ( urb - > actual_length ! = 0 ) ) {
skb_put ( skb , urb - > actual_length ) ;
2010-04-23 10:28:17 +05:30
/* Process the command first */
ath9k_htc_rx_msg ( hif_dev - > htc_handle , skb ,
skb - > len , USB_REG_IN_PIPE ) ;
2010-04-13 00:29:05 +08:00
nskb = alloc_skb ( MAX_REG_IN_BUF_SIZE , GFP_ATOMIC ) ;
2010-04-23 10:28:17 +05:30
if ( ! nskb ) {
dev_err ( & hif_dev - > udev - > dev ,
" ath9k_htc: REG_IN memory allocation failure \n " ) ;
urb - > context = NULL ;
return ;
}
2010-03-17 14:25:25 +05:30
2010-11-08 12:49:12 +05:30
usb_fill_bulk_urb ( urb , hif_dev - > udev ,
2010-09-16 19:56:55 +05:30
usb_rcvbulkpipe ( hif_dev - > udev ,
USB_REG_IN_PIPE ) ,
2010-03-17 14:25:25 +05:30
nskb - > data , MAX_REG_IN_BUF_SIZE ,
2010-11-08 12:49:12 +05:30
ath9k_hif_usb_reg_in_cb , nskb ) ;
2010-03-17 14:25:25 +05:30
}
resubmit :
2011-04-13 11:25:23 +05:30
usb_anchor_urb ( urb , & hif_dev - > reg_in_submitted ) ;
2010-03-17 14:25:25 +05:30
ret = usb_submit_urb ( urb , GFP_ATOMIC ) ;
2011-04-13 11:25:23 +05:30
if ( ret ) {
usb_unanchor_urb ( urb ) ;
2010-03-17 14:25:25 +05:30
goto free ;
2011-04-13 11:25:23 +05:30
}
2010-03-17 14:25:25 +05:30
return ;
free :
2010-04-13 00:29:05 +08:00
kfree_skb ( skb ) ;
2010-03-29 16:07:15 +05:30
urb - > context = NULL ;
2010-03-17 14:25:25 +05:30
}
static void ath9k_hif_usb_dealloc_tx_urbs ( struct hif_device_usb * hif_dev )
{
struct tx_buf * tx_buf = NULL , * tx_buf_tmp = NULL ;
2010-12-28 14:28:05 +05:30
unsigned long flags ;
2010-03-17 14:25:25 +05:30
2010-04-23 10:28:09 +05:30
list_for_each_entry_safe ( tx_buf , tx_buf_tmp ,
& hif_dev - > tx . tx_buf , list ) {
usb_kill_urb ( tx_buf - > urb ) ;
2010-03-17 14:25:25 +05:30
list_del ( & tx_buf - > list ) ;
usb_free_urb ( tx_buf - > urb ) ;
kfree ( tx_buf - > buf ) ;
kfree ( tx_buf ) ;
}
2010-12-28 14:28:05 +05:30
spin_lock_irqsave ( & hif_dev - > tx . tx_lock , flags ) ;
hif_dev - > tx . flags | = HIF_USB_TX_FLUSH ;
spin_unlock_irqrestore ( & hif_dev - > tx . tx_lock , flags ) ;
2010-03-17 14:25:25 +05:30
list_for_each_entry_safe ( tx_buf , tx_buf_tmp ,
& hif_dev - > tx . tx_pending , list ) {
usb_kill_urb ( tx_buf - > urb ) ;
list_del ( & tx_buf - > list ) ;
usb_free_urb ( tx_buf - > urb ) ;
kfree ( tx_buf - > buf ) ;
kfree ( tx_buf ) ;
}
2011-04-13 11:26:46 +05:30
usb_kill_anchored_urbs ( & hif_dev - > mgmt_submitted ) ;
2010-03-17 14:25:25 +05:30
}
static int ath9k_hif_usb_alloc_tx_urbs ( struct hif_device_usb * hif_dev )
{
struct tx_buf * tx_buf ;
int i ;
INIT_LIST_HEAD ( & hif_dev - > tx . tx_buf ) ;
INIT_LIST_HEAD ( & hif_dev - > tx . tx_pending ) ;
spin_lock_init ( & hif_dev - > tx . tx_lock ) ;
__skb_queue_head_init ( & hif_dev - > tx . tx_skb_queue ) ;
2011-04-13 11:26:46 +05:30
init_usb_anchor ( & hif_dev - > mgmt_submitted ) ;
2010-03-17 14:25:25 +05:30
for ( i = 0 ; i < MAX_TX_URB_NUM ; i + + ) {
tx_buf = kzalloc ( sizeof ( struct tx_buf ) , GFP_KERNEL ) ;
if ( ! tx_buf )
goto err ;
tx_buf - > buf = kzalloc ( MAX_TX_BUF_SIZE , GFP_KERNEL ) ;
if ( ! tx_buf - > buf )
goto err ;
tx_buf - > urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! tx_buf - > urb )
goto err ;
tx_buf - > hif_dev = hif_dev ;
__skb_queue_head_init ( & tx_buf - > skb_queue ) ;
list_add_tail ( & tx_buf - > list , & hif_dev - > tx . tx_buf ) ;
}
hif_dev - > tx . tx_buf_cnt = MAX_TX_URB_NUM ;
return 0 ;
err :
2010-05-14 16:52:37 +02:00
if ( tx_buf ) {
kfree ( tx_buf - > buf ) ;
kfree ( tx_buf ) ;
}
2010-03-17 14:25:25 +05:30
ath9k_hif_usb_dealloc_tx_urbs ( hif_dev ) ;
return - ENOMEM ;
}
static void ath9k_hif_usb_dealloc_rx_urbs ( struct hif_device_usb * hif_dev )
{
2010-03-29 16:07:15 +05:30
usb_kill_anchored_urbs ( & hif_dev - > rx_submitted ) ;
2010-03-17 14:25:25 +05:30
}
static int ath9k_hif_usb_alloc_rx_urbs ( struct hif_device_usb * hif_dev )
{
2010-03-29 16:07:15 +05:30
struct urb * urb = NULL ;
struct sk_buff * skb = NULL ;
2010-03-17 14:25:25 +05:30
int i , ret ;
2010-03-29 16:07:15 +05:30
init_usb_anchor ( & hif_dev - > rx_submitted ) ;
2010-04-06 15:28:11 +05:30
spin_lock_init ( & hif_dev - > rx_lock ) ;
2010-03-29 16:07:15 +05:30
2010-03-17 14:25:25 +05:30
for ( i = 0 ; i < MAX_RX_URB_NUM ; i + + ) {
/* Allocate URB */
2010-03-29 16:07:15 +05:30
urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( urb = = NULL ) {
2010-03-17 14:25:25 +05:30
ret = - ENOMEM ;
2010-03-29 16:07:15 +05:30
goto err_urb ;
2010-03-17 14:25:25 +05:30
}
/* Allocate buffer */
2010-04-13 00:28:53 +08:00
skb = alloc_skb ( MAX_RX_BUF_SIZE , GFP_KERNEL ) ;
2010-03-29 16:07:15 +05:30
if ( ! skb ) {
ret = - ENOMEM ;
goto err_skb ;
}
2010-03-17 14:25:25 +05:30
2010-03-29 16:07:15 +05:30
usb_fill_bulk_urb ( urb , hif_dev - > udev ,
usb_rcvbulkpipe ( hif_dev - > udev ,
USB_WLAN_RX_PIPE ) ,
skb - > data , MAX_RX_BUF_SIZE ,
ath9k_hif_usb_rx_cb , skb ) ;
/* Anchor URB */
usb_anchor_urb ( urb , & hif_dev - > rx_submitted ) ;
2010-03-17 14:25:25 +05:30
2010-03-29 16:07:15 +05:30
/* Submit URB */
ret = usb_submit_urb ( urb , GFP_KERNEL ) ;
if ( ret ) {
usb_unanchor_urb ( urb ) ;
goto err_submit ;
}
2010-04-06 15:28:13 +05:30
/*
* Drop reference count .
* This ensures that the URB is freed when killing them .
*/
usb_free_urb ( urb ) ;
2010-03-17 14:25:25 +05:30
}
return 0 ;
2010-03-29 16:07:15 +05:30
err_submit :
2010-04-13 00:28:53 +08:00
kfree_skb ( skb ) ;
2010-03-29 16:07:15 +05:30
err_skb :
usb_free_urb ( urb ) ;
err_urb :
2010-03-17 14:25:25 +05:30
ath9k_hif_usb_dealloc_rx_urbs ( hif_dev ) ;
return ret ;
}
2011-04-13 11:25:23 +05:30
static void ath9k_hif_usb_dealloc_reg_in_urbs ( struct hif_device_usb * hif_dev )
2010-03-17 14:25:25 +05:30
{
2011-04-13 11:25:23 +05:30
usb_kill_anchored_urbs ( & hif_dev - > reg_in_submitted ) ;
2010-03-17 14:25:25 +05:30
}
2011-04-13 11:25:23 +05:30
static int ath9k_hif_usb_alloc_reg_in_urbs ( struct hif_device_usb * hif_dev )
2010-03-17 14:25:25 +05:30
{
2011-04-13 11:25:23 +05:30
struct urb * urb = NULL ;
struct sk_buff * skb = NULL ;
int i , ret ;
2010-03-17 14:25:25 +05:30
2011-04-13 11:25:23 +05:30
init_usb_anchor ( & hif_dev - > reg_in_submitted ) ;
2010-03-17 14:25:25 +05:30
2011-04-13 11:25:23 +05:30
for ( i = 0 ; i < MAX_REG_IN_URB_NUM ; i + + ) {
2010-03-17 14:25:25 +05:30
2011-04-13 11:25:23 +05:30
/* Allocate URB */
urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( urb = = NULL ) {
ret = - ENOMEM ;
goto err_urb ;
}
2010-03-17 14:25:25 +05:30
2011-04-13 11:25:23 +05:30
/* Allocate buffer */
skb = alloc_skb ( MAX_REG_IN_BUF_SIZE , GFP_KERNEL ) ;
if ( ! skb ) {
ret = - ENOMEM ;
goto err_skb ;
}
usb_fill_bulk_urb ( urb , hif_dev - > udev ,
usb_rcvbulkpipe ( hif_dev - > udev ,
USB_REG_IN_PIPE ) ,
skb - > data , MAX_REG_IN_BUF_SIZE ,
ath9k_hif_usb_reg_in_cb , skb ) ;
/* Anchor URB */
usb_anchor_urb ( urb , & hif_dev - > reg_in_submitted ) ;
/* Submit URB */
ret = usb_submit_urb ( urb , GFP_KERNEL ) ;
if ( ret ) {
usb_unanchor_urb ( urb ) ;
goto err_submit ;
}
/*
* Drop reference count .
* This ensures that the URB is freed when killing them .
*/
usb_free_urb ( urb ) ;
}
2010-03-17 14:25:25 +05:30
return 0 ;
2011-04-13 11:25:23 +05:30
err_submit :
kfree_skb ( skb ) ;
err_skb :
usb_free_urb ( urb ) ;
err_urb :
ath9k_hif_usb_dealloc_reg_in_urbs ( hif_dev ) ;
return ret ;
2010-03-17 14:25:25 +05:30
}
static int ath9k_hif_usb_alloc_urbs ( struct hif_device_usb * hif_dev )
{
2010-04-06 15:28:17 +05:30
/* Register Write */
init_usb_anchor ( & hif_dev - > regout_submitted ) ;
2010-03-17 14:25:25 +05:30
/* TX */
if ( ath9k_hif_usb_alloc_tx_urbs ( hif_dev ) < 0 )
goto err ;
/* RX */
if ( ath9k_hif_usb_alloc_rx_urbs ( hif_dev ) < 0 )
2010-07-07 15:19:18 +05:30
goto err_rx ;
2010-03-17 14:25:25 +05:30
2010-04-06 15:28:17 +05:30
/* Register Read */
2011-04-13 11:25:23 +05:30
if ( ath9k_hif_usb_alloc_reg_in_urbs ( hif_dev ) < 0 )
2010-07-07 15:19:18 +05:30
goto err_reg ;
2010-03-17 14:25:25 +05:30
return 0 ;
2010-07-07 15:19:18 +05:30
err_reg :
ath9k_hif_usb_dealloc_rx_urbs ( hif_dev ) ;
err_rx :
ath9k_hif_usb_dealloc_tx_urbs ( hif_dev ) ;
2010-03-17 14:25:25 +05:30
err :
return - ENOMEM ;
}
2010-05-11 16:24:40 +05:30
static void ath9k_hif_usb_dealloc_urbs ( struct hif_device_usb * hif_dev )
{
usb_kill_anchored_urbs ( & hif_dev - > regout_submitted ) ;
2011-04-13 11:25:23 +05:30
ath9k_hif_usb_dealloc_reg_in_urbs ( hif_dev ) ;
2010-05-11 16:24:40 +05:30
ath9k_hif_usb_dealloc_tx_urbs ( hif_dev ) ;
ath9k_hif_usb_dealloc_rx_urbs ( hif_dev ) ;
}
2010-11-19 16:53:22 +05:30
static int ath9k_hif_usb_download_fw ( struct hif_device_usb * hif_dev ,
u32 drv_info )
2010-03-17 14:25:25 +05:30
{
int transfer , err ;
const void * data = hif_dev - > firmware - > data ;
size_t len = hif_dev - > firmware - > size ;
u32 addr = AR9271_FIRMWARE ;
u8 * buf = kzalloc ( 4096 , GFP_KERNEL ) ;
2010-06-02 15:53:34 +05:30
u32 firm_offset ;
2010-03-17 14:25:25 +05:30
if ( ! buf )
return - ENOMEM ;
while ( len ) {
transfer = min_t ( int , len , 4096 ) ;
memcpy ( buf , data , transfer ) ;
err = usb_control_msg ( hif_dev - > udev ,
usb_sndctrlpipe ( hif_dev - > udev , 0 ) ,
FIRMWARE_DOWNLOAD , 0x40 | USB_DIR_OUT ,
addr > > 8 , 0 , buf , transfer , HZ ) ;
if ( err < 0 ) {
kfree ( buf ) ;
return err ;
}
len - = transfer ;
data + = transfer ;
addr + = transfer ;
}
kfree ( buf ) ;
2010-12-07 16:31:38 +05:30
if ( IS_AR7010_DEVICE ( drv_info ) )
2010-06-02 15:53:34 +05:30
firm_offset = AR7010_FIRMWARE_TEXT ;
2010-11-19 16:53:22 +05:30
else
2010-06-02 15:53:34 +05:30
firm_offset = AR9271_FIRMWARE_TEXT ;
2010-03-17 14:25:25 +05:30
/*
* Issue FW download complete command to firmware .
*/
err = usb_control_msg ( hif_dev - > udev , usb_sndctrlpipe ( hif_dev - > udev , 0 ) ,
FIRMWARE_DOWNLOAD_COMP ,
0x40 | USB_DIR_OUT ,
2010-06-02 15:53:34 +05:30
firm_offset > > 8 , 0 , NULL , 0 , HZ ) ;
2010-03-17 14:25:25 +05:30
if ( err )
return - EIO ;
dev_info ( & hif_dev - > udev - > dev , " ath9k_htc: Transferred FW: %s, size: %ld \n " ,
2010-06-02 15:53:30 +05:30
hif_dev - > fw_name , ( unsigned long ) hif_dev - > firmware - > size ) ;
2010-03-17 14:25:25 +05:30
return 0 ;
}
2010-11-19 16:53:22 +05:30
static int ath9k_hif_usb_dev_init ( struct hif_device_usb * hif_dev , u32 drv_info )
2010-03-17 14:25:25 +05:30
{
2010-09-14 14:35:55 +05:30
int ret , idx ;
struct usb_host_interface * alt = & hif_dev - > interface - > altsetting [ 0 ] ;
struct usb_endpoint_descriptor * endp ;
2010-03-17 14:25:25 +05:30
/* Request firmware */
2010-06-02 15:53:30 +05:30
ret = request_firmware ( & hif_dev - > firmware , hif_dev - > fw_name ,
& hif_dev - > udev - > dev ) ;
2010-03-17 14:25:25 +05:30
if ( ret ) {
dev_err ( & hif_dev - > udev - > dev ,
2010-06-02 15:53:30 +05:30
" ath9k_htc: Firmware - %s not found \n " , hif_dev - > fw_name ) ;
2010-03-17 14:25:25 +05:30
goto err_fw_req ;
}
2010-05-11 16:24:40 +05:30
/* Download firmware */
2010-11-19 16:53:22 +05:30
ret = ath9k_hif_usb_download_fw ( hif_dev , drv_info ) ;
2010-05-11 16:24:40 +05:30
if ( ret ) {
dev_err ( & hif_dev - > udev - > dev ,
2010-06-02 15:53:30 +05:30
" ath9k_htc: Firmware - %s download failed \n " ,
hif_dev - > fw_name ) ;
2010-05-11 16:24:40 +05:30
goto err_fw_download ;
}
2010-09-14 14:35:55 +05:30
/* On downloading the firmware to the target, the USB descriptor of EP4
* is ' patched ' to change the type of the endpoint to Bulk . This will
* bring down CPU usage during the scan period .
*/
for ( idx = 0 ; idx < alt - > desc . bNumEndpoints ; idx + + ) {
endp = & alt - > endpoint [ idx ] . desc ;
2010-11-08 12:49:12 +05:30
if ( ( endp - > bmAttributes & USB_ENDPOINT_XFERTYPE_MASK )
= = USB_ENDPOINT_XFER_INT ) {
2010-09-14 14:35:55 +05:30
endp - > bmAttributes & = ~ USB_ENDPOINT_XFERTYPE_MASK ;
endp - > bmAttributes | = USB_ENDPOINT_XFER_BULK ;
endp - > bInterval = 0 ;
}
}
2010-11-08 12:49:12 +05:30
/* Alloc URBs */
ret = ath9k_hif_usb_alloc_urbs ( hif_dev ) ;
if ( ret ) {
dev_err ( & hif_dev - > udev - > dev ,
" ath9k_htc: Unable to allocate URBs \n " ) ;
2011-02-21 07:50:38 +05:30
goto err_fw_download ;
2010-11-08 12:49:12 +05:30
}
2010-03-17 14:25:25 +05:30
return 0 ;
2010-12-07 16:32:02 +05:30
err_fw_download :
2010-03-17 14:25:25 +05:30
release_firmware ( hif_dev - > firmware ) ;
err_fw_req :
hif_dev - > firmware = NULL ;
return ret ;
}
static void ath9k_hif_usb_dev_deinit ( struct hif_device_usb * hif_dev )
{
ath9k_hif_usb_dealloc_urbs ( hif_dev ) ;
if ( hif_dev - > firmware )
release_firmware ( hif_dev - > firmware ) ;
}
2011-02-21 07:47:52 +05:30
/*
* An exact copy of the function from zd1211rw .
*/
static int send_eject_command ( struct usb_interface * interface )
{
struct usb_device * udev = interface_to_usbdev ( interface ) ;
struct usb_host_interface * iface_desc = & interface - > altsetting [ 0 ] ;
struct usb_endpoint_descriptor * endpoint ;
unsigned char * cmd ;
u8 bulk_out_ep ;
int r ;
/* Find bulk out endpoint */
for ( r = 1 ; r > = 0 ; r - - ) {
endpoint = & iface_desc - > endpoint [ r ] . desc ;
if ( usb_endpoint_dir_out ( endpoint ) & &
usb_endpoint_xfer_bulk ( endpoint ) ) {
bulk_out_ep = endpoint - > bEndpointAddress ;
break ;
}
}
if ( r = = - 1 ) {
dev_err ( & udev - > dev ,
" ath9k_htc: Could not find bulk out endpoint \n " ) ;
return - ENODEV ;
}
cmd = kzalloc ( 31 , GFP_KERNEL ) ;
if ( cmd = = NULL )
return - ENODEV ;
/* USB bulk command block */
cmd [ 0 ] = 0x55 ; /* bulk command signature */
cmd [ 1 ] = 0x53 ; /* bulk command signature */
cmd [ 2 ] = 0x42 ; /* bulk command signature */
cmd [ 3 ] = 0x43 ; /* bulk command signature */
cmd [ 14 ] = 6 ; /* command length */
cmd [ 15 ] = 0x1b ; /* SCSI command: START STOP UNIT */
cmd [ 19 ] = 0x2 ; /* eject disc */
dev_info ( & udev - > dev , " Ejecting storage device... \n " ) ;
r = usb_bulk_msg ( udev , usb_sndbulkpipe ( udev , bulk_out_ep ) ,
cmd , 31 , NULL , 2000 ) ;
kfree ( cmd ) ;
if ( r )
return r ;
/* At this point, the device disconnects and reconnects with the real
* ID numbers . */
usb_set_intfdata ( interface , NULL ) ;
return 0 ;
}
2010-03-17 14:25:25 +05:30
static int ath9k_hif_usb_probe ( struct usb_interface * interface ,
const struct usb_device_id * id )
{
struct usb_device * udev = interface_to_usbdev ( interface ) ;
struct hif_device_usb * hif_dev ;
int ret = 0 ;
2011-02-21 07:47:52 +05:30
if ( id - > driver_info = = STORAGE_DEVICE )
return send_eject_command ( interface ) ;
2010-03-17 14:25:25 +05:30
hif_dev = kzalloc ( sizeof ( struct hif_device_usb ) , GFP_KERNEL ) ;
if ( ! hif_dev ) {
ret = - ENOMEM ;
goto err_alloc ;
}
usb_get_dev ( udev ) ;
hif_dev - > udev = udev ;
hif_dev - > interface = interface ;
hif_dev - > device_id = id - > idProduct ;
# ifdef CONFIG_PM
udev - > reset_resume = 1 ;
# endif
usb_set_intfdata ( interface , hif_dev ) ;
2010-05-11 16:24:41 +05:30
hif_dev - > htc_handle = ath9k_htc_hw_alloc ( hif_dev , & hif_usb ,
& hif_dev - > udev - > dev ) ;
if ( hif_dev - > htc_handle = = NULL ) {
ret = - ENOMEM ;
goto err_htc_hw_alloc ;
}
2010-06-02 15:53:30 +05:30
/* Find out which firmware to load */
2010-12-07 16:31:38 +05:30
if ( IS_AR7010_DEVICE ( id - > driver_info ) )
2011-04-13 11:22:33 +05:30
hif_dev - > fw_name = FIRMWARE_AR7010_1_1 ;
2010-11-19 16:53:22 +05:30
else
2010-06-23 14:20:45 -04:00
hif_dev - > fw_name = FIRMWARE_AR9271 ;
2010-06-02 15:53:30 +05:30
2010-11-19 16:53:22 +05:30
ret = ath9k_hif_usb_dev_init ( hif_dev , id - > driver_info ) ;
2010-03-17 14:25:25 +05:30
if ( ret ) {
ret = - EINVAL ;
goto err_hif_init_usb ;
}
2010-05-11 16:24:41 +05:30
ret = ath9k_htc_hw_init ( hif_dev - > htc_handle ,
2011-04-11 22:56:55 +05:30
& interface - > dev , hif_dev - > device_id ,
2010-11-19 16:53:22 +05:30
hif_dev - > udev - > product , id - > driver_info ) ;
2010-03-17 14:25:25 +05:30
if ( ret ) {
ret = - EINVAL ;
goto err_htc_hw_init ;
}
dev_info ( & hif_dev - > udev - > dev , " ath9k_htc: USB layer initialized \n " ) ;
return 0 ;
err_htc_hw_init :
ath9k_hif_usb_dev_deinit ( hif_dev ) ;
err_hif_init_usb :
2010-05-11 16:24:41 +05:30
ath9k_htc_hw_free ( hif_dev - > htc_handle ) ;
err_htc_hw_alloc :
2010-03-17 14:25:25 +05:30
usb_set_intfdata ( interface , NULL ) ;
kfree ( hif_dev ) ;
usb_put_dev ( udev ) ;
err_alloc :
return ret ;
}
2010-04-23 10:28:16 +05:30
static void ath9k_hif_usb_reboot ( struct usb_device * udev )
{
u32 reboot_cmd = 0xffffffff ;
void * buf ;
int ret ;
2010-05-15 23:17:19 +02:00
buf = kmemdup ( & reboot_cmd , 4 , GFP_KERNEL ) ;
2010-04-23 10:28:16 +05:30
if ( ! buf )
return ;
ret = usb_bulk_msg ( udev , usb_sndbulkpipe ( udev , USB_REG_OUT_PIPE ) ,
buf , 4 , NULL , HZ ) ;
if ( ret )
dev_err ( & udev - > dev , " ath9k_htc: USB reboot failed \n " ) ;
kfree ( buf ) ;
}
2010-03-17 14:25:25 +05:30
static void ath9k_hif_usb_disconnect ( struct usb_interface * interface )
{
struct usb_device * udev = interface_to_usbdev ( interface ) ;
2010-11-30 13:42:08 -08:00
struct hif_device_usb * hif_dev = usb_get_intfdata ( interface ) ;
2010-12-20 08:02:42 +05:30
bool unplugged = ( udev - > state = = USB_STATE_NOTATTACHED ) ? true : false ;
2010-03-17 14:25:25 +05:30
2011-02-21 07:47:52 +05:30
if ( ! hif_dev )
return ;
ath9k_htc_hw_deinit ( hif_dev - > htc_handle , unplugged ) ;
ath9k_htc_hw_free ( hif_dev - > htc_handle ) ;
ath9k_hif_usb_dev_deinit ( hif_dev ) ;
usb_set_intfdata ( interface , NULL ) ;
2010-03-17 14:25:25 +05:30
2010-12-20 08:02:42 +05:30
if ( ! unplugged & & ( hif_dev - > flags & HIF_USB_START ) )
2010-04-23 10:28:16 +05:30
ath9k_hif_usb_reboot ( udev ) ;
2010-03-17 14:25:25 +05:30
kfree ( hif_dev ) ;
dev_info ( & udev - > dev , " ath9k_htc: USB layer deinitialized \n " ) ;
usb_put_dev ( udev ) ;
}
# ifdef CONFIG_PM
static int ath9k_hif_usb_suspend ( struct usb_interface * interface ,
pm_message_t message )
{
2010-11-30 13:42:08 -08:00
struct hif_device_usb * hif_dev = usb_get_intfdata ( interface ) ;
2010-03-17 14:25:25 +05:30
2010-12-01 12:30:27 +05:30
/*
* The device has to be set to FULLSLEEP mode in case no
* interface is up .
*/
if ( ! ( hif_dev - > flags & HIF_USB_START ) )
ath9k_htc_suspend ( hif_dev - > htc_handle ) ;
2010-03-17 14:25:25 +05:30
ath9k_hif_usb_dealloc_urbs ( hif_dev ) ;
return 0 ;
}
static int ath9k_hif_usb_resume ( struct usb_interface * interface )
{
2010-11-30 13:42:08 -08:00
struct hif_device_usb * hif_dev = usb_get_intfdata ( interface ) ;
2010-11-19 16:53:22 +05:30
struct htc_target * htc_handle = hif_dev - > htc_handle ;
2010-03-17 14:25:25 +05:30
int ret ;
ret = ath9k_hif_usb_alloc_urbs ( hif_dev ) ;
if ( ret )
return ret ;
if ( hif_dev - > firmware ) {
2010-11-19 16:53:22 +05:30
ret = ath9k_hif_usb_download_fw ( hif_dev ,
2010-12-07 16:31:38 +05:30
htc_handle - > drv_priv - > ah - > hw_version . usbdev ) ;
2010-03-17 14:25:25 +05:30
if ( ret )
goto fail_resume ;
} else {
ath9k_hif_usb_dealloc_urbs ( hif_dev ) ;
return - EIO ;
}
mdelay ( 100 ) ;
2010-11-19 16:53:22 +05:30
ret = ath9k_htc_resume ( htc_handle ) ;
2010-03-17 14:25:25 +05:30
if ( ret )
goto fail_resume ;
return 0 ;
fail_resume :
ath9k_hif_usb_dealloc_urbs ( hif_dev ) ;
return ret ;
}
# endif
static struct usb_driver ath9k_hif_usb_driver = {
2011-04-11 22:56:55 +05:30
. name = KBUILD_MODNAME ,
2010-03-17 14:25:25 +05:30
. probe = ath9k_hif_usb_probe ,
. disconnect = ath9k_hif_usb_disconnect ,
# ifdef CONFIG_PM
. suspend = ath9k_hif_usb_suspend ,
. resume = ath9k_hif_usb_resume ,
. reset_resume = ath9k_hif_usb_resume ,
# endif
. id_table = ath9k_hif_usb_ids ,
. soft_unbind = 1 ,
} ;
int ath9k_hif_usb_init ( void )
{
return usb_register ( & ath9k_hif_usb_driver ) ;
}
void ath9k_hif_usb_exit ( void )
{
usb_deregister ( & ath9k_hif_usb_driver ) ;
}