2012-04-18 20:08:28 -07:00
/*
* Marvell Wireless LAN device driver : USB specific handling
*
2014-06-19 21:38:57 -07:00
* Copyright ( C ) 2012 - 2014 , Marvell International Ltd .
2012-04-18 20:08:28 -07:00
*
* This software file ( the " File " ) is distributed by Marvell International
* Ltd . under the terms of the GNU General Public License Version 2 , June 1991
* ( the " License " ) . You may use , redistribute and / or modify this File in
* accordance with the terms and conditions of the License , a copy of which
* is available by writing to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA or on the
* worldwide web at http : //www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS - IS , WITHOUT WARRANTY OF ANY KIND , AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED . The License provides additional details about
* this warranty disclaimer .
*/
# include "main.h"
# include "usb.h"
# define USB_VERSION "1.0"
2014-04-14 15:32:54 -07:00
static u8 user_rmmod ;
2012-04-18 20:08:28 -07:00
static struct mwifiex_if_ops usb_ops ;
static struct semaphore add_remove_card_sem ;
static struct usb_device_id mwifiex_usb_table [ ] = {
2014-11-20 16:52:58 +01:00
/* 8766 */
{ USB_DEVICE ( USB8XXX_VID , USB8766_PID_1 ) } ,
{ USB_DEVICE_AND_INTERFACE_INFO ( USB8XXX_VID , USB8766_PID_2 ,
USB_CLASS_VENDOR_SPEC ,
USB_SUBCLASS_VENDOR_SPEC , 0xff ) } ,
2014-01-09 19:36:55 -08:00
/* 8797 */
{ USB_DEVICE ( USB8XXX_VID , USB8797_PID_1 ) } ,
{ USB_DEVICE_AND_INTERFACE_INFO ( USB8XXX_VID , USB8797_PID_2 ,
USB_CLASS_VENDOR_SPEC ,
USB_SUBCLASS_VENDOR_SPEC , 0xff ) } ,
2015-01-23 17:09:18 +05:30
/* 8801 */
{ USB_DEVICE ( USB8XXX_VID , USB8801_PID_1 ) } ,
{ USB_DEVICE_AND_INTERFACE_INFO ( USB8XXX_VID , USB8801_PID_2 ,
USB_CLASS_VENDOR_SPEC ,
USB_SUBCLASS_VENDOR_SPEC , 0xff ) } ,
2015-08-05 06:09:40 -07:00
/* 8997 */
{ USB_DEVICE ( USB8XXX_VID , USB8997_PID_1 ) } ,
{ USB_DEVICE_AND_INTERFACE_INFO ( USB8XXX_VID , USB8997_PID_2 ,
USB_CLASS_VENDOR_SPEC ,
USB_SUBCLASS_VENDOR_SPEC , 0xff ) } ,
2012-04-18 20:08:28 -07:00
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , mwifiex_usb_table ) ;
static int mwifiex_usb_submit_rx_urb ( struct urb_context * ctx , int size ) ;
/* This function handles received packet. Necessary action is taken based on
* cmd / event / data .
*/
static int mwifiex_usb_recv ( struct mwifiex_adapter * adapter ,
struct sk_buff * skb , u8 ep )
{
u32 recv_type ;
__le32 tmp ;
2012-06-20 20:21:13 -07:00
int ret ;
2012-04-18 20:08:28 -07:00
if ( adapter - > hs_activated )
mwifiex_process_hs_config ( adapter ) ;
if ( skb - > len < INTF_HEADER_LEN ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" %s: invalid skb->len \n " , __func__ ) ;
2012-04-18 20:08:28 -07:00
return - 1 ;
}
switch ( ep ) {
case MWIFIEX_USB_EP_CMD_EVENT :
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , EVENT ,
" %s: EP_CMD_EVENT \n " , __func__ ) ;
2012-04-18 20:08:28 -07:00
skb_copy_from_linear_data ( skb , & tmp , INTF_HEADER_LEN ) ;
recv_type = le32_to_cpu ( tmp ) ;
skb_pull ( skb , INTF_HEADER_LEN ) ;
switch ( recv_type ) {
case MWIFIEX_USB_TYPE_CMD :
if ( skb - > len > MWIFIEX_SIZE_OF_CMD_BUFFER ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" CMD: skb->len too large \n " ) ;
2012-06-20 20:21:13 -07:00
ret = - 1 ;
goto exit_restore_skb ;
2012-04-18 20:08:28 -07:00
} else if ( ! adapter - > curr_cmd ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , WARN , " CMD: no curr_cmd \n " ) ;
2012-04-18 20:08:28 -07:00
if ( adapter - > ps_state = = PS_STATE_SLEEP_CFM ) {
mwifiex_process_sleep_confirm_resp (
adapter , skb - > data ,
skb - > len ) ;
2012-06-20 20:21:13 -07:00
ret = 0 ;
goto exit_restore_skb ;
2012-04-18 20:08:28 -07:00
}
2012-06-20 20:21:13 -07:00
ret = - 1 ;
goto exit_restore_skb ;
2012-04-18 20:08:28 -07:00
}
adapter - > curr_cmd - > resp_skb = skb ;
adapter - > cmd_resp_received = true ;
break ;
case MWIFIEX_USB_TYPE_EVENT :
if ( skb - > len < sizeof ( u32 ) ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" EVENT: skb->len too small \n " ) ;
2012-06-20 20:21:13 -07:00
ret = - 1 ;
goto exit_restore_skb ;
2012-04-18 20:08:28 -07:00
}
skb_copy_from_linear_data ( skb , & tmp , sizeof ( u32 ) ) ;
adapter - > event_cause = le32_to_cpu ( tmp ) ;
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , EVENT ,
" event_cause %#x \n " , adapter - > event_cause ) ;
2012-04-18 20:08:28 -07:00
if ( skb - > len > MAX_EVENT_SIZE ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" EVENT: event body too large \n " ) ;
2012-06-20 20:21:13 -07:00
ret = - 1 ;
goto exit_restore_skb ;
2012-04-18 20:08:28 -07:00
}
2012-06-20 20:21:12 -07:00
memcpy ( adapter - > event_body , skb - > data +
MWIFIEX_EVENT_HEADER_LEN , skb - > len ) ;
2012-04-18 20:08:28 -07:00
adapter - > event_received = true ;
adapter - > event_skb = skb ;
break ;
default :
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" unknown recv_type %#x \n " , recv_type ) ;
2012-04-18 20:08:28 -07:00
return - 1 ;
}
break ;
case MWIFIEX_USB_EP_DATA :
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , DATA , " %s: EP_DATA \n " , __func__ ) ;
2012-04-18 20:08:28 -07:00
if ( skb - > len > MWIFIEX_RX_DATA_BUF_SIZE ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" DATA: skb->len too large \n " ) ;
2012-04-18 20:08:28 -07:00
return - 1 ;
}
2014-11-05 17:04:27 +05:30
skb_queue_tail ( & adapter - > rx_data_q , skb ) ;
2012-04-18 20:08:28 -07:00
adapter - > data_received = true ;
2014-11-05 17:04:27 +05:30
atomic_inc ( & adapter - > rx_pending ) ;
2012-04-18 20:08:28 -07:00
break ;
default :
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" %s: unknown endport %#x \n " , __func__ , ep ) ;
2012-04-18 20:08:28 -07:00
return - 1 ;
}
return - EINPROGRESS ;
2012-06-20 20:21:13 -07:00
exit_restore_skb :
/* The buffer will be reused for further cmds/events */
skb_push ( skb , INTF_HEADER_LEN ) ;
return ret ;
2012-04-18 20:08:28 -07:00
}
static void mwifiex_usb_rx_complete ( struct urb * urb )
{
struct urb_context * context = ( struct urb_context * ) urb - > context ;
struct mwifiex_adapter * adapter = context - > adapter ;
struct sk_buff * skb = context - > skb ;
struct usb_card_rec * card ;
int recv_length = urb - > actual_length ;
int size , status ;
if ( ! adapter | | ! adapter - > card ) {
pr_err ( " mwifiex adapter or card structure is not valid \n " ) ;
return ;
}
card = ( struct usb_card_rec * ) adapter - > card ;
if ( card - > rx_cmd_ep = = context - > ep )
atomic_dec ( & card - > rx_cmd_urb_pending ) ;
else
atomic_dec ( & card - > rx_data_urb_pending ) ;
if ( recv_length ) {
if ( urb - > status | | ( adapter - > surprise_removed ) ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" URB status is failed: %d \n " , urb - > status ) ;
2012-04-18 20:08:28 -07:00
/* Do not free skb in case of command ep */
if ( card - > rx_cmd_ep ! = context - > ep )
dev_kfree_skb_any ( skb ) ;
goto setup_for_next ;
}
if ( skb - > len > recv_length )
skb_trim ( skb , recv_length ) ;
else
skb_put ( skb , recv_length - skb - > len ) ;
status = mwifiex_usb_recv ( adapter , skb , context - > ep ) ;
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , INFO ,
" info: recv_length=%d, status=%d \n " ,
recv_length , status ) ;
2012-04-18 20:08:28 -07:00
if ( status = = - EINPROGRESS ) {
2015-03-13 17:37:54 +05:30
mwifiex_queue_main_work ( adapter ) ;
2012-04-18 20:08:28 -07:00
/* urb for data_ep is re-submitted now;
* urb for cmd_ep will be re - submitted in callback
* mwifiex_usb_recv_complete
*/
if ( card - > rx_cmd_ep = = context - > ep )
return ;
} else {
if ( status = = - 1 )
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" received data processing failed! \n " ) ;
2012-04-18 20:08:28 -07:00
/* Do not free skb in case of command ep */
if ( card - > rx_cmd_ep ! = context - > ep )
dev_kfree_skb_any ( skb ) ;
}
} else if ( urb - > status ) {
if ( ! adapter - > is_suspended ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , FATAL ,
" Card is removed: %d \n " , urb - > status ) ;
2012-04-18 20:08:28 -07:00
adapter - > surprise_removed = true ;
}
dev_kfree_skb_any ( skb ) ;
return ;
} else {
/* Do not free skb in case of command ep */
if ( card - > rx_cmd_ep ! = context - > ep )
dev_kfree_skb_any ( skb ) ;
/* fall through setup_for_next */
}
setup_for_next :
if ( card - > rx_cmd_ep = = context - > ep )
size = MWIFIEX_RX_CMD_BUF_SIZE ;
else
size = MWIFIEX_RX_DATA_BUF_SIZE ;
2014-11-05 17:04:29 +05:30
if ( card - > rx_cmd_ep = = context - > ep ) {
mwifiex_usb_submit_rx_urb ( context , size ) ;
} else {
2015-06-28 20:07:38 -05:00
if ( atomic_read ( & adapter - > rx_pending ) < = HIGH_RX_PENDING ) {
2014-11-05 17:04:29 +05:30
mwifiex_usb_submit_rx_urb ( context , size ) ;
2015-06-28 20:07:38 -05:00
} else {
context - > skb = NULL ;
}
2014-11-05 17:04:29 +05:30
}
2012-04-18 20:08:28 -07:00
return ;
}
static void mwifiex_usb_tx_complete ( struct urb * urb )
{
struct urb_context * context = ( struct urb_context * ) ( urb - > context ) ;
struct mwifiex_adapter * adapter = context - > adapter ;
struct usb_card_rec * card = adapter - > card ;
2015-09-18 06:32:16 -07:00
struct usb_tx_data_port * port ;
int i ;
2012-04-18 20:08:28 -07:00
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , INFO ,
" %s: status: %d \n " , __func__ , urb - > status ) ;
2012-04-18 20:08:28 -07:00
if ( context - > ep = = card - > tx_cmd_ep ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , CMD ,
" %s: CMD \n " , __func__ ) ;
2012-04-18 20:08:28 -07:00
atomic_dec ( & card - > tx_cmd_urb_pending ) ;
adapter - > cmd_sent = false ;
} else {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , DATA ,
" %s: DATA \n " , __func__ ) ;
2015-09-18 06:32:16 -07:00
for ( i = 0 ; i < MWIFIEX_TX_DATA_PORT ; i + + ) {
port = & card - > port [ i ] ;
if ( context - > ep = = port - > tx_data_ep ) {
atomic_dec ( & port - > tx_data_urb_pending ) ;
2015-09-18 06:32:18 -07:00
port - > block_status = false ;
2015-09-18 06:32:16 -07:00
break ;
}
}
2015-09-18 06:32:14 -07:00
adapter - > data_sent = false ;
2012-11-01 18:44:16 -07:00
mwifiex_write_data_complete ( adapter , context - > skb , 0 ,
2012-04-18 20:08:28 -07:00
urb - > status ? - 1 : 0 ) ;
}
2015-09-18 06:32:17 -07:00
if ( card - > mc_resync_flag )
mwifiex_multi_chan_resync ( adapter ) ;
2015-03-13 17:37:54 +05:30
mwifiex_queue_main_work ( adapter ) ;
2012-04-18 20:08:28 -07:00
return ;
}
static int mwifiex_usb_submit_rx_urb ( struct urb_context * ctx , int size )
{
struct mwifiex_adapter * adapter = ctx - > adapter ;
struct usb_card_rec * card = ( struct usb_card_rec * ) adapter - > card ;
if ( card - > rx_cmd_ep ! = ctx - > ep ) {
ctx - > skb = dev_alloc_skb ( size ) ;
if ( ! ctx - > skb ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" %s: dev_alloc_skb failed \n " , __func__ ) ;
2012-04-18 20:08:28 -07:00
return - ENOMEM ;
}
}
usb_fill_bulk_urb ( ctx - > urb , card - > udev ,
usb_rcvbulkpipe ( card - > udev , ctx - > ep ) , ctx - > skb - > data ,
size , mwifiex_usb_rx_complete , ( void * ) ctx ) ;
if ( card - > rx_cmd_ep = = ctx - > ep )
atomic_inc ( & card - > rx_cmd_urb_pending ) ;
else
atomic_inc ( & card - > rx_data_urb_pending ) ;
if ( usb_submit_urb ( ctx - > urb , GFP_ATOMIC ) ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR , " usb_submit_urb failed \n " ) ;
2012-04-18 20:08:28 -07:00
dev_kfree_skb_any ( ctx - > skb ) ;
ctx - > skb = NULL ;
if ( card - > rx_cmd_ep = = ctx - > ep )
atomic_dec ( & card - > rx_cmd_urb_pending ) ;
else
atomic_dec ( & card - > rx_data_urb_pending ) ;
return - 1 ;
}
return 0 ;
}
static void mwifiex_usb_free ( struct usb_card_rec * card )
{
2015-09-18 06:32:16 -07:00
struct usb_tx_data_port * port ;
int i , j ;
2012-04-18 20:08:28 -07:00
if ( atomic_read ( & card - > rx_cmd_urb_pending ) & & card - > rx_cmd . urb )
usb_kill_urb ( card - > rx_cmd . urb ) ;
usb_free_urb ( card - > rx_cmd . urb ) ;
card - > rx_cmd . urb = NULL ;
if ( atomic_read ( & card - > rx_data_urb_pending ) )
for ( i = 0 ; i < MWIFIEX_RX_DATA_URB ; i + + )
if ( card - > rx_data_list [ i ] . urb )
usb_kill_urb ( card - > rx_data_list [ i ] . urb ) ;
for ( i = 0 ; i < MWIFIEX_RX_DATA_URB ; i + + ) {
usb_free_urb ( card - > rx_data_list [ i ] . urb ) ;
card - > rx_data_list [ i ] . urb = NULL ;
}
2015-09-18 06:32:16 -07:00
for ( i = 0 ; i < MWIFIEX_TX_DATA_PORT ; i + + ) {
port = & card - > port [ i ] ;
for ( j = 0 ; j < MWIFIEX_TX_DATA_URB ; j + + ) {
usb_free_urb ( port - > tx_data_list [ j ] . urb ) ;
port - > tx_data_list [ j ] . urb = NULL ;
}
2012-04-18 20:08:28 -07:00
}
usb_free_urb ( card - > tx_cmd . urb ) ;
card - > tx_cmd . urb = NULL ;
return ;
}
/* This function probes an mwifiex device and registers it. It allocates
* the card structure , initiates the device registration and initialization
* procedure by adding a logical interface .
*/
static int mwifiex_usb_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct usb_device * udev = interface_to_usbdev ( intf ) ;
struct usb_host_interface * iface_desc = intf - > cur_altsetting ;
struct usb_endpoint_descriptor * epd ;
int ret , i ;
struct usb_card_rec * card ;
u16 id_vendor , id_product , bcd_device , bcd_usb ;
card = kzalloc ( sizeof ( struct usb_card_rec ) , GFP_KERNEL ) ;
if ( ! card )
return - ENOMEM ;
id_vendor = le16_to_cpu ( udev - > descriptor . idVendor ) ;
id_product = le16_to_cpu ( udev - > descriptor . idProduct ) ;
bcd_device = le16_to_cpu ( udev - > descriptor . bcdDevice ) ;
bcd_usb = le16_to_cpu ( udev - > descriptor . bcdUSB ) ;
pr_debug ( " info: VID/PID = %X/%X, Boot2 version = %X \n " ,
id_vendor , id_product , bcd_device ) ;
/* PID_1 is used for firmware downloading only */
2014-01-09 19:36:55 -08:00
switch ( id_product ) {
2014-11-20 16:52:58 +01:00
case USB8766_PID_1 :
2014-01-09 19:36:55 -08:00
case USB8797_PID_1 :
2015-01-23 17:09:18 +05:30
case USB8801_PID_1 :
2015-08-05 06:09:40 -07:00
case USB8997_PID_1 :
2014-01-09 19:36:55 -08:00
card - > usb_boot_state = USB8XXX_FW_DNLD ;
break ;
2014-11-20 16:52:58 +01:00
case USB8766_PID_2 :
2014-01-09 19:36:55 -08:00
case USB8797_PID_2 :
2015-01-23 17:09:18 +05:30
case USB8801_PID_2 :
2015-08-05 06:09:40 -07:00
case USB8997_PID_2 :
2014-01-09 19:36:55 -08:00
card - > usb_boot_state = USB8XXX_FW_READY ;
break ;
default :
2014-09-09 20:27:44 -07:00
pr_warn ( " unknown id_product %#x \n " , id_product ) ;
2014-01-09 19:36:55 -08:00
card - > usb_boot_state = USB8XXX_FW_DNLD ;
break ;
}
2012-04-18 20:08:28 -07:00
card - > udev = udev ;
card - > intf = intf ;
2012-11-30 22:08:31 +09:00
pr_debug ( " info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x \n " ,
2012-04-18 20:08:28 -07:00
udev - > descriptor . bcdUSB , udev - > descriptor . bDeviceClass ,
udev - > descriptor . bDeviceSubClass ,
udev - > descriptor . bDeviceProtocol ) ;
for ( i = 0 ; i < iface_desc - > desc . bNumEndpoints ; + + i ) {
epd = & iface_desc - > endpoint [ i ] . desc ;
if ( usb_endpoint_dir_in ( epd ) & &
usb_endpoint_num ( epd ) = = MWIFIEX_USB_EP_CMD_EVENT & &
usb_endpoint_xfer_bulk ( epd ) ) {
pr_debug ( " info: bulk IN: max pkt size: %d, addr: %d \n " ,
le16_to_cpu ( epd - > wMaxPacketSize ) ,
epd - > bEndpointAddress ) ;
card - > rx_cmd_ep = usb_endpoint_num ( epd ) ;
atomic_set ( & card - > rx_cmd_urb_pending , 0 ) ;
}
if ( usb_endpoint_dir_in ( epd ) & &
usb_endpoint_num ( epd ) = = MWIFIEX_USB_EP_DATA & &
usb_endpoint_xfer_bulk ( epd ) ) {
pr_debug ( " info: bulk IN: max pkt size: %d, addr: %d \n " ,
le16_to_cpu ( epd - > wMaxPacketSize ) ,
epd - > bEndpointAddress ) ;
card - > rx_data_ep = usb_endpoint_num ( epd ) ;
atomic_set ( & card - > rx_data_urb_pending , 0 ) ;
}
if ( usb_endpoint_dir_out ( epd ) & &
usb_endpoint_num ( epd ) = = MWIFIEX_USB_EP_DATA & &
usb_endpoint_xfer_bulk ( epd ) ) {
pr_debug ( " info: bulk OUT: max pkt size: %d, addr: %d \n " ,
le16_to_cpu ( epd - > wMaxPacketSize ) ,
epd - > bEndpointAddress ) ;
2015-09-18 06:32:16 -07:00
card - > port [ 0 ] . tx_data_ep = usb_endpoint_num ( epd ) ;
atomic_set ( & card - > port [ 0 ] . tx_data_urb_pending , 0 ) ;
}
if ( usb_endpoint_dir_out ( epd ) & &
usb_endpoint_num ( epd ) = = MWIFIEX_USB_EP_DATA_CH2 & &
usb_endpoint_xfer_bulk ( epd ) ) {
pr_debug ( " info: bulk OUT chan2: \t "
" max pkt size: %d, addr: %d \n " ,
le16_to_cpu ( epd - > wMaxPacketSize ) ,
epd - > bEndpointAddress ) ;
card - > port [ 1 ] . tx_data_ep = usb_endpoint_num ( epd ) ;
atomic_set ( & card - > port [ 1 ] . tx_data_urb_pending , 0 ) ;
2012-04-18 20:08:28 -07:00
}
if ( usb_endpoint_dir_out ( epd ) & &
usb_endpoint_num ( epd ) = = MWIFIEX_USB_EP_CMD_EVENT & &
usb_endpoint_xfer_bulk ( epd ) ) {
pr_debug ( " info: bulk OUT: max pkt size: %d, addr: %d \n " ,
le16_to_cpu ( epd - > wMaxPacketSize ) ,
epd - > bEndpointAddress ) ;
card - > tx_cmd_ep = usb_endpoint_num ( epd ) ;
atomic_set ( & card - > tx_cmd_urb_pending , 0 ) ;
card - > bulk_out_maxpktsize =
le16_to_cpu ( epd - > wMaxPacketSize ) ;
}
}
usb_set_intfdata ( intf , card ) ;
ret = mwifiex_add_card ( card , & add_remove_card_sem , & usb_ops ,
MWIFIEX_USB ) ;
if ( ret ) {
pr_err ( " %s: mwifiex_add_card failed: %d \n " , __func__ , ret ) ;
usb_reset_device ( udev ) ;
kfree ( card ) ;
return ret ;
}
usb_get_dev ( udev ) ;
return 0 ;
}
/* Kernel needs to suspend all functions separately. Therefore all
* registered functions must have drivers with suspend and resume
* methods . Failing that the kernel simply removes the whole card .
*
* If already not suspended , this function allocates and sends a
* ' host sleep activate ' request to the firmware and turns off the traffic .
*/
static int mwifiex_usb_suspend ( struct usb_interface * intf , pm_message_t message )
{
struct usb_card_rec * card = usb_get_intfdata ( intf ) ;
struct mwifiex_adapter * adapter ;
2015-09-18 06:32:16 -07:00
struct usb_tx_data_port * port ;
int i , j ;
2012-04-18 20:08:28 -07:00
if ( ! card | | ! card - > adapter ) {
pr_err ( " %s: card or card->adapter is NULL \n " , __func__ ) ;
return 0 ;
}
adapter = card - > adapter ;
if ( unlikely ( adapter - > is_suspended ) )
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , WARN ,
" Device already suspended \n " ) ;
2012-04-18 20:08:28 -07:00
mwifiex_enable_hs ( adapter ) ;
/* 'is_suspended' flag indicates device is suspended.
* It must be set here before the usb_kill_urb ( ) calls . Reason
* is in the complete handlers , urb - > status ( = - ENOENT ) and
* this flag is used in combination to distinguish between a
* ' suspended ' state and a ' disconnect ' one .
*/
adapter - > is_suspended = true ;
2014-03-25 19:01:20 -07:00
adapter - > hs_enabling = false ;
2012-04-18 20:08:28 -07:00
if ( atomic_read ( & card - > rx_cmd_urb_pending ) & & card - > rx_cmd . urb )
usb_kill_urb ( card - > rx_cmd . urb ) ;
if ( atomic_read ( & card - > rx_data_urb_pending ) )
for ( i = 0 ; i < MWIFIEX_RX_DATA_URB ; i + + )
if ( card - > rx_data_list [ i ] . urb )
usb_kill_urb ( card - > rx_data_list [ i ] . urb ) ;
2015-09-18 06:32:16 -07:00
for ( i = 0 ; i < MWIFIEX_TX_DATA_PORT ; i + + ) {
port = & card - > port [ i ] ;
for ( j = 0 ; j < MWIFIEX_TX_DATA_URB ; j + + ) {
if ( port - > tx_data_list [ j ] . urb )
usb_kill_urb ( port - > tx_data_list [ j ] . urb ) ;
}
}
2012-04-18 20:08:28 -07:00
if ( card - > tx_cmd . urb )
usb_kill_urb ( card - > tx_cmd . urb ) ;
return 0 ;
}
/* Kernel needs to suspend all functions separately. Therefore all
* registered functions must have drivers with suspend and resume
* methods . Failing that the kernel simply removes the whole card .
*
* If already not resumed , this function turns on the traffic and
* sends a ' host sleep cancel ' request to the firmware .
*/
static int mwifiex_usb_resume ( struct usb_interface * intf )
{
struct usb_card_rec * card = usb_get_intfdata ( intf ) ;
struct mwifiex_adapter * adapter ;
int i ;
if ( ! card | | ! card - > adapter ) {
pr_err ( " %s: card or card->adapter is NULL \n " , __func__ ) ;
return 0 ;
}
adapter = card - > adapter ;
if ( unlikely ( ! adapter - > is_suspended ) ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , WARN ,
" Device already resumed \n " ) ;
2012-04-18 20:08:28 -07:00
return 0 ;
}
/* Indicate device resumed. The netdev queue will be resumed only
* after the urbs have been re - submitted
*/
adapter - > is_suspended = false ;
if ( ! atomic_read ( & card - > rx_data_urb_pending ) )
for ( i = 0 ; i < MWIFIEX_RX_DATA_URB ; i + + )
mwifiex_usb_submit_rx_urb ( & card - > rx_data_list [ i ] ,
MWIFIEX_RX_DATA_BUF_SIZE ) ;
if ( ! atomic_read ( & card - > rx_cmd_urb_pending ) ) {
card - > rx_cmd . skb = dev_alloc_skb ( MWIFIEX_RX_CMD_BUF_SIZE ) ;
if ( card - > rx_cmd . skb )
mwifiex_usb_submit_rx_urb ( & card - > rx_cmd ,
MWIFIEX_RX_CMD_BUF_SIZE ) ;
}
/* Disable Host Sleep */
if ( adapter - > hs_activated )
mwifiex_cancel_hs ( mwifiex_get_priv ( adapter ,
MWIFIEX_BSS_ROLE_ANY ) ,
MWIFIEX_ASYNC_CMD ) ;
return 0 ;
}
static void mwifiex_usb_disconnect ( struct usb_interface * intf )
{
struct usb_card_rec * card = usb_get_intfdata ( intf ) ;
2014-04-14 15:32:54 -07:00
struct mwifiex_adapter * adapter ;
2012-04-18 20:08:28 -07:00
2014-04-14 15:32:54 -07:00
if ( ! card | | ! card - > adapter ) {
pr_err ( " %s: card or card->adapter is NULL \n " , __func__ ) ;
2012-04-18 20:08:28 -07:00
return ;
}
2014-04-14 15:32:54 -07:00
adapter = card - > adapter ;
if ( ! adapter - > priv_num )
return ;
2012-04-18 20:08:28 -07:00
2014-04-14 15:32:54 -07:00
if ( user_rmmod ) {
# ifdef CONFIG_PM
if ( adapter - > is_suspended )
mwifiex_usb_resume ( intf ) ;
# endif
mwifiex_deauthenticate_all ( adapter ) ;
2013-11-14 19:10:42 -08:00
2014-04-14 15:32:54 -07:00
mwifiex_init_shutdown_fw ( mwifiex_get_priv ( adapter ,
MWIFIEX_BSS_ROLE_ANY ) ,
MWIFIEX_FUNC_SHUTDOWN ) ;
2013-11-14 19:10:42 -08:00
}
2012-04-18 20:08:28 -07:00
2014-04-14 15:32:54 -07:00
mwifiex_usb_free ( card ) ;
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , FATAL ,
" %s: removing card \n " , __func__ ) ;
2014-04-14 15:32:54 -07:00
mwifiex_remove_card ( adapter , & add_remove_card_sem ) ;
2012-04-18 20:08:28 -07:00
usb_set_intfdata ( intf , NULL ) ;
usb_put_dev ( interface_to_usbdev ( intf ) ) ;
kfree ( card ) ;
return ;
}
static struct usb_driver mwifiex_usb_driver = {
2014-02-21 12:23:00 -08:00
. name = " mwifiex_usb " ,
2012-04-18 20:08:28 -07:00
. probe = mwifiex_usb_probe ,
. disconnect = mwifiex_usb_disconnect ,
. id_table = mwifiex_usb_table ,
. suspend = mwifiex_usb_suspend ,
. resume = mwifiex_usb_resume ,
2014-04-14 15:32:54 -07:00
. soft_unbind = 1 ,
2012-04-18 20:08:28 -07:00
} ;
static int mwifiex_usb_tx_init ( struct mwifiex_adapter * adapter )
{
struct usb_card_rec * card = ( struct usb_card_rec * ) adapter - > card ;
2015-09-18 06:32:16 -07:00
struct usb_tx_data_port * port ;
int i , j ;
2012-04-18 20:08:28 -07:00
card - > tx_cmd . adapter = adapter ;
card - > tx_cmd . ep = card - > tx_cmd_ep ;
card - > tx_cmd . urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! card - > tx_cmd . urb ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" tx_cmd.urb allocation failed \n " ) ;
2012-04-18 20:08:28 -07:00
return - ENOMEM ;
}
2015-09-18 06:32:16 -07:00
for ( i = 0 ; i < MWIFIEX_TX_DATA_PORT ; i + + ) {
port = & card - > port [ i ] ;
if ( ! port - > tx_data_ep )
continue ;
port - > tx_data_ix = 0 ;
2015-09-18 06:32:17 -07:00
if ( port - > tx_data_ep = = MWIFIEX_USB_EP_DATA )
port - > block_status = false ;
else
port - > block_status = true ;
2015-09-18 06:32:16 -07:00
for ( j = 0 ; j < MWIFIEX_TX_DATA_URB ; j + + ) {
port - > tx_data_list [ j ] . adapter = adapter ;
port - > tx_data_list [ j ] . ep = port - > tx_data_ep ;
port - > tx_data_list [ j ] . urb =
usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! port - > tx_data_list [ j ] . urb ) {
mwifiex_dbg ( adapter , ERROR ,
" urb allocation failed \n " ) ;
return - ENOMEM ;
}
2012-04-18 20:08:28 -07:00
}
}
return 0 ;
}
static int mwifiex_usb_rx_init ( struct mwifiex_adapter * adapter )
{
struct usb_card_rec * card = ( struct usb_card_rec * ) adapter - > card ;
int i ;
card - > rx_cmd . adapter = adapter ;
card - > rx_cmd . ep = card - > rx_cmd_ep ;
card - > rx_cmd . urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! card - > rx_cmd . urb ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR , " rx_cmd.urb allocation failed \n " ) ;
2012-04-18 20:08:28 -07:00
return - ENOMEM ;
}
card - > rx_cmd . skb = dev_alloc_skb ( MWIFIEX_RX_CMD_BUF_SIZE ) ;
2015-05-12 00:48:20 +05:30
if ( ! card - > rx_cmd . skb )
2012-04-18 20:08:28 -07:00
return - ENOMEM ;
if ( mwifiex_usb_submit_rx_urb ( & card - > rx_cmd , MWIFIEX_RX_CMD_BUF_SIZE ) )
return - 1 ;
for ( i = 0 ; i < MWIFIEX_RX_DATA_URB ; i + + ) {
card - > rx_data_list [ i ] . adapter = adapter ;
card - > rx_data_list [ i ] . ep = card - > rx_data_ep ;
card - > rx_data_list [ i ] . urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! card - > rx_data_list [ i ] . urb ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" rx_data_list[] urb allocation failed \n " ) ;
2012-04-18 20:08:28 -07:00
return - 1 ;
}
if ( mwifiex_usb_submit_rx_urb ( & card - > rx_data_list [ i ] ,
MWIFIEX_RX_DATA_BUF_SIZE ) )
return - 1 ;
}
return 0 ;
}
static int mwifiex_write_data_sync ( struct mwifiex_adapter * adapter , u8 * pbuf ,
u32 * len , u8 ep , u32 timeout )
{
struct usb_card_rec * card = adapter - > card ;
int actual_length , ret ;
if ( ! ( * len % card - > bulk_out_maxpktsize ) )
( * len ) + + ;
/* Send the data block */
ret = usb_bulk_msg ( card - > udev , usb_sndbulkpipe ( card - > udev , ep ) , pbuf ,
* len , & actual_length , timeout ) ;
if ( ret ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" usb_bulk_msg for tx failed: %d \n " , ret ) ;
2013-01-25 18:23:00 -08:00
return ret ;
2012-04-18 20:08:28 -07:00
}
* len = actual_length ;
return ret ;
}
static int mwifiex_read_data_sync ( struct mwifiex_adapter * adapter , u8 * pbuf ,
u32 * len , u8 ep , u32 timeout )
{
struct usb_card_rec * card = adapter - > card ;
int actual_length , ret ;
/* Receive the data response */
ret = usb_bulk_msg ( card - > udev , usb_rcvbulkpipe ( card - > udev , ep ) , pbuf ,
* len , & actual_length , timeout ) ;
if ( ret ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" usb_bulk_msg for rx failed: %d \n " , ret ) ;
2013-01-25 18:23:00 -08:00
return ret ;
2012-04-18 20:08:28 -07:00
}
* len = actual_length ;
return ret ;
}
2015-09-18 06:32:17 -07:00
static void mwifiex_usb_port_resync ( struct mwifiex_adapter * adapter )
{
struct usb_card_rec * card = adapter - > card ;
u8 active_port = MWIFIEX_USB_EP_DATA ;
struct mwifiex_private * priv = NULL ;
int i ;
if ( adapter - > usb_mc_status ) {
for ( i = 0 ; i < adapter - > priv_num ; i + + ) {
priv = adapter - > priv [ i ] ;
if ( ! priv )
continue ;
if ( ( priv - > bss_role = = MWIFIEX_BSS_ROLE_UAP & &
! priv - > bss_started ) | |
( priv - > bss_role = = MWIFIEX_BSS_ROLE_STA & &
! priv - > media_connected ) )
priv - > usb_port = MWIFIEX_USB_EP_DATA ;
}
for ( i = 0 ; i < MWIFIEX_TX_DATA_PORT ; i + + )
card - > port [ i ] . block_status = false ;
} else {
for ( i = 0 ; i < adapter - > priv_num ; i + + ) {
priv = adapter - > priv [ i ] ;
if ( ! priv )
continue ;
if ( ( priv - > bss_role = = MWIFIEX_BSS_ROLE_UAP & &
priv - > bss_started ) | |
( priv - > bss_role = = MWIFIEX_BSS_ROLE_STA & &
priv - > media_connected ) ) {
active_port = priv - > usb_port ;
break ;
}
}
for ( i = 0 ; i < adapter - > priv_num ; i + + ) {
priv = adapter - > priv [ i ] ;
if ( priv )
priv - > usb_port = active_port ;
}
for ( i = 0 ; i < MWIFIEX_TX_DATA_PORT ; i + + ) {
if ( active_port = = card - > port [ i ] . tx_data_ep )
card - > port [ i ] . block_status = false ;
else
card - > port [ i ] . block_status = true ;
}
}
}
2015-09-18 06:32:18 -07:00
static bool mwifiex_usb_is_port_ready ( struct mwifiex_private * priv )
{
struct usb_card_rec * card = priv - > adapter - > card ;
int idx ;
for ( idx = 0 ; idx < MWIFIEX_TX_DATA_PORT ; idx + + ) {
if ( priv - > usb_port = = card - > port [ idx ] . tx_data_ep )
return ! card - > port [ idx ] . block_status ;
}
return false ;
}
static inline u8 mwifiex_usb_data_sent ( struct mwifiex_adapter * adapter )
{
struct usb_card_rec * card = adapter - > card ;
int i ;
for ( i = 0 ; i < MWIFIEX_TX_DATA_PORT ; i + + )
if ( ! card - > port [ i ] . block_status )
return false ;
return true ;
}
2012-04-18 20:08:28 -07:00
/* This function write a command/data packet to card. */
static int mwifiex_usb_host_to_card ( struct mwifiex_adapter * adapter , u8 ep ,
struct sk_buff * skb ,
struct mwifiex_tx_param * tx_param )
{
struct usb_card_rec * card = adapter - > card ;
2015-09-18 06:32:16 -07:00
struct urb_context * context = NULL ;
struct usb_tx_data_port * port = NULL ;
2012-04-18 20:08:28 -07:00
u8 * data = ( u8 * ) skb - > data ;
struct urb * tx_urb ;
2015-09-18 06:32:18 -07:00
int idx , ret ;
2012-04-18 20:08:28 -07:00
if ( adapter - > is_suspended ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" %s: not allowed while suspended \n " , __func__ ) ;
2012-04-18 20:08:28 -07:00
return - 1 ;
}
if ( adapter - > surprise_removed ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR , " %s: device removed \n " , __func__ ) ;
2012-04-18 20:08:28 -07:00
return - 1 ;
}
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , INFO , " %s: ep=%d \n " , __func__ , ep ) ;
2012-04-18 20:08:28 -07:00
if ( ep = = card - > tx_cmd_ep ) {
context = & card - > tx_cmd ;
} else {
2015-09-18 06:32:16 -07:00
for ( idx = 0 ; idx < MWIFIEX_TX_DATA_PORT ; idx + + ) {
if ( ep = = card - > port [ idx ] . tx_data_ep ) {
port = & card - > port [ idx ] ;
if ( atomic_read ( & port - > tx_data_urb_pending )
> = MWIFIEX_TX_DATA_URB ) {
2015-09-18 06:32:18 -07:00
port - > block_status = true ;
ret = - EBUSY ;
goto done ;
2015-09-18 06:32:16 -07:00
}
if ( port - > tx_data_ix > = MWIFIEX_TX_DATA_URB )
port - > tx_data_ix = 0 ;
context =
& port - > tx_data_list [ port - > tx_data_ix + + ] ;
break ;
}
}
if ( ! port ) {
mwifiex_dbg ( adapter , ERROR , " Wrong usb tx data port \n " ) ;
return - 1 ;
}
2012-04-18 20:08:28 -07:00
}
context - > adapter = adapter ;
context - > ep = ep ;
context - > skb = skb ;
tx_urb = context - > urb ;
usb_fill_bulk_urb ( tx_urb , card - > udev , usb_sndbulkpipe ( card - > udev , ep ) ,
data , skb - > len , mwifiex_usb_tx_complete ,
( void * ) context ) ;
tx_urb - > transfer_flags | = URB_ZERO_PACKET ;
if ( ep = = card - > tx_cmd_ep )
atomic_inc ( & card - > tx_cmd_urb_pending ) ;
else
2015-09-18 06:32:16 -07:00
atomic_inc ( & port - > tx_data_urb_pending ) ;
2012-04-18 20:08:28 -07:00
if ( usb_submit_urb ( tx_urb , GFP_ATOMIC ) ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" %s: usb_submit_urb failed \n " , __func__ ) ;
2012-04-18 20:08:28 -07:00
if ( ep = = card - > tx_cmd_ep ) {
atomic_dec ( & card - > tx_cmd_urb_pending ) ;
} else {
2015-09-18 06:32:16 -07:00
atomic_dec ( & port - > tx_data_urb_pending ) ;
2015-09-18 06:32:18 -07:00
port - > block_status = false ;
2015-09-18 06:32:16 -07:00
if ( port - > tx_data_ix )
port - > tx_data_ix - - ;
2012-04-18 20:08:28 -07:00
else
2015-09-18 06:32:16 -07:00
port - > tx_data_ix = MWIFIEX_TX_DATA_URB ;
2012-04-18 20:08:28 -07:00
}
return - 1 ;
} else {
2015-09-18 06:32:16 -07:00
if ( ep ! = card - > tx_cmd_ep & &
atomic_read ( & port - > tx_data_urb_pending ) = =
2015-09-18 06:32:14 -07:00
MWIFIEX_TX_DATA_URB ) {
2015-09-18 06:32:18 -07:00
port - > block_status = true ;
ret = - ENOSR ;
goto done ;
2015-09-18 06:32:14 -07:00
}
2012-04-18 20:08:28 -07:00
}
return - EINPROGRESS ;
2015-09-18 06:32:18 -07:00
done :
if ( ep ! = card - > tx_cmd_ep )
adapter - > data_sent = mwifiex_usb_data_sent ( adapter ) ;
return ret ;
2012-04-18 20:08:28 -07:00
}
/* This function register usb device and initialize parameter. */
static int mwifiex_register_dev ( struct mwifiex_adapter * adapter )
{
struct usb_card_rec * card = ( struct usb_card_rec * ) adapter - > card ;
card - > adapter = adapter ;
adapter - > dev = & card - > udev - > dev ;
2014-01-09 19:36:55 -08:00
switch ( le16_to_cpu ( card - > udev - > descriptor . idProduct ) ) {
2015-08-05 06:09:40 -07:00
case USB8997_PID_1 :
case USB8997_PID_2 :
adapter - > tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K ;
strcpy ( adapter - > fw_name , USB8997_DEFAULT_FW_NAME ) ;
adapter - > ext_scan = true ;
break ;
2014-11-20 16:52:58 +01:00
case USB8766_PID_1 :
case USB8766_PID_2 :
adapter - > tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K ;
strcpy ( adapter - > fw_name , USB8766_DEFAULT_FW_NAME ) ;
2015-01-23 17:09:19 +05:30
adapter - > ext_scan = true ;
2014-11-20 16:52:58 +01:00
break ;
2015-01-23 17:09:18 +05:30
case USB8801_PID_1 :
case USB8801_PID_2 :
adapter - > tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K ;
strcpy ( adapter - > fw_name , USB8801_DEFAULT_FW_NAME ) ;
2015-01-23 17:09:19 +05:30
adapter - > ext_scan = false ;
2015-01-23 17:09:18 +05:30
break ;
2014-01-09 19:36:55 -08:00
case USB8797_PID_1 :
case USB8797_PID_2 :
default :
2014-02-27 19:35:13 -08:00
adapter - > tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K ;
2014-01-09 19:36:55 -08:00
strcpy ( adapter - > fw_name , USB8797_DEFAULT_FW_NAME ) ;
break ;
}
2015-09-18 06:32:15 -07:00
adapter - > usb_mc_status = false ;
2015-09-18 06:32:17 -07:00
adapter - > usb_mc_setup = false ;
2015-09-18 06:32:15 -07:00
2012-04-18 20:08:28 -07:00
return 0 ;
}
2013-07-22 19:17:51 -07:00
static void mwifiex_unregister_dev ( struct mwifiex_adapter * adapter )
{
struct usb_card_rec * card = ( struct usb_card_rec * ) adapter - > card ;
2013-11-14 19:10:42 -08:00
card - > adapter = NULL ;
2013-07-22 19:17:51 -07:00
}
2012-04-18 20:08:28 -07:00
static int mwifiex_prog_fw_w_helper ( struct mwifiex_adapter * adapter ,
struct mwifiex_fw_image * fw )
{
int ret = 0 ;
u8 * firmware = fw - > fw_buf , * recv_buff ;
2014-01-09 19:36:55 -08:00
u32 retries = USB8XXX_FW_MAX_RETRY , dlen ;
2012-04-18 20:08:28 -07:00
u32 fw_seqnum = 0 , tlen = 0 , dnld_cmd = 0 ;
struct fw_data * fwdata ;
struct fw_sync_header sync_fw ;
u8 check_winner = 1 ;
if ( ! firmware ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" No firmware image found! Terminating download \n " ) ;
2012-04-18 20:08:28 -07:00
ret = - 1 ;
goto fw_exit ;
}
/* Allocate memory for transmit */
fwdata = kzalloc ( FW_DNLD_TX_BUF_SIZE , GFP_KERNEL ) ;
2015-08-04 10:49:27 +03:00
if ( ! fwdata ) {
ret = - ENOMEM ;
2012-04-18 20:08:28 -07:00
goto fw_exit ;
2015-08-04 10:49:27 +03:00
}
2012-04-18 20:08:28 -07:00
/* Allocate memory for receive */
recv_buff = kzalloc ( FW_DNLD_RX_BUF_SIZE , GFP_KERNEL ) ;
if ( ! recv_buff )
goto cleanup ;
do {
/* Send pseudo data to check winner status first */
if ( check_winner ) {
memset ( & fwdata - > fw_hdr , 0 , sizeof ( struct fw_header ) ) ;
dlen = 0 ;
} else {
/* copy the header of the fw_data to get the length */
2013-01-02 16:23:01 -08:00
memcpy ( & fwdata - > fw_hdr , & firmware [ tlen ] ,
sizeof ( struct fw_header ) ) ;
2012-04-18 20:08:28 -07:00
dlen = le32_to_cpu ( fwdata - > fw_hdr . data_len ) ;
dnld_cmd = le32_to_cpu ( fwdata - > fw_hdr . dnld_cmd ) ;
tlen + = sizeof ( struct fw_header ) ;
2013-01-02 16:23:01 -08:00
memcpy ( fwdata - > data , & firmware [ tlen ] , dlen ) ;
2012-04-18 20:08:28 -07:00
fwdata - > seq_num = cpu_to_le32 ( fw_seqnum ) ;
tlen + = dlen ;
}
/* If the send/receive fails or CRC occurs then retry */
while ( retries - - ) {
u8 * buf = ( u8 * ) fwdata ;
u32 len = FW_DATA_XMIT_SIZE ;
/* send the firmware block */
ret = mwifiex_write_data_sync ( adapter , buf , & len ,
MWIFIEX_USB_EP_CMD_EVENT ,
MWIFIEX_USB_TIMEOUT ) ;
if ( ret ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" write_data_sync: failed: %d \n " ,
ret ) ;
2012-04-18 20:08:28 -07:00
continue ;
}
buf = recv_buff ;
len = FW_DNLD_RX_BUF_SIZE ;
/* Receive the firmware block response */
ret = mwifiex_read_data_sync ( adapter , buf , & len ,
MWIFIEX_USB_EP_CMD_EVENT ,
MWIFIEX_USB_TIMEOUT ) ;
if ( ret ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" read_data_sync: failed: %d \n " ,
ret ) ;
2012-04-18 20:08:28 -07:00
continue ;
}
memcpy ( & sync_fw , recv_buff ,
sizeof ( struct fw_sync_header ) ) ;
/* check 1st firmware block resp for highest bit set */
if ( check_winner ) {
if ( le32_to_cpu ( sync_fw . cmd ) & 0x80000000 ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , WARN ,
" USB is not the winner %#x \n " ,
sync_fw . cmd ) ;
2012-04-18 20:08:28 -07:00
/* returning success */
ret = 0 ;
goto cleanup ;
}
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , MSG ,
" start to download FW... \n " ) ;
2012-04-18 20:08:28 -07:00
check_winner = 0 ;
break ;
}
/* check the firmware block response for CRC errors */
if ( sync_fw . cmd ) {
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , ERROR ,
" FW received block with CRC %#x \n " ,
sync_fw . cmd ) ;
2012-04-18 20:08:28 -07:00
ret = - 1 ;
continue ;
}
2014-01-09 19:36:55 -08:00
retries = USB8XXX_FW_MAX_RETRY ;
2012-04-18 20:08:28 -07:00
break ;
}
fw_seqnum + + ;
} while ( ( dnld_cmd ! = FW_HAS_LAST_BLOCK ) & & retries ) ;
cleanup :
2015-05-12 00:48:20 +05:30
mwifiex_dbg ( adapter , MSG ,
" info: FW download over, size %d bytes \n " , tlen ) ;
2012-04-18 20:08:28 -07:00
kfree ( recv_buff ) ;
kfree ( fwdata ) ;
if ( retries )
ret = 0 ;
fw_exit :
return ret ;
}
static int mwifiex_usb_dnld_fw ( struct mwifiex_adapter * adapter ,
struct mwifiex_fw_image * fw )
{
int ret ;
struct usb_card_rec * card = ( struct usb_card_rec * ) adapter - > card ;
2014-01-09 19:36:55 -08:00
if ( card - > usb_boot_state = = USB8XXX_FW_DNLD ) {
2012-04-18 20:08:28 -07:00
ret = mwifiex_prog_fw_w_helper ( adapter , fw ) ;
if ( ret )
return - 1 ;
/* Boot state changes after successful firmware download */
2014-01-09 19:36:55 -08:00
if ( card - > usb_boot_state = = USB8XXX_FW_DNLD )
2012-04-18 20:08:28 -07:00
return - 1 ;
}
ret = mwifiex_usb_rx_init ( adapter ) ;
if ( ! ret )
ret = mwifiex_usb_tx_init ( adapter ) ;
return ret ;
}
static void mwifiex_submit_rx_urb ( struct mwifiex_adapter * adapter , u8 ep )
{
struct usb_card_rec * card = ( struct usb_card_rec * ) adapter - > card ;
skb_push ( card - > rx_cmd . skb , INTF_HEADER_LEN ) ;
if ( ( ep = = card - > rx_cmd_ep ) & &
( ! atomic_read ( & card - > rx_cmd_urb_pending ) ) )
mwifiex_usb_submit_rx_urb ( & card - > rx_cmd ,
MWIFIEX_RX_CMD_BUF_SIZE ) ;
return ;
}
static int mwifiex_usb_cmd_event_complete ( struct mwifiex_adapter * adapter ,
struct sk_buff * skb )
{
mwifiex_submit_rx_urb ( adapter , MWIFIEX_USB_EP_CMD_EVENT ) ;
return 0 ;
}
/* This function wakes up the card. */
static int mwifiex_pm_wakeup_card ( struct mwifiex_adapter * adapter )
{
/* Simulation of HS_AWAKE event */
adapter - > pm_wakeup_fw_try = false ;
2015-03-12 00:38:40 -07:00
del_timer ( & adapter - > wakeup_timer ) ;
2012-04-18 20:08:28 -07:00
adapter - > pm_wakeup_card_req = false ;
adapter - > ps_state = PS_STATE_AWAKE ;
return 0 ;
}
2014-11-05 17:04:29 +05:30
static void mwifiex_usb_submit_rem_rx_urbs ( struct mwifiex_adapter * adapter )
{
struct usb_card_rec * card = ( struct usb_card_rec * ) adapter - > card ;
int i ;
struct urb_context * ctx ;
for ( i = 0 ; i < MWIFIEX_RX_DATA_URB ; i + + ) {
if ( card - > rx_data_list [ i ] . skb )
continue ;
ctx = & card - > rx_data_list [ i ] ;
mwifiex_usb_submit_rx_urb ( ctx , MWIFIEX_RX_DATA_BUF_SIZE ) ;
}
}
2014-12-23 19:14:08 +05:30
/* This function is called after the card has woken up. */
static inline int
mwifiex_pm_wakeup_card_complete ( struct mwifiex_adapter * adapter )
{
return 0 ;
}
2012-04-18 20:08:28 -07:00
static struct mwifiex_if_ops usb_ops = {
. register_dev = mwifiex_register_dev ,
2013-07-22 19:17:51 -07:00
. unregister_dev = mwifiex_unregister_dev ,
2012-04-18 20:08:28 -07:00
. wakeup = mwifiex_pm_wakeup_card ,
. wakeup_complete = mwifiex_pm_wakeup_card_complete ,
/* USB specific */
. dnld_fw = mwifiex_usb_dnld_fw ,
. cmdrsp_complete = mwifiex_usb_cmd_event_complete ,
. event_complete = mwifiex_usb_cmd_event_complete ,
. host_to_card = mwifiex_usb_host_to_card ,
2014-11-05 17:04:29 +05:30
. submit_rem_rx_urbs = mwifiex_usb_submit_rem_rx_urbs ,
2015-09-18 06:32:17 -07:00
. multi_port_resync = mwifiex_usb_port_resync ,
2015-09-18 06:32:18 -07:00
. is_port_ready = mwifiex_usb_is_port_ready ,
2012-04-18 20:08:28 -07:00
} ;
/* This function initializes the USB driver module.
*
* This initiates the semaphore and registers the device with
* USB bus .
*/
static int mwifiex_usb_init_module ( void )
{
int ret ;
pr_debug ( " Marvell USB8797 Driver \n " ) ;
sema_init ( & add_remove_card_sem , 1 ) ;
ret = usb_register ( & mwifiex_usb_driver ) ;
if ( ret )
pr_err ( " Driver register failed! \n " ) ;
else
pr_debug ( " info: Driver registered successfully! \n " ) ;
return ret ;
}
/* This function cleans up the USB driver.
*
* The following major steps are followed in . disconnect for cleanup :
* - Resume the device if its suspended
* - Disconnect the device if connected
* - Shutdown the firmware
* - Unregister the device from USB bus .
*/
static void mwifiex_usb_cleanup_module ( void )
{
if ( ! down_interruptible ( & add_remove_card_sem ) )
up ( & add_remove_card_sem ) ;
2014-04-14 15:32:54 -07:00
/* set the flag as user is removing this module */
user_rmmod = 1 ;
2012-04-18 20:08:28 -07:00
usb_deregister ( & mwifiex_usb_driver ) ;
}
module_init ( mwifiex_usb_init_module ) ;
module_exit ( mwifiex_usb_cleanup_module ) ;
MODULE_AUTHOR ( " Marvell International Ltd. " ) ;
MODULE_DESCRIPTION ( " Marvell WiFi-Ex USB Driver version " USB_VERSION ) ;
MODULE_VERSION ( USB_VERSION ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2014-11-20 16:52:58 +01:00
MODULE_FIRMWARE ( USB8766_DEFAULT_FW_NAME ) ;
2014-01-09 19:36:55 -08:00
MODULE_FIRMWARE ( USB8797_DEFAULT_FW_NAME ) ;
2015-01-23 17:09:18 +05:30
MODULE_FIRMWARE ( USB8801_DEFAULT_FW_NAME ) ;
2015-08-05 06:09:40 -07:00
MODULE_FIRMWARE ( USB8997_DEFAULT_FW_NAME ) ;