2010-09-06 01:09:20 +02:00
/*
* Atheros CARL9170 driver
*
* USB - frontend
*
* Copyright 2008 , Johannes Berg < johannes @ sipsolutions . net >
* Copyright 2009 , 2010 , Christian Lamparter < chunkeey @ googlemail . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; see the file COPYING . If not , see
* http : //www.gnu.org/licenses/.
*
* This file incorporates work covered by the following copyright and
* permission notice :
* Copyright ( c ) 2007 - 2008 Atheros Communications , Inc .
*
* 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 .
*/
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/usb.h>
# include <linux/firmware.h>
# include <linux/etherdevice.h>
# include <linux/device.h>
# include <net/mac80211.h>
# include "carl9170.h"
# include "cmd.h"
# include "hw.h"
# include "fwcmd.h"
MODULE_AUTHOR ( " Johannes Berg <johannes@sipsolutions.net> " ) ;
MODULE_AUTHOR ( " Christian Lamparter <chunkeey@googlemail.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Atheros AR9170 802.11n USB wireless " ) ;
MODULE_FIRMWARE ( CARL9170FW_NAME ) ;
MODULE_ALIAS ( " ar9170usb " ) ;
MODULE_ALIAS ( " arusb_lnx " ) ;
/*
* Note :
*
* Always update our wiki ' s device list ( located at :
* http : //wireless.kernel.org/en/users/Drivers/ar9170/devices ),
* whenever you add a new device .
*/
static struct usb_device_id carl9170_usb_ids [ ] = {
/* Atheros 9170 */
{ USB_DEVICE ( 0x0cf3 , 0x9170 ) } ,
/* Atheros TG121N */
{ USB_DEVICE ( 0x0cf3 , 0x1001 ) } ,
/* TP-Link TL-WN821N v2 */
{ USB_DEVICE ( 0x0cf3 , 0x1002 ) , . driver_info = CARL9170_WPS_BUTTON |
CARL9170_ONE_LED } ,
/* 3Com Dual Band 802.11n USB Adapter */
{ USB_DEVICE ( 0x0cf3 , 0x1010 ) } ,
/* H3C Dual Band 802.11n USB Adapter */
{ USB_DEVICE ( 0x0cf3 , 0x1011 ) } ,
/* Cace Airpcap NX */
{ USB_DEVICE ( 0xcace , 0x0300 ) } ,
/* D-Link DWA 160 A1 */
{ USB_DEVICE ( 0x07d1 , 0x3c10 ) } ,
/* D-Link DWA 160 A2 */
{ USB_DEVICE ( 0x07d1 , 0x3a09 ) } ,
2010-10-30 19:46:37 +02:00
/* D-Link DWA 130 D */
{ USB_DEVICE ( 0x07d1 , 0x3a0f ) } ,
2010-09-06 01:09:20 +02:00
/* Netgear WNA1000 */
{ USB_DEVICE ( 0x0846 , 0x9040 ) } ,
2010-10-30 19:46:37 +02:00
/* Netgear WNDA3100 (v1) */
2010-09-06 01:09:20 +02:00
{ USB_DEVICE ( 0x0846 , 0x9010 ) } ,
/* Netgear WN111 v2 */
{ USB_DEVICE ( 0x0846 , 0x9001 ) , . driver_info = CARL9170_ONE_LED } ,
/* Zydas ZD1221 */
{ USB_DEVICE ( 0x0ace , 0x1221 ) } ,
/* Proxim ORiNOCO 802.11n USB */
{ USB_DEVICE ( 0x1435 , 0x0804 ) } ,
/* WNC Generic 11n USB Dongle */
{ USB_DEVICE ( 0x1435 , 0x0326 ) } ,
/* ZyXEL NWD271N */
{ USB_DEVICE ( 0x0586 , 0x3417 ) } ,
/* Z-Com UB81 BG */
{ USB_DEVICE ( 0x0cde , 0x0023 ) } ,
/* Z-Com UB82 ABG */
{ USB_DEVICE ( 0x0cde , 0x0026 ) } ,
/* Sphairon Homelink 1202 */
{ USB_DEVICE ( 0x0cde , 0x0027 ) } ,
/* Arcadyan WN7512 */
{ USB_DEVICE ( 0x083a , 0xf522 ) } ,
/* Planex GWUS300 */
{ USB_DEVICE ( 0x2019 , 0x5304 ) } ,
/* IO-Data WNGDNUS2 */
{ USB_DEVICE ( 0x04bb , 0x093f ) } ,
/* NEC WL300NU-G */
{ USB_DEVICE ( 0x0409 , 0x0249 ) } ,
2011-06-30 21:06:17 +02:00
/* NEC WL300NU-AG */
{ USB_DEVICE ( 0x0409 , 0x02b4 ) } ,
2010-09-06 01:09:20 +02:00
/* AVM FRITZ!WLAN USB Stick N */
{ USB_DEVICE ( 0x057c , 0x8401 ) } ,
/* AVM FRITZ!WLAN USB Stick N 2.4 */
{ USB_DEVICE ( 0x057c , 0x8402 ) } ,
/* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */
{ USB_DEVICE ( 0x1668 , 0x1200 ) } ,
2011-02-22 14:49:43 +01:00
/* Airlive X.USB a/b/g/n */
{ USB_DEVICE ( 0x1b75 , 0x9170 ) } ,
2010-09-06 01:09:20 +02:00
/* terminate */
{ }
} ;
MODULE_DEVICE_TABLE ( usb , carl9170_usb_ids ) ;
static void carl9170_usb_submit_data_urb ( struct ar9170 * ar )
{
struct urb * urb ;
int err ;
if ( atomic_inc_return ( & ar - > tx_anch_urbs ) > AR9170_NUM_TX_URBS )
goto err_acc ;
urb = usb_get_from_anchor ( & ar - > tx_wait ) ;
if ( ! urb )
goto err_acc ;
usb_anchor_urb ( urb , & ar - > tx_anch ) ;
err = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( unlikely ( err ) ) {
if ( net_ratelimit ( ) ) {
dev_err ( & ar - > udev - > dev , " tx submit failed (%d) \n " ,
urb - > status ) ;
}
usb_unanchor_urb ( urb ) ;
usb_anchor_urb ( urb , & ar - > tx_err ) ;
}
usb_free_urb ( urb ) ;
if ( likely ( err = = 0 ) )
return ;
err_acc :
atomic_dec ( & ar - > tx_anch_urbs ) ;
}
static void carl9170_usb_tx_data_complete ( struct urb * urb )
{
2010-11-30 13:42:08 -08:00
struct ar9170 * ar = usb_get_intfdata ( usb_ifnum_to_if ( urb - > dev , 0 ) ) ;
2010-09-06 01:09:20 +02:00
if ( WARN_ON_ONCE ( ! ar ) ) {
dev_kfree_skb_irq ( urb - > context ) ;
return ;
}
atomic_dec ( & ar - > tx_anch_urbs ) ;
switch ( urb - > status ) {
/* everything is fine */
case 0 :
carl9170_tx_callback ( ar , ( void * ) urb - > context ) ;
break ;
/* disconnect */
case - ENOENT :
case - ECONNRESET :
case - ENODEV :
case - ESHUTDOWN :
/*
* Defer the frame clean - up to the tasklet worker .
* This is necessary , because carl9170_tx_drop
* does not work in an irqsave context .
*/
usb_anchor_urb ( urb , & ar - > tx_err ) ;
return ;
/* a random transmission error has occurred? */
default :
if ( net_ratelimit ( ) ) {
dev_err ( & ar - > udev - > dev , " tx failed (%d) \n " ,
urb - > status ) ;
}
usb_anchor_urb ( urb , & ar - > tx_err ) ;
break ;
}
if ( likely ( IS_STARTED ( ar ) ) )
carl9170_usb_submit_data_urb ( ar ) ;
}
static int carl9170_usb_submit_cmd_urb ( struct ar9170 * ar )
{
struct urb * urb ;
int err ;
if ( atomic_inc_return ( & ar - > tx_cmd_urbs ) ! = 1 ) {
atomic_dec ( & ar - > tx_cmd_urbs ) ;
return 0 ;
}
urb = usb_get_from_anchor ( & ar - > tx_cmd ) ;
if ( ! urb ) {
atomic_dec ( & ar - > tx_cmd_urbs ) ;
return 0 ;
}
usb_anchor_urb ( urb , & ar - > tx_anch ) ;
err = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( unlikely ( err ) ) {
usb_unanchor_urb ( urb ) ;
atomic_dec ( & ar - > tx_cmd_urbs ) ;
}
usb_free_urb ( urb ) ;
return err ;
}
static void carl9170_usb_cmd_complete ( struct urb * urb )
{
struct ar9170 * ar = urb - > context ;
int err = 0 ;
if ( WARN_ON_ONCE ( ! ar ) )
return ;
atomic_dec ( & ar - > tx_cmd_urbs ) ;
switch ( urb - > status ) {
/* everything is fine */
case 0 :
break ;
/* disconnect */
case - ENOENT :
case - ECONNRESET :
case - ENODEV :
case - ESHUTDOWN :
return ;
default :
err = urb - > status ;
break ;
}
if ( ! IS_INITIALIZED ( ar ) )
return ;
if ( err )
dev_err ( & ar - > udev - > dev , " submit cmd cb failed (%d). \n " , err ) ;
err = carl9170_usb_submit_cmd_urb ( ar ) ;
if ( err )
dev_err ( & ar - > udev - > dev , " submit cmd failed (%d). \n " , err ) ;
}
static void carl9170_usb_rx_irq_complete ( struct urb * urb )
{
struct ar9170 * ar = urb - > context ;
if ( WARN_ON_ONCE ( ! ar ) )
return ;
switch ( urb - > status ) {
/* everything is fine */
case 0 :
break ;
/* disconnect */
case - ENOENT :
case - ECONNRESET :
case - ENODEV :
case - ESHUTDOWN :
return ;
default :
goto resubmit ;
}
2012-10-06 20:42:54 +02:00
/*
* While the carl9170 firmware does not use this EP , the
* firmware loader in the EEPROM unfortunately does .
* Therefore we need to be ready to handle out - of - band
* responses and traps in case the firmware crashed and
* the loader took over again .
*/
2010-09-06 01:09:20 +02:00
carl9170_handle_command_response ( ar , urb - > transfer_buffer ,
urb - > actual_length ) ;
resubmit :
usb_anchor_urb ( urb , & ar - > rx_anch ) ;
if ( unlikely ( usb_submit_urb ( urb , GFP_ATOMIC ) ) )
usb_unanchor_urb ( urb ) ;
}
static int carl9170_usb_submit_rx_urb ( struct ar9170 * ar , gfp_t gfp )
{
struct urb * urb ;
int err = 0 , runs = 0 ;
while ( ( atomic_read ( & ar - > rx_anch_urbs ) < AR9170_NUM_RX_URBS ) & &
( runs + + < AR9170_NUM_RX_URBS ) ) {
err = - ENOSPC ;
urb = usb_get_from_anchor ( & ar - > rx_pool ) ;
if ( urb ) {
usb_anchor_urb ( urb , & ar - > rx_anch ) ;
err = usb_submit_urb ( urb , gfp ) ;
if ( unlikely ( err ) ) {
usb_unanchor_urb ( urb ) ;
usb_anchor_urb ( urb , & ar - > rx_pool ) ;
} else {
atomic_dec ( & ar - > rx_pool_urbs ) ;
atomic_inc ( & ar - > rx_anch_urbs ) ;
}
usb_free_urb ( urb ) ;
}
}
return err ;
}
static void carl9170_usb_rx_work ( struct ar9170 * ar )
{
struct urb * urb ;
int i ;
for ( i = 0 ; i < AR9170_NUM_RX_URBS_POOL ; i + + ) {
urb = usb_get_from_anchor ( & ar - > rx_work ) ;
if ( ! urb )
break ;
atomic_dec ( & ar - > rx_work_urbs ) ;
if ( IS_INITIALIZED ( ar ) ) {
carl9170_rx ( ar , urb - > transfer_buffer ,
urb - > actual_length ) ;
}
usb_anchor_urb ( urb , & ar - > rx_pool ) ;
atomic_inc ( & ar - > rx_pool_urbs ) ;
usb_free_urb ( urb ) ;
carl9170_usb_submit_rx_urb ( ar , GFP_ATOMIC ) ;
}
}
void carl9170_usb_handle_tx_err ( struct ar9170 * ar )
{
struct urb * urb ;
while ( ( urb = usb_get_from_anchor ( & ar - > tx_err ) ) ) {
struct sk_buff * skb = ( void * ) urb - > context ;
carl9170_tx_drop ( ar , skb ) ;
carl9170_tx_callback ( ar , skb ) ;
usb_free_urb ( urb ) ;
}
}
static void carl9170_usb_tasklet ( unsigned long data )
{
struct ar9170 * ar = ( struct ar9170 * ) data ;
2010-09-17 22:47:28 +02:00
if ( ! IS_INITIALIZED ( ar ) )
return ;
2010-09-06 01:09:20 +02:00
carl9170_usb_rx_work ( ar ) ;
/*
* Strictly speaking : The tx scheduler is not part of the USB system .
* But the rx worker returns frames back to the mac80211 - stack and
* this is the _perfect_ place to generate the next transmissions .
*/
if ( IS_STARTED ( ar ) )
carl9170_tx_scheduler ( ar ) ;
}
static void carl9170_usb_rx_complete ( struct urb * urb )
{
struct ar9170 * ar = ( struct ar9170 * ) urb - > context ;
int err ;
if ( WARN_ON_ONCE ( ! ar ) )
return ;
atomic_dec ( & ar - > rx_anch_urbs ) ;
switch ( urb - > status ) {
case 0 :
/* rx path */
usb_anchor_urb ( urb , & ar - > rx_work ) ;
atomic_inc ( & ar - > rx_work_urbs ) ;
break ;
case - ENOENT :
case - ECONNRESET :
case - ENODEV :
case - ESHUTDOWN :
/* handle disconnect events*/
return ;
default :
/* handle all other errors */
usb_anchor_urb ( urb , & ar - > rx_pool ) ;
atomic_inc ( & ar - > rx_pool_urbs ) ;
break ;
}
err = carl9170_usb_submit_rx_urb ( ar , GFP_ATOMIC ) ;
if ( unlikely ( err ) ) {
/*
* usb_submit_rx_urb reported a problem .
* In case this is due to a rx buffer shortage ,
* elevate the tasklet worker priority to
* the highest available level .
*/
tasklet_hi_schedule ( & ar - > usb_tasklet ) ;
if ( atomic_read ( & ar - > rx_anch_urbs ) = = 0 ) {
/*
* The system is too slow to cope with
* the enormous workload . We have simply
* run out of active rx urbs and this
2011-03-30 22:57:33 -03:00
* unfortunately leads to an unpredictable
2010-09-06 01:09:20 +02:00
* device .
*/
2010-10-29 23:26:13 +02:00
ieee80211_queue_work ( ar - > hw , & ar - > ping_work ) ;
2010-09-06 01:09:20 +02:00
}
} else {
/*
* Using anything less than _high_ priority absolutely
* kills the rx performance my UP - System . . .
*/
tasklet_hi_schedule ( & ar - > usb_tasklet ) ;
}
}
static struct urb * carl9170_usb_alloc_rx_urb ( struct ar9170 * ar , gfp_t gfp )
{
struct urb * urb ;
void * buf ;
buf = kmalloc ( ar - > fw . rx_size , gfp ) ;
if ( ! buf )
return NULL ;
urb = usb_alloc_urb ( 0 , gfp ) ;
if ( ! urb ) {
kfree ( buf ) ;
return NULL ;
}
usb_fill_bulk_urb ( urb , ar - > udev , usb_rcvbulkpipe ( ar - > udev ,
AR9170_USB_EP_RX ) , buf , ar - > fw . rx_size ,
carl9170_usb_rx_complete , ar ) ;
urb - > transfer_flags | = URB_FREE_BUFFER ;
return urb ;
}
static int carl9170_usb_send_rx_irq_urb ( struct ar9170 * ar )
{
struct urb * urb = NULL ;
void * ibuf ;
int err = - ENOMEM ;
urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! urb )
goto out ;
ibuf = kmalloc ( AR9170_USB_EP_CTRL_MAX , GFP_KERNEL ) ;
if ( ! ibuf )
goto out ;
usb_fill_int_urb ( urb , ar - > udev , usb_rcvintpipe ( ar - > udev ,
AR9170_USB_EP_IRQ ) , ibuf , AR9170_USB_EP_CTRL_MAX ,
carl9170_usb_rx_irq_complete , ar , 1 ) ;
urb - > transfer_flags | = URB_FREE_BUFFER ;
usb_anchor_urb ( urb , & ar - > rx_anch ) ;
err = usb_submit_urb ( urb , GFP_KERNEL ) ;
if ( err )
usb_unanchor_urb ( urb ) ;
out :
usb_free_urb ( urb ) ;
return err ;
}
static int carl9170_usb_init_rx_bulk_urbs ( struct ar9170 * ar )
{
struct urb * urb ;
int i , err = - EINVAL ;
/*
* The driver actively maintains a second shadow
* pool for inactive , but fully - prepared rx urbs .
*
* The pool should help the driver to master huge
* workload spikes without running the risk of
* undersupplying the hardware or wasting time by
* processing rx data ( streams ) inside the urb
* completion ( hardirq context ) .
*/
for ( i = 0 ; i < AR9170_NUM_RX_URBS_POOL ; i + + ) {
urb = carl9170_usb_alloc_rx_urb ( ar , GFP_KERNEL ) ;
if ( ! urb ) {
err = - ENOMEM ;
goto err_out ;
}
usb_anchor_urb ( urb , & ar - > rx_pool ) ;
atomic_inc ( & ar - > rx_pool_urbs ) ;
usb_free_urb ( urb ) ;
}
err = carl9170_usb_submit_rx_urb ( ar , GFP_KERNEL ) ;
if ( err )
goto err_out ;
/* the device now waiting for the firmware. */
carl9170_set_state_when ( ar , CARL9170_STOPPED , CARL9170_IDLE ) ;
return 0 ;
err_out :
usb_scuttle_anchored_urbs ( & ar - > rx_pool ) ;
usb_scuttle_anchored_urbs ( & ar - > rx_work ) ;
usb_kill_anchored_urbs ( & ar - > rx_anch ) ;
return err ;
}
static int carl9170_usb_flush ( struct ar9170 * ar )
{
struct urb * urb ;
int ret , err = 0 ;
while ( ( urb = usb_get_from_anchor ( & ar - > tx_wait ) ) ) {
struct sk_buff * skb = ( void * ) urb - > context ;
carl9170_tx_drop ( ar , skb ) ;
carl9170_tx_callback ( ar , skb ) ;
usb_free_urb ( urb ) ;
}
2010-11-15 15:11:26 +01:00
ret = usb_wait_anchor_empty_timeout ( & ar - > tx_cmd , 1000 ) ;
2010-09-06 01:09:20 +02:00
if ( ret = = 0 )
err = - ETIMEDOUT ;
/* lets wait a while until the tx - queues are dried out */
2010-11-15 15:11:26 +01:00
ret = usb_wait_anchor_empty_timeout ( & ar - > tx_anch , 1000 ) ;
2010-09-06 01:09:20 +02:00
if ( ret = = 0 )
err = - ETIMEDOUT ;
usb_kill_anchored_urbs ( & ar - > tx_anch ) ;
carl9170_usb_handle_tx_err ( ar ) ;
return err ;
}
static void carl9170_usb_cancel_urbs ( struct ar9170 * ar )
{
int err ;
carl9170_set_state ( ar , CARL9170_UNKNOWN_STATE ) ;
err = carl9170_usb_flush ( ar ) ;
if ( err )
dev_err ( & ar - > udev - > dev , " stuck tx urbs! \n " ) ;
usb_poison_anchored_urbs ( & ar - > tx_anch ) ;
carl9170_usb_handle_tx_err ( ar ) ;
usb_poison_anchored_urbs ( & ar - > rx_anch ) ;
tasklet_kill ( & ar - > usb_tasklet ) ;
usb_scuttle_anchored_urbs ( & ar - > rx_work ) ;
usb_scuttle_anchored_urbs ( & ar - > rx_pool ) ;
usb_scuttle_anchored_urbs ( & ar - > tx_cmd ) ;
}
int __carl9170_exec_cmd ( struct ar9170 * ar , struct carl9170_cmd * cmd ,
const bool free_buf )
{
struct urb * urb ;
2010-10-16 01:38:46 +02:00
int err = 0 ;
2010-09-06 01:09:20 +02:00
2010-10-16 01:38:46 +02:00
if ( ! IS_INITIALIZED ( ar ) ) {
err = - EPERM ;
goto err_free ;
}
2010-09-06 01:09:20 +02:00
2010-10-16 01:38:46 +02:00
if ( WARN_ON ( cmd - > hdr . len > CARL9170_MAX_CMD_LEN - 4 ) ) {
err = - EINVAL ;
goto err_free ;
}
2010-09-06 01:09:20 +02:00
urb = usb_alloc_urb ( 0 , GFP_ATOMIC ) ;
2010-10-16 01:38:46 +02:00
if ( ! urb ) {
err = - ENOMEM ;
goto err_free ;
}
2010-09-06 01:09:20 +02:00
2014-08-07 14:15:50 +02:00
if ( ar - > usb_ep_cmd_is_bulk )
usb_fill_bulk_urb ( urb , ar - > udev ,
usb_sndbulkpipe ( ar - > udev , AR9170_USB_EP_CMD ) ,
cmd , cmd - > hdr . len + 4 ,
carl9170_usb_cmd_complete , ar ) ;
else
usb_fill_int_urb ( urb , ar - > udev ,
usb_sndintpipe ( ar - > udev , AR9170_USB_EP_CMD ) ,
cmd , cmd - > hdr . len + 4 ,
carl9170_usb_cmd_complete , ar , 1 ) ;
2010-09-06 01:09:20 +02:00
if ( free_buf )
urb - > transfer_flags | = URB_FREE_BUFFER ;
usb_anchor_urb ( urb , & ar - > tx_cmd ) ;
usb_free_urb ( urb ) ;
return carl9170_usb_submit_cmd_urb ( ar ) ;
2010-10-16 01:38:46 +02:00
err_free :
if ( free_buf )
kfree ( cmd ) ;
return err ;
2010-09-06 01:09:20 +02:00
}
int carl9170_exec_cmd ( struct ar9170 * ar , const enum carl9170_cmd_oids cmd ,
unsigned int plen , void * payload , unsigned int outlen , void * out )
{
int err = - ENOMEM ;
2015-05-12 20:18:38 +02:00
unsigned long time_left ;
2010-09-06 01:09:20 +02:00
if ( ! IS_ACCEPTING_CMD ( ar ) )
return - EIO ;
if ( ! ( cmd & CARL9170_CMD_ASYNC_FLAG ) )
might_sleep ( ) ;
ar - > cmd . hdr . len = plen ;
ar - > cmd . hdr . cmd = cmd ;
/* writing multiple regs fills this buffer already */
if ( plen & & payload ! = ( u8 * ) ( ar - > cmd . data ) )
memcpy ( ar - > cmd . data , payload , plen ) ;
spin_lock_bh ( & ar - > cmd_lock ) ;
ar - > readbuf = ( u8 * ) out ;
ar - > readlen = outlen ;
spin_unlock_bh ( & ar - > cmd_lock ) ;
err = __carl9170_exec_cmd ( ar , & ar - > cmd , false ) ;
if ( ! ( cmd & CARL9170_CMD_ASYNC_FLAG ) ) {
2015-05-12 20:18:38 +02:00
time_left = wait_for_completion_timeout ( & ar - > cmd_wait , HZ ) ;
if ( time_left = = 0 ) {
2010-09-06 01:09:20 +02:00
err = - ETIMEDOUT ;
goto err_unbuf ;
}
if ( ar - > readlen ! = outlen ) {
err = - EMSGSIZE ;
goto err_unbuf ;
}
}
return 0 ;
err_unbuf :
/* Maybe the device was removed in the moment we were waiting? */
if ( IS_STARTED ( ar ) ) {
dev_err ( & ar - > udev - > dev , " no command feedback "
" received (%d). \n " , err ) ;
/* provide some maybe useful debug information */
print_hex_dump_bytes ( " carl9170 cmd: " , DUMP_PREFIX_NONE ,
& ar - > cmd , plen + 4 ) ;
carl9170_restart ( ar , CARL9170_RR_COMMAND_TIMEOUT ) ;
}
/* invalidate to avoid completing the next command prematurely */
spin_lock_bh ( & ar - > cmd_lock ) ;
ar - > readbuf = NULL ;
ar - > readlen = 0 ;
spin_unlock_bh ( & ar - > cmd_lock ) ;
return err ;
}
void carl9170_usb_tx ( struct ar9170 * ar , struct sk_buff * skb )
{
struct urb * urb ;
struct ar9170_stream * tx_stream ;
void * data ;
unsigned int len ;
if ( ! IS_STARTED ( ar ) )
goto err_drop ;
urb = usb_alloc_urb ( 0 , GFP_ATOMIC ) ;
if ( ! urb )
goto err_drop ;
if ( ar - > fw . tx_stream ) {
tx_stream = ( void * ) ( skb - > data - sizeof ( * tx_stream ) ) ;
len = skb - > len + sizeof ( * tx_stream ) ;
tx_stream - > length = cpu_to_le16 ( len ) ;
tx_stream - > tag = cpu_to_le16 ( AR9170_TX_STREAM_TAG ) ;
data = tx_stream ;
} else {
data = skb - > data ;
len = skb - > len ;
}
usb_fill_bulk_urb ( urb , ar - > udev , usb_sndbulkpipe ( ar - > udev ,
AR9170_USB_EP_TX ) , data , len ,
carl9170_usb_tx_data_complete , skb ) ;
urb - > transfer_flags | = URB_ZERO_PACKET ;
usb_anchor_urb ( urb , & ar - > tx_wait ) ;
usb_free_urb ( urb ) ;
carl9170_usb_submit_data_urb ( ar ) ;
return ;
err_drop :
carl9170_tx_drop ( ar , skb ) ;
carl9170_tx_callback ( ar , skb ) ;
}
static void carl9170_release_firmware ( struct ar9170 * ar )
{
if ( ar - > fw . fw ) {
release_firmware ( ar - > fw . fw ) ;
memset ( & ar - > fw , 0 , sizeof ( ar - > fw ) ) ;
}
}
void carl9170_usb_stop ( struct ar9170 * ar )
{
int ret ;
carl9170_set_state_when ( ar , CARL9170_IDLE , CARL9170_STOPPED ) ;
ret = carl9170_usb_flush ( ar ) ;
if ( ret )
dev_err ( & ar - > udev - > dev , " kill pending tx urbs. \n " ) ;
usb_poison_anchored_urbs ( & ar - > tx_anch ) ;
carl9170_usb_handle_tx_err ( ar ) ;
/* kill any pending command */
spin_lock_bh ( & ar - > cmd_lock ) ;
ar - > readlen = 0 ;
spin_unlock_bh ( & ar - > cmd_lock ) ;
complete_all ( & ar - > cmd_wait ) ;
/* This is required to prevent an early completion on _start */
2013-11-14 14:32:02 -08:00
reinit_completion ( & ar - > cmd_wait ) ;
2010-09-06 01:09:20 +02:00
/*
* Note :
* So far we freed all tx urbs , but we won ' t dare to touch any rx urbs .
* Else we would end up with a unresponsive device . . .
*/
}
int carl9170_usb_open ( struct ar9170 * ar )
{
usb_unpoison_anchored_urbs ( & ar - > tx_anch ) ;
carl9170_set_state_when ( ar , CARL9170_STOPPED , CARL9170_IDLE ) ;
return 0 ;
}
static int carl9170_usb_load_firmware ( struct ar9170 * ar )
{
const u8 * data ;
u8 * buf ;
unsigned int transfer ;
size_t len ;
u32 addr ;
int err = 0 ;
buf = kmalloc ( 4096 , GFP_KERNEL ) ;
if ( ! buf ) {
err = - ENOMEM ;
goto err_out ;
}
data = ar - > fw . fw - > data ;
len = ar - > fw . fw - > size ;
addr = ar - > fw . address ;
/* this removes the miniboot image */
data + = ar - > fw . offset ;
len - = ar - > fw . offset ;
while ( len ) {
transfer = min_t ( unsigned int , len , 4096u ) ;
memcpy ( buf , data , transfer ) ;
err = usb_control_msg ( ar - > udev , usb_sndctrlpipe ( ar - > udev , 0 ) ,
0x30 /* FW DL */ , 0x40 | USB_DIR_OUT ,
addr > > 8 , 0 , buf , transfer , 100 ) ;
if ( err < 0 ) {
kfree ( buf ) ;
goto err_out ;
}
len - = transfer ;
data + = transfer ;
addr + = transfer ;
}
kfree ( buf ) ;
err = usb_control_msg ( ar - > udev , usb_sndctrlpipe ( ar - > udev , 0 ) ,
0x31 /* FW DL COMPLETE */ ,
0x40 | USB_DIR_OUT , 0 , 0 , NULL , 0 , 200 ) ;
if ( wait_for_completion_timeout ( & ar - > fw_boot_wait , HZ ) = = 0 ) {
err = - ETIMEDOUT ;
goto err_out ;
}
err = carl9170_echo_test ( ar , 0x4a110123 ) ;
if ( err )
goto err_out ;
2010-12-26 18:22:29 +01:00
/* now, start the command response counter */
2010-09-06 01:09:20 +02:00
ar - > cmd_seq = - 1 ;
return 0 ;
err_out :
dev_err ( & ar - > udev - > dev , " firmware upload failed (%d). \n " , err ) ;
return err ;
}
int carl9170_usb_restart ( struct ar9170 * ar )
{
int err = 0 ;
if ( ar - > intf - > condition ! = USB_INTERFACE_BOUND )
return 0 ;
2010-12-26 18:22:29 +01:00
/*
* Disable the command response sequence counter check .
* We already know that the device / firmware is in a bad state .
* So , no extra points are awarded to anyone who reminds the
* driver about that .
*/
2010-09-06 01:09:20 +02:00
ar - > cmd_seq = - 2 ;
err = carl9170_reboot ( ar ) ;
carl9170_usb_stop ( ar ) ;
if ( err )
goto err_out ;
tasklet_schedule ( & ar - > usb_tasklet ) ;
/* The reboot procedure can take quite a while to complete. */
msleep ( 1100 ) ;
err = carl9170_usb_open ( ar ) ;
if ( err )
goto err_out ;
err = carl9170_usb_load_firmware ( ar ) ;
if ( err )
goto err_out ;
return 0 ;
err_out :
carl9170_usb_cancel_urbs ( ar ) ;
return err ;
}
void carl9170_usb_reset ( struct ar9170 * ar )
{
/*
* This is the last resort to get the device going again
* without any * user replugging action * .
*
* But there is a catch : usb_reset really is like a physical
* * reconnect * . The mac80211 state will be lost in the process .
* Therefore a userspace application , which is monitoring
* the link must step in .
*/
carl9170_usb_cancel_urbs ( ar ) ;
carl9170_usb_stop ( ar ) ;
usb_queue_reset_device ( ar - > intf ) ;
}
static int carl9170_usb_init_device ( struct ar9170 * ar )
{
int err ;
2010-12-26 18:22:29 +01:00
/*
* The carl9170 firmware let ' s the driver know when it ' s
* ready for action . But we have to be prepared to gracefully
* handle all spurious [ flushed ] messages after each ( re - ) boot .
* Thus the command response counter remains disabled until it
* can be safely synchronized .
*/
ar - > cmd_seq = - 2 ;
2010-09-06 01:09:20 +02:00
err = carl9170_usb_send_rx_irq_urb ( ar ) ;
if ( err )
goto err_out ;
err = carl9170_usb_init_rx_bulk_urbs ( ar ) ;
if ( err )
goto err_unrx ;
2010-12-26 18:22:29 +01:00
err = carl9170_usb_open ( ar ) ;
if ( err )
goto err_unrx ;
2010-09-06 01:09:20 +02:00
mutex_lock ( & ar - > mutex ) ;
err = carl9170_usb_load_firmware ( ar ) ;
mutex_unlock ( & ar - > mutex ) ;
if ( err )
2010-12-26 18:22:29 +01:00
goto err_stop ;
2010-09-06 01:09:20 +02:00
return 0 ;
2010-12-26 18:22:29 +01:00
err_stop :
carl9170_usb_stop ( ar ) ;
2010-09-06 01:09:20 +02:00
err_unrx :
carl9170_usb_cancel_urbs ( ar ) ;
err_out :
return err ;
}
static void carl9170_usb_firmware_failed ( struct ar9170 * ar )
{
struct device * parent = ar - > udev - > dev . parent ;
struct usb_device * udev ;
/*
* Store a copy of the usb_device pointer locally .
* This is because device_release_driver initiates
* carl9170_usb_disconnect , which in turn frees our
* driver context ( ar ) .
*/
udev = ar - > udev ;
complete ( & ar - > fw_load_wait ) ;
/* unbind anything failed */
if ( parent )
device_lock ( parent ) ;
device_release_driver ( & udev - > dev ) ;
if ( parent )
device_unlock ( parent ) ;
usb_put_dev ( udev ) ;
}
static void carl9170_usb_firmware_finish ( struct ar9170 * ar )
{
int err ;
err = carl9170_parse_firmware ( ar ) ;
if ( err )
goto err_freefw ;
err = carl9170_usb_init_device ( ar ) ;
if ( err )
goto err_freefw ;
err = carl9170_register ( ar ) ;
carl9170_usb_stop ( ar ) ;
if ( err )
goto err_unrx ;
complete ( & ar - > fw_load_wait ) ;
usb_put_dev ( ar - > udev ) ;
return ;
err_unrx :
carl9170_usb_cancel_urbs ( ar ) ;
err_freefw :
carl9170_release_firmware ( ar ) ;
carl9170_usb_firmware_failed ( ar ) ;
}
static void carl9170_usb_firmware_step2 ( const struct firmware * fw ,
void * context )
{
struct ar9170 * ar = context ;
if ( fw ) {
ar - > fw . fw = fw ;
carl9170_usb_firmware_finish ( ar ) ;
return ;
}
dev_err ( & ar - > udev - > dev , " firmware not found. \n " ) ;
carl9170_usb_firmware_failed ( ar ) ;
}
static int carl9170_usb_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
2014-08-07 14:15:50 +02:00
struct usb_endpoint_descriptor * ep ;
2010-09-06 01:09:20 +02:00
struct ar9170 * ar ;
struct usb_device * udev ;
2014-08-07 14:15:50 +02:00
int i , err ;
2010-09-06 01:09:20 +02:00
err = usb_reset_device ( interface_to_usbdev ( intf ) ) ;
if ( err )
return err ;
ar = carl9170_alloc ( sizeof ( * ar ) ) ;
if ( IS_ERR ( ar ) )
return PTR_ERR ( ar ) ;
udev = interface_to_usbdev ( intf ) ;
usb_get_dev ( udev ) ;
ar - > udev = udev ;
ar - > intf = intf ;
ar - > features = id - > driver_info ;
2014-08-07 14:15:50 +02:00
/* We need to remember the type of endpoint 4 because it differs
* between high - and full - speed configuration . The high - speed
* configuration specifies it as interrupt and the full - speed
* configuration as bulk endpoint . This information is required
* later when sending urbs to that endpoint .
*/
for ( i = 0 ; i < intf - > cur_altsetting - > desc . bNumEndpoints ; + + i ) {
ep = & intf - > cur_altsetting - > endpoint [ i ] . desc ;
if ( usb_endpoint_num ( ep ) = = AR9170_USB_EP_CMD & &
usb_endpoint_dir_out ( ep ) & &
usb_endpoint_type ( ep ) = = USB_ENDPOINT_XFER_BULK )
ar - > usb_ep_cmd_is_bulk = true ;
}
2010-09-06 01:09:20 +02:00
usb_set_intfdata ( intf , ar ) ;
SET_IEEE80211_DEV ( ar - > hw , & intf - > dev ) ;
init_usb_anchor ( & ar - > rx_anch ) ;
init_usb_anchor ( & ar - > rx_pool ) ;
init_usb_anchor ( & ar - > rx_work ) ;
init_usb_anchor ( & ar - > tx_wait ) ;
init_usb_anchor ( & ar - > tx_anch ) ;
init_usb_anchor ( & ar - > tx_cmd ) ;
init_usb_anchor ( & ar - > tx_err ) ;
init_completion ( & ar - > cmd_wait ) ;
init_completion ( & ar - > fw_boot_wait ) ;
init_completion ( & ar - > fw_load_wait ) ;
tasklet_init ( & ar - > usb_tasklet , carl9170_usb_tasklet ,
( unsigned long ) ar ) ;
atomic_set ( & ar - > tx_cmd_urbs , 0 ) ;
atomic_set ( & ar - > tx_anch_urbs , 0 ) ;
atomic_set ( & ar - > rx_work_urbs , 0 ) ;
atomic_set ( & ar - > rx_anch_urbs , 0 ) ;
atomic_set ( & ar - > rx_pool_urbs , 0 ) ;
usb_get_dev ( ar - > udev ) ;
carl9170_set_state ( ar , CARL9170_STOPPED ) ;
2013-09-27 23:51:51 -04:00
err = request_firmware_nowait ( THIS_MODULE , 1 , CARL9170FW_NAME ,
2010-09-06 01:09:20 +02:00
& ar - > udev - > dev , GFP_KERNEL , ar , carl9170_usb_firmware_step2 ) ;
2013-09-27 23:51:51 -04:00
if ( err ) {
usb_put_dev ( udev ) ;
usb_put_dev ( udev ) ;
carl9170_free ( ar ) ;
}
return err ;
2010-09-06 01:09:20 +02:00
}
static void carl9170_usb_disconnect ( struct usb_interface * intf )
{
struct ar9170 * ar = usb_get_intfdata ( intf ) ;
struct usb_device * udev ;
if ( WARN_ON ( ! ar ) )
return ;
udev = ar - > udev ;
wait_for_completion ( & ar - > fw_load_wait ) ;
if ( IS_INITIALIZED ( ar ) ) {
carl9170_reboot ( ar ) ;
carl9170_usb_stop ( ar ) ;
}
carl9170_usb_cancel_urbs ( ar ) ;
carl9170_unregister ( ar ) ;
usb_set_intfdata ( intf , NULL ) ;
carl9170_release_firmware ( ar ) ;
carl9170_free ( ar ) ;
usb_put_dev ( udev ) ;
}
# ifdef CONFIG_PM
static int carl9170_usb_suspend ( struct usb_interface * intf ,
pm_message_t message )
{
struct ar9170 * ar = usb_get_intfdata ( intf ) ;
if ( ! ar )
return - ENODEV ;
carl9170_usb_cancel_urbs ( ar ) ;
return 0 ;
}
static int carl9170_usb_resume ( struct usb_interface * intf )
{
struct ar9170 * ar = usb_get_intfdata ( intf ) ;
int err ;
if ( ! ar )
return - ENODEV ;
usb_unpoison_anchored_urbs ( & ar - > rx_anch ) ;
2010-12-26 18:22:29 +01:00
carl9170_set_state ( ar , CARL9170_STOPPED ) ;
2010-09-06 01:09:20 +02:00
2010-12-26 18:22:29 +01:00
/*
* The USB documentation demands that [ for suspend ] all traffic
* to and from the device has to stop . This would be fine , but
* there ' s a catch : the device [ usb phy ] does not come back .
*
* Upon resume the firmware will " kill " itself and the
* boot - code sorts out the magic voodoo .
* Not very nice , but there ' s not much what could go wrong .
*/
msleep ( 1100 ) ;
2010-09-06 01:09:20 +02:00
2010-12-26 18:22:29 +01:00
err = carl9170_usb_init_device ( ar ) ;
2010-09-06 01:09:20 +02:00
if ( err )
goto err_unrx ;
return 0 ;
err_unrx :
carl9170_usb_cancel_urbs ( ar ) ;
return err ;
}
# endif /* CONFIG_PM */
static struct usb_driver carl9170_driver = {
. name = KBUILD_MODNAME ,
. probe = carl9170_usb_probe ,
. disconnect = carl9170_usb_disconnect ,
. id_table = carl9170_usb_ids ,
. soft_unbind = 1 ,
# ifdef CONFIG_PM
. suspend = carl9170_usb_suspend ,
. resume = carl9170_usb_resume ,
2010-12-26 18:22:29 +01:00
. reset_resume = carl9170_usb_resume ,
2010-09-06 01:09:20 +02:00
# endif /* CONFIG_PM */
2012-04-23 10:08:51 -07:00
. disable_hub_initiated_lpm = 1 ,
2010-09-06 01:09:20 +02:00
} ;
2011-11-18 09:44:20 -08:00
module_usb_driver ( carl9170_driver ) ;