2007-02-10 17:25:27 +03:00
/**
* This file contains functions used in USB interface module .
*/
# include <linux/delay.h>
2007-05-25 20:37:58 +04:00
# include <linux/moduleparam.h>
2007-02-10 17:25:27 +03:00
# include <linux/firmware.h>
# include <linux/netdevice.h>
# include <linux/usb.h>
2007-05-25 20:49:10 +04:00
# define DRV_NAME "usb8xxx"
2007-02-10 17:25:27 +03:00
# include "host.h"
# include "decl.h"
# include "defs.h"
# include "dev.h"
# include "if_usb.h"
# define MESSAGE_HEADER_LEN 4
2007-11-21 01:43:32 +03:00
static char * lbs_fw_name = " usb8388.bin " ;
2007-11-16 02:05:47 +03:00
module_param_named ( fw_name , lbs_fw_name , charp , 0644 ) ;
2007-05-25 20:37:58 +04:00
2007-02-10 17:25:27 +03:00
static struct usb_device_id if_usb_table [ ] = {
/* Enter the device signature inside */
2007-05-25 08:11:58 +04:00
{ USB_DEVICE ( 0x1286 , 0x2001 ) } ,
{ USB_DEVICE ( 0x05a3 , 0x8388 ) } ,
2007-02-10 17:25:27 +03:00
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , if_usb_table ) ;
static void if_usb_receive ( struct urb * urb ) ;
static void if_usb_receive_fwload ( struct urb * urb ) ;
2007-08-20 19:43:25 +04:00
static int if_usb_prog_firmware ( struct usb_card_rec * cardp ) ;
2007-11-23 17:43:44 +03:00
static int if_usb_host_to_card ( struct lbs_private * priv ,
u8 type ,
u8 * payload ,
u16 nb ) ;
static int if_usb_get_int_status ( struct lbs_private * priv , u8 * ) ;
static int if_usb_read_event_cause ( struct lbs_private * ) ;
2007-08-20 19:43:25 +04:00
static int usb_tx_block ( struct usb_card_rec * cardp , u8 * payload , u16 nb ) ;
2007-08-02 19:49:06 +04:00
static void if_usb_free ( struct usb_card_rec * cardp ) ;
2007-08-20 19:43:25 +04:00
static int if_usb_submit_rx_urb ( struct usb_card_rec * cardp ) ;
static int if_usb_reset_device ( struct usb_card_rec * cardp ) ;
2007-02-10 17:25:27 +03:00
/**
* @ brief call back function to handle the status of the URB
* @ param urb pointer to urb structure
* @ return N / A
*/
static void if_usb_write_bulk_callback ( struct urb * urb )
{
2007-08-20 19:43:25 +04:00
struct usb_card_rec * cardp = ( struct usb_card_rec * ) urb - > context ;
2007-02-10 17:25:27 +03:00
/* handle the transmission complete validations */
2007-08-20 19:43:25 +04:00
if ( urb - > status = = 0 ) {
2007-11-23 17:43:44 +03:00
struct lbs_private * priv = cardp - > priv ;
2007-08-20 19:43:25 +04:00
2007-05-25 19:27:16 +04:00
/*
lbs_deb_usbd ( & urb - > dev - > dev , " URB status is successfull \n " ) ;
lbs_deb_usbd ( & urb - > dev - > dev , " Actual length transmitted %d \n " ,
2007-02-10 17:25:27 +03:00
urb - > actual_length ) ;
2007-05-25 19:27:16 +04:00
*/
2007-08-20 19:43:25 +04:00
/* Used for both firmware TX and regular TX. priv isn't
* valid at firmware load time .
*/
if ( priv ) {
2007-11-23 17:43:44 +03:00
struct lbs_adapter * adapter = priv - > adapter ;
2007-08-20 19:43:25 +04:00
struct net_device * dev = priv - > dev ;
priv - > dnld_sent = DNLD_RES_RECEIVED ;
/* Wake main thread if commands are pending */
if ( ! adapter - > cur_cmd )
wake_up_interruptible ( & priv - > waitq ) ;
2007-11-21 01:44:14 +03:00
if ( adapter - > connect_status = = LBS_CONNECTED )
2007-08-20 19:43:25 +04:00
netif_wake_queue ( dev ) ;
2007-11-21 01:44:14 +03:00
if ( priv - > mesh_dev & & ( adapter - > mesh_connect_status = = LBS_CONNECTED ) )
2007-08-20 19:43:25 +04:00
netif_wake_queue ( priv - > mesh_dev ) ;
2007-05-25 20:06:56 +04:00
}
2007-08-20 19:43:25 +04:00
} else {
/* print the failure status number for debug */
lbs_pr_info ( " URB in failure status: %d \n " , urb - > status ) ;
2007-02-10 17:25:27 +03:00
}
return ;
}
/**
* @ brief free tx / rx urb , skb and rx buffer
* @ param cardp pointer usb_card_rec
* @ return N / A
*/
2007-08-02 19:49:06 +04:00
static void if_usb_free ( struct usb_card_rec * cardp )
2007-02-10 17:25:27 +03:00
{
2007-05-25 19:27:16 +04:00
lbs_deb_enter ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
/* Unlink tx & rx urb */
usb_kill_urb ( cardp - > tx_urb ) ;
usb_kill_urb ( cardp - > rx_urb ) ;
usb_free_urb ( cardp - > tx_urb ) ;
cardp - > tx_urb = NULL ;
usb_free_urb ( cardp - > rx_urb ) ;
cardp - > rx_urb = NULL ;
kfree ( cardp - > bulk_out_buffer ) ;
cardp - > bulk_out_buffer = NULL ;
2007-05-25 19:27:16 +04:00
lbs_deb_leave ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
}
/**
* @ brief sets the configuration values
* @ param ifnum interface number
* @ param id pointer to usb_device_id
* @ return 0 on success , error code on failure
*/
static int if_usb_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct usb_device * udev ;
struct usb_host_interface * iface_desc ;
struct usb_endpoint_descriptor * endpoint ;
2007-11-23 17:43:44 +03:00
struct lbs_private * priv ;
2007-05-25 20:41:52 +04:00
struct usb_card_rec * cardp ;
2007-02-10 17:25:27 +03:00
int i ;
udev = interface_to_usbdev ( intf ) ;
2007-05-25 20:41:52 +04:00
cardp = kzalloc ( sizeof ( struct usb_card_rec ) , GFP_KERNEL ) ;
if ( ! cardp ) {
2007-02-10 17:25:27 +03:00
lbs_pr_err ( " Out of memory allocating private data. \n " ) ;
goto error ;
}
2007-05-25 20:41:52 +04:00
cardp - > udev = udev ;
2007-02-10 17:25:27 +03:00
iface_desc = intf - > cur_altsetting ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & udev - > dev , " bcdUSB = 0x%X bDeviceClass = 0x%X "
2007-02-10 17:25:27 +03:00
" bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X \n " ,
2007-05-26 07:36:54 +04:00
le16_to_cpu ( udev - > descriptor . bcdUSB ) ,
udev - > descriptor . bDeviceClass ,
udev - > descriptor . bDeviceSubClass ,
udev - > descriptor . bDeviceProtocol ) ;
2007-02-10 17:25:27 +03:00
for ( i = 0 ; i < iface_desc - > desc . bNumEndpoints ; + + i ) {
endpoint = & iface_desc - > endpoint [ i ] . desc ;
if ( ( endpoint - > bEndpointAddress & USB_ENDPOINT_DIR_MASK )
& & ( ( endpoint - > bmAttributes & USB_ENDPOINT_XFERTYPE_MASK ) = =
USB_ENDPOINT_XFER_BULK ) ) {
/* we found a bulk in endpoint */
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & udev - > dev , " Bulk in size is %d \n " ,
2007-05-26 07:36:54 +04:00
le16_to_cpu ( endpoint - > wMaxPacketSize ) ) ;
if ( ! ( cardp - > rx_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ) ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & udev - > dev ,
2007-02-10 17:25:27 +03:00
" Rx URB allocation failed \n " ) ;
goto dealloc ;
}
2007-05-25 20:41:52 +04:00
cardp - > rx_urb_recall = 0 ;
2007-02-10 17:25:27 +03:00
2007-05-25 20:41:52 +04:00
cardp - > bulk_in_size =
2007-05-26 07:36:54 +04:00
le16_to_cpu ( endpoint - > wMaxPacketSize ) ;
2007-05-25 20:41:52 +04:00
cardp - > bulk_in_endpointAddr =
2007-02-10 17:25:27 +03:00
( endpoint - >
bEndpointAddress & USB_ENDPOINT_NUMBER_MASK ) ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & udev - > dev , " in_endpoint = %d \n " ,
2007-02-10 17:25:27 +03:00
endpoint - > bEndpointAddress ) ;
}
if ( ( ( endpoint - >
bEndpointAddress & USB_ENDPOINT_DIR_MASK ) = =
USB_DIR_OUT )
& & ( ( endpoint - > bmAttributes & USB_ENDPOINT_XFERTYPE_MASK ) = =
USB_ENDPOINT_XFER_BULK ) ) {
/* We found bulk out endpoint */
2007-05-26 07:36:54 +04:00
if ( ! ( cardp - > tx_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ) ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & udev - > dev ,
2007-02-10 17:25:27 +03:00
" Tx URB allocation failed \n " ) ;
goto dealloc ;
}
2007-05-25 20:41:52 +04:00
cardp - > bulk_out_size =
2007-05-26 07:36:54 +04:00
le16_to_cpu ( endpoint - > wMaxPacketSize ) ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & udev - > dev ,
2007-05-26 07:36:54 +04:00
" Bulk out size is %d \n " ,
le16_to_cpu ( endpoint - > wMaxPacketSize ) ) ;
2007-05-25 20:41:52 +04:00
cardp - > bulk_out_endpointAddr =
2007-02-10 17:25:27 +03:00
endpoint - > bEndpointAddress ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & udev - > dev , " out_endpoint = %d \n " ,
2007-02-10 17:25:27 +03:00
endpoint - > bEndpointAddress ) ;
2007-05-25 20:41:52 +04:00
cardp - > bulk_out_buffer =
2007-02-10 17:25:27 +03:00
kmalloc ( MRVDRV_ETH_TX_PACKET_BUFFER_SIZE ,
GFP_KERNEL ) ;
2007-05-25 20:41:52 +04:00
if ( ! cardp - > bulk_out_buffer ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & udev - > dev ,
2007-02-10 17:25:27 +03:00
" Could not allocate buffer \n " ) ;
goto dealloc ;
}
}
}
2007-08-20 19:43:25 +04:00
/* Upload firmware */
cardp - > rinfo . cardp = cardp ;
if ( if_usb_prog_firmware ( cardp ) ) {
lbs_deb_usbd ( & udev - > dev , " FW upload failed " ) ;
goto err_prog_firmware ;
}
2007-11-16 02:05:47 +03:00
if ( ! ( priv = lbs_add_card ( cardp , & udev - > dev ) ) )
2007-08-20 19:43:25 +04:00
goto err_prog_firmware ;
2007-05-25 20:01:42 +04:00
2007-08-20 19:43:25 +04:00
cardp - > priv = priv ;
2007-08-02 21:16:55 +04:00
2007-11-16 02:05:47 +03:00
if ( lbs_add_mesh ( priv , & udev - > dev ) )
2007-05-25 20:09:13 +04:00
goto err_add_mesh ;
2007-05-25 20:06:56 +04:00
2007-08-20 19:43:25 +04:00
cardp - > eth_dev = priv - > dev ;
2007-05-25 20:17:06 +04:00
priv - > hw_host_to_card = if_usb_host_to_card ;
priv - > hw_get_int_status = if_usb_get_int_status ;
priv - > hw_read_event_cause = if_usb_read_event_cause ;
2007-08-02 21:19:24 +04:00
priv - > boot2_version = udev - > descriptor . bcdDevice ;
2007-05-25 20:17:06 +04:00
2007-08-20 19:43:25 +04:00
/* Delay 200 ms to waiting for the FW ready */
if_usb_submit_rx_urb ( cardp ) ;
msleep_interruptible ( 200 ) ;
priv - > adapter - > fw_ready = 1 ;
2007-11-16 02:05:47 +03:00
if ( lbs_start_card ( priv ) )
2007-08-20 19:43:25 +04:00
goto err_start_card ;
2007-05-25 20:04:31 +04:00
2007-02-10 17:25:27 +03:00
usb_get_dev ( udev ) ;
2007-05-25 20:41:52 +04:00
usb_set_intfdata ( intf , cardp ) ;
2007-02-10 17:25:27 +03:00
return 0 ;
2007-08-20 19:43:25 +04:00
err_start_card :
2007-11-16 02:05:47 +03:00
lbs_remove_mesh ( priv ) ;
2007-05-25 20:09:13 +04:00
err_add_mesh :
2007-11-16 02:05:47 +03:00
lbs_remove_card ( priv ) ;
2007-08-20 19:43:25 +04:00
err_prog_firmware :
if_usb_reset_device ( cardp ) ;
2007-02-10 17:25:27 +03:00
dealloc :
2007-05-25 20:41:52 +04:00
if_usb_free ( cardp ) ;
2007-02-10 17:25:27 +03:00
error :
return - ENOMEM ;
}
/**
* @ brief free resource and cleanup
2007-05-25 20:41:52 +04:00
* @ param intf USB interface structure
2007-02-10 17:25:27 +03:00
* @ return N / A
*/
static void if_usb_disconnect ( struct usb_interface * intf )
{
struct usb_card_rec * cardp = usb_get_intfdata ( intf ) ;
2007-11-23 17:43:44 +03:00
struct lbs_private * priv = ( struct lbs_private * ) cardp - > priv ;
2007-02-10 17:25:27 +03:00
2007-08-20 19:43:25 +04:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-02-10 17:25:27 +03:00
2007-08-20 19:43:25 +04:00
/* Update Surprise removed to TRUE */
cardp - > surprise_removed = 1 ;
2007-02-10 17:25:27 +03:00
2007-08-20 19:43:25 +04:00
if ( priv ) {
2007-11-23 17:43:44 +03:00
struct lbs_adapter * adapter = priv - > adapter ;
2007-08-20 19:43:25 +04:00
adapter - > surpriseremoved = 1 ;
2007-11-16 02:05:47 +03:00
lbs_stop_card ( priv ) ;
lbs_remove_mesh ( priv ) ;
lbs_remove_card ( priv ) ;
2007-08-20 19:43:25 +04:00
}
2007-02-10 17:25:27 +03:00
2007-11-21 01:43:55 +03:00
/* this is (apparently?) necessary for future usage of the device */
lbs_prepare_and_send_command ( priv , CMD_802_11_RESET , CMD_ACT_HALT ,
0 , 0 , NULL ) ;
2007-02-10 17:25:27 +03:00
/* Unlink and free urb */
if_usb_free ( cardp ) ;
usb_set_intfdata ( intf , NULL ) ;
usb_put_dev ( interface_to_usbdev ( intf ) ) ;
2007-08-20 19:43:25 +04:00
lbs_deb_leave ( LBS_DEB_MAIN ) ;
2007-02-10 17:25:27 +03:00
}
/**
* @ brief This function download FW
2007-11-23 17:43:44 +03:00
* @ param priv pointer to struct lbs_private
2007-02-10 17:25:27 +03:00
* @ return 0
*/
2007-08-20 19:43:25 +04:00
static int if_prog_firmware ( struct usb_card_rec * cardp )
2007-02-10 17:25:27 +03:00
{
struct FWData * fwdata ;
struct fwheader * fwheader ;
2007-08-20 19:43:25 +04:00
u8 * firmware = cardp - > fw - > data ;
2007-02-10 17:25:27 +03:00
fwdata = kmalloc ( sizeof ( struct FWData ) , GFP_ATOMIC ) ;
if ( ! fwdata )
return - 1 ;
fwheader = & fwdata - > fwheader ;
if ( ! cardp - > CRC_OK ) {
cardp - > totalbytes = cardp - > fwlastblksent ;
cardp - > fwseqnum = cardp - > lastseqnum - 1 ;
}
2007-05-25 19:27:16 +04:00
/*
lbs_deb_usbd ( & cardp - > udev - > dev , " totalbytes = %d \n " ,
2007-02-10 17:25:27 +03:00
cardp - > totalbytes ) ;
2007-05-25 19:27:16 +04:00
*/
2007-02-10 17:25:27 +03:00
memcpy ( fwheader , & firmware [ cardp - > totalbytes ] ,
sizeof ( struct fwheader ) ) ;
cardp - > fwlastblksent = cardp - > totalbytes ;
cardp - > totalbytes + = sizeof ( struct fwheader ) ;
2007-05-25 19:27:16 +04:00
/* lbs_deb_usbd(&cardp->udev->dev,"Copy Data\n"); */
2007-02-10 17:25:27 +03:00
memcpy ( fwdata - > data , & firmware [ cardp - > totalbytes ] ,
2007-05-26 07:36:54 +04:00
le32_to_cpu ( fwdata - > fwheader . datalength ) ) ;
2007-02-10 17:25:27 +03:00
2007-05-25 19:27:16 +04:00
/*
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-05-26 07:38:14 +04:00
" Data length = %d \n " , le32_to_cpu ( fwdata - > fwheader . datalength ) ) ;
2007-05-25 19:27:16 +04:00
*/
2007-02-10 17:25:27 +03:00
cardp - > fwseqnum = cardp - > fwseqnum + 1 ;
2007-05-26 07:36:54 +04:00
fwdata - > seqnum = cpu_to_le32 ( cardp - > fwseqnum ) ;
cardp - > lastseqnum = cardp - > fwseqnum ;
cardp - > totalbytes + = le32_to_cpu ( fwdata - > fwheader . datalength ) ;
2007-02-10 17:25:27 +03:00
2007-05-26 07:36:54 +04:00
if ( fwheader - > dnldcmd = = cpu_to_le32 ( FW_HAS_DATA_TO_RECV ) ) {
2007-05-25 19:27:16 +04:00
/*
2007-05-26 07:36:54 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " There are data to follow \n " ) ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" seqnum = %d totalbytes = %d \n " , cardp - > fwseqnum ,
cardp - > totalbytes ) ;
2007-05-25 19:27:16 +04:00
*/
2007-02-10 17:25:27 +03:00
memcpy ( cardp - > bulk_out_buffer , fwheader , FW_DATA_XMIT_SIZE ) ;
2007-08-20 19:43:25 +04:00
usb_tx_block ( cardp , cardp - > bulk_out_buffer , FW_DATA_XMIT_SIZE ) ;
2007-02-10 17:25:27 +03:00
2007-05-26 07:38:14 +04:00
} else if ( fwdata - > fwheader . dnldcmd = = cpu_to_le32 ( FW_HAS_LAST_BLOCK ) ) {
2007-05-25 19:27:16 +04:00
/*
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" Host has finished FW downloading \n " ) ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" Donwloading FW JUMP BLOCK \n " ) ;
2007-05-25 19:27:16 +04:00
*/
2007-02-10 17:25:27 +03:00
memcpy ( cardp - > bulk_out_buffer , fwheader , FW_DATA_XMIT_SIZE ) ;
2007-08-20 19:43:25 +04:00
usb_tx_block ( cardp , cardp - > bulk_out_buffer , FW_DATA_XMIT_SIZE ) ;
2007-02-10 17:25:27 +03:00
cardp - > fwfinalblk = 1 ;
}
2007-05-25 19:27:16 +04:00
/*
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" The firmware download is done size is %d \n " ,
cardp - > totalbytes ) ;
2007-05-25 19:27:16 +04:00
*/
2007-02-10 17:25:27 +03:00
kfree ( fwdata ) ;
return 0 ;
}
2007-08-20 19:43:25 +04:00
static int if_usb_reset_device ( struct usb_card_rec * cardp )
2007-02-10 17:25:27 +03:00
{
int ret ;
2007-11-23 17:43:44 +03:00
struct lbs_private * priv = cardp - > priv ;
2007-02-10 17:25:27 +03:00
2007-05-25 20:01:42 +04:00
lbs_deb_enter ( LBS_DEB_USB ) ;
2007-08-02 19:36:22 +04:00
/* Try a USB port reset first, if that fails send the reset
* command to the firmware .
*/
2007-02-10 17:25:27 +03:00
ret = usb_reset_device ( cardp - > udev ) ;
2007-08-20 19:43:25 +04:00
if ( ! ret & & priv ) {
2007-02-10 17:25:27 +03:00
msleep ( 10 ) ;
2007-11-16 02:05:47 +03:00
ret = lbs_reset_device ( priv ) ;
2007-02-10 17:25:27 +03:00
msleep ( 10 ) ;
}
2007-05-25 20:01:42 +04:00
lbs_deb_leave_args ( LBS_DEB_USB , " ret %d " , ret ) ;
2007-02-10 17:25:27 +03:00
return ret ;
}
/**
* @ brief This function transfer the data to the device .
2007-11-23 17:43:44 +03:00
* @ param priv pointer to struct lbs_private
2007-02-10 17:25:27 +03:00
* @ param payload pointer to payload data
* @ param nb data length
* @ return 0 or - 1
*/
2007-08-20 19:43:25 +04:00
static int usb_tx_block ( struct usb_card_rec * cardp , u8 * payload , u16 nb )
2007-02-10 17:25:27 +03:00
{
int ret = - 1 ;
/* check if device is removed */
2007-08-20 19:43:25 +04:00
if ( cardp - > surprise_removed ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " Device removed \n " ) ;
2007-02-10 17:25:27 +03:00
goto tx_ret ;
}
usb_fill_bulk_urb ( cardp - > tx_urb , cardp - > udev ,
usb_sndbulkpipe ( cardp - > udev ,
cardp - > bulk_out_endpointAddr ) ,
2007-08-20 19:43:25 +04:00
payload , nb , if_usb_write_bulk_callback , cardp ) ;
2007-02-10 17:25:27 +03:00
cardp - > tx_urb - > transfer_flags | = URB_ZERO_PACKET ;
if ( ( ret = usb_submit_urb ( cardp - > tx_urb , GFP_ATOMIC ) ) ) {
/* transfer failed */
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " usb_submit_urb failed \n " ) ;
2007-02-10 17:25:27 +03:00
ret = - 1 ;
} else {
2007-05-25 19:27:16 +04:00
/* lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb success\n"); */
2007-02-10 17:25:27 +03:00
ret = 0 ;
}
tx_ret :
return ret ;
}
2007-08-20 19:43:25 +04:00
static int __if_usb_submit_rx_urb ( struct usb_card_rec * cardp ,
void ( * callbackfn ) ( struct urb * urb ) )
2007-02-10 17:25:27 +03:00
{
struct sk_buff * skb ;
struct read_cb_info * rinfo = & cardp - > rinfo ;
int ret = - 1 ;
if ( ! ( skb = dev_alloc_skb ( MRVDRV_ETH_RX_PACKET_BUFFER_SIZE ) ) ) {
lbs_pr_err ( " No free skb \n " ) ;
goto rx_ret ;
}
rinfo - > skb = skb ;
/* Fill the receive configuration URB and initialise the Rx call back */
usb_fill_bulk_urb ( cardp - > rx_urb , cardp - > udev ,
usb_rcvbulkpipe ( cardp - > udev ,
cardp - > bulk_in_endpointAddr ) ,
2007-05-11 07:10:18 +04:00
( void * ) ( skb - > tail + ( size_t ) IPFIELD_ALIGN_OFFSET ) ,
2007-02-10 17:25:27 +03:00
MRVDRV_ETH_RX_PACKET_BUFFER_SIZE , callbackfn ,
rinfo ) ;
cardp - > rx_urb - > transfer_flags | = URB_ZERO_PACKET ;
2007-05-25 19:27:16 +04:00
/* lbs_deb_usbd(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); */
2007-02-10 17:25:27 +03:00
if ( ( ret = usb_submit_urb ( cardp - > rx_urb , GFP_ATOMIC ) ) ) {
/* handle failure conditions */
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " Submit Rx URB failed \n " ) ;
2007-02-10 17:25:27 +03:00
ret = - 1 ;
} else {
2007-05-25 19:27:16 +04:00
/* lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB success\n"); */
2007-02-10 17:25:27 +03:00
ret = 0 ;
}
rx_ret :
return ret ;
}
2007-08-20 19:43:25 +04:00
static int if_usb_submit_rx_urb_fwload ( struct usb_card_rec * cardp )
2007-02-10 17:25:27 +03:00
{
2007-08-20 19:43:25 +04:00
return __if_usb_submit_rx_urb ( cardp , & if_usb_receive_fwload ) ;
2007-02-10 17:25:27 +03:00
}
2007-08-20 19:43:25 +04:00
static int if_usb_submit_rx_urb ( struct usb_card_rec * cardp )
2007-02-10 17:25:27 +03:00
{
2007-08-20 19:43:25 +04:00
return __if_usb_submit_rx_urb ( cardp , & if_usb_receive ) ;
2007-02-10 17:25:27 +03:00
}
static void if_usb_receive_fwload ( struct urb * urb )
{
struct read_cb_info * rinfo = ( struct read_cb_info * ) urb - > context ;
struct sk_buff * skb = rinfo - > skb ;
2007-08-20 19:43:25 +04:00
struct usb_card_rec * cardp = ( struct usb_card_rec * ) rinfo - > cardp ;
2007-02-10 17:25:27 +03:00
struct fwsyncheader * syncfwheader ;
struct bootcmdrespStr bootcmdresp ;
if ( urb - > status ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" URB status is failed during fw load \n " ) ;
kfree_skb ( skb ) ;
return ;
}
if ( cardp - > bootcmdresp = = 0 ) {
memcpy ( & bootcmdresp , skb - > data + IPFIELD_ALIGN_OFFSET ,
sizeof ( bootcmdresp ) ) ;
2007-05-26 07:36:54 +04:00
if ( le16_to_cpu ( cardp - > udev - > descriptor . bcdDevice ) < 0x3106 ) {
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
2007-08-20 19:43:25 +04:00
if_usb_submit_rx_urb_fwload ( cardp ) ;
2007-02-10 17:25:27 +03:00
cardp - > bootcmdresp = 1 ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" Received valid boot command response \n " ) ;
return ;
}
2007-05-26 07:36:54 +04:00
if ( bootcmdresp . u32magicnumber ! = cpu_to_le32 ( BOOT_CMD_MAGIC_NUMBER ) ) {
2007-02-10 17:25:27 +03:00
lbs_pr_info (
" boot cmd response wrong magic number (0x%x) \n " ,
2007-05-26 07:36:54 +04:00
le32_to_cpu ( bootcmdresp . u32magicnumber ) ) ;
2007-02-10 17:25:27 +03:00
} else if ( bootcmdresp . u8cmd_tag ! = BOOT_CMD_FW_BY_USB ) {
lbs_pr_info (
" boot cmd response cmd_tag error (%d) \n " ,
bootcmdresp . u8cmd_tag ) ;
} else if ( bootcmdresp . u8result ! = BOOT_CMD_RESP_OK ) {
lbs_pr_info (
" boot cmd response result error (%d) \n " ,
bootcmdresp . u8result ) ;
} else {
cardp - > bootcmdresp = 1 ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" Received valid boot command response \n " ) ;
}
kfree_skb ( skb ) ;
2007-08-20 19:43:25 +04:00
if_usb_submit_rx_urb_fwload ( cardp ) ;
2007-02-10 17:25:27 +03:00
return ;
}
syncfwheader = kmalloc ( sizeof ( struct fwsyncheader ) , GFP_ATOMIC ) ;
if ( ! syncfwheader ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " Failure to allocate syncfwheader \n " ) ;
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
return ;
}
memcpy ( syncfwheader , skb - > data + IPFIELD_ALIGN_OFFSET ,
sizeof ( struct fwsyncheader ) ) ;
if ( ! syncfwheader - > cmd ) {
2007-05-25 19:27:16 +04:00
/*
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" FW received Blk with correct CRC \n " ) ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" FW received Blk seqnum = %d \n " ,
syncfwheader - > seqnum ) ;
2007-05-25 19:27:16 +04:00
*/
2007-02-10 17:25:27 +03:00
cardp - > CRC_OK = 1 ;
} else {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" FW received Blk with CRC error \n " ) ;
cardp - > CRC_OK = 0 ;
}
kfree_skb ( skb ) ;
if ( cardp - > fwfinalblk ) {
cardp - > fwdnldover = 1 ;
goto exit ;
}
2007-08-20 19:43:25 +04:00
if_prog_firmware ( cardp ) ;
2007-02-10 17:25:27 +03:00
2007-08-20 19:43:25 +04:00
if_usb_submit_rx_urb_fwload ( cardp ) ;
2007-02-10 17:25:27 +03:00
exit :
kfree ( syncfwheader ) ;
return ;
}
# define MRVDRV_MIN_PKT_LEN 30
static inline void process_cmdtypedata ( int recvlength , struct sk_buff * skb ,
struct usb_card_rec * cardp ,
2007-11-23 17:43:44 +03:00
struct lbs_private * priv )
2007-02-10 17:25:27 +03:00
{
if ( recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
MESSAGE_HEADER_LEN | | recvlength < MRVDRV_MIN_PKT_LEN ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" Packet length is Invalid \n " ) ;
kfree_skb ( skb ) ;
return ;
}
skb_reserve ( skb , IPFIELD_ALIGN_OFFSET ) ;
skb_put ( skb , recvlength ) ;
skb_pull ( skb , MESSAGE_HEADER_LEN ) ;
2007-11-16 02:05:47 +03:00
lbs_process_rxed_packet ( priv , skb ) ;
2007-05-25 21:05:16 +04:00
priv - > upld_len = ( recvlength - MESSAGE_HEADER_LEN ) ;
2007-02-10 17:25:27 +03:00
}
static inline void process_cmdrequest ( int recvlength , u8 * recvbuff ,
struct sk_buff * skb ,
struct usb_card_rec * cardp ,
2007-11-23 17:43:44 +03:00
struct lbs_private * priv )
2007-02-10 17:25:27 +03:00
{
u8 * cmdbuf ;
if ( recvlength > MRVDRV_SIZE_OF_CMD_BUFFER ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" The receive buffer is too large \n " ) ;
kfree_skb ( skb ) ;
return ;
}
if ( ! in_interrupt ( ) )
BUG ( ) ;
spin_lock ( & priv - > adapter - > driver_lock ) ;
/* take care of cur_cmd = NULL case by reading the
* data to clear the interrupt */
if ( ! priv - > adapter - > cur_cmd ) {
2007-05-25 21:05:16 +04:00
cmdbuf = priv - > upld_buf ;
2007-08-02 19:49:45 +04:00
priv - > adapter - > hisregcpy & = ~ MRVDRV_CMD_UPLD_RDY ;
2007-02-10 17:25:27 +03:00
} else
cmdbuf = priv - > adapter - > cur_cmd - > bufvirtualaddr ;
2007-08-02 19:49:45 +04:00
cardp - > usb_int_cause | = MRVDRV_CMD_UPLD_RDY ;
2007-05-25 21:05:16 +04:00
priv - > upld_len = ( recvlength - MESSAGE_HEADER_LEN ) ;
2007-02-10 17:25:27 +03:00
memcpy ( cmdbuf , recvbuff + MESSAGE_HEADER_LEN ,
2007-05-25 21:05:16 +04:00
priv - > upld_len ) ;
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
2007-11-16 02:05:47 +03:00
lbs_interrupt ( priv - > dev ) ;
2007-02-10 17:25:27 +03:00
spin_unlock ( & priv - > adapter - > driver_lock ) ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" Wake up main thread to handle cmd response \n " ) ;
return ;
}
/**
* @ brief This function reads of the packet into the upload buff ,
* wake up the main thread and initialise the Rx callack .
*
* @ param urb pointer to struct urb
* @ return N / A
*/
static void if_usb_receive ( struct urb * urb )
{
struct read_cb_info * rinfo = ( struct read_cb_info * ) urb - > context ;
struct sk_buff * skb = rinfo - > skb ;
2007-08-20 19:43:25 +04:00
struct usb_card_rec * cardp = ( struct usb_card_rec * ) rinfo - > cardp ;
2007-11-23 17:43:44 +03:00
struct lbs_private * priv = cardp - > priv ;
2007-02-10 17:25:27 +03:00
int recvlength = urb - > actual_length ;
u8 * recvbuff = NULL ;
2007-08-03 17:40:55 +04:00
u32 recvtype = 0 ;
2007-02-10 17:25:27 +03:00
2007-05-25 19:27:16 +04:00
lbs_deb_enter ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
if ( recvlength ) {
2007-08-03 17:40:55 +04:00
__le32 tmp ;
2007-02-10 17:25:27 +03:00
if ( urb - > status ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-02-10 17:25:27 +03:00
" URB status is failed \n " ) ;
kfree_skb ( skb ) ;
goto setup_for_next ;
}
recvbuff = skb - > data + IPFIELD_ALIGN_OFFSET ;
2007-08-03 17:40:55 +04:00
memcpy ( & tmp , recvbuff , sizeof ( u32 ) ) ;
recvtype = le32_to_cpu ( tmp ) ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-08-03 17:40:55 +04:00
" Recv length = 0x%x, Recv type = 0x%X \n " ,
recvlength , recvtype ) ;
2007-02-10 17:25:27 +03:00
} else if ( urb - > status )
goto rx_exit ;
switch ( recvtype ) {
case CMD_TYPE_DATA :
process_cmdtypedata ( recvlength , skb , cardp , priv ) ;
break ;
case CMD_TYPE_REQUEST :
process_cmdrequest ( recvlength , recvbuff , skb , cardp , priv ) ;
break ;
case CMD_TYPE_INDICATION :
/* Event cause handling */
spin_lock ( & priv - > adapter - > driver_lock ) ;
2007-05-26 07:36:54 +04:00
cardp - > usb_event_cause = le32_to_cpu ( * ( __le32 * ) ( recvbuff + MESSAGE_HEADER_LEN ) ) ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " **EVENT** 0x%X \n " ,
2007-02-10 17:25:27 +03:00
cardp - > usb_event_cause ) ;
if ( cardp - > usb_event_cause & 0xffff0000 ) {
2007-11-16 02:05:47 +03:00
lbs_send_tx_feedback ( priv ) ;
2007-05-11 07:08:54 +04:00
spin_unlock ( & priv - > adapter - > driver_lock ) ;
2007-02-10 17:25:27 +03:00
break ;
}
2007-05-26 07:36:54 +04:00
cardp - > usb_event_cause < < = 3 ;
2007-08-02 19:49:45 +04:00
cardp - > usb_int_cause | = MRVDRV_CARDEVENT ;
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
2007-11-16 02:05:47 +03:00
lbs_interrupt ( priv - > dev ) ;
2007-02-10 17:25:27 +03:00
spin_unlock ( & priv - > adapter - > driver_lock ) ;
goto rx_exit ;
default :
2007-08-03 17:40:55 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " Unknown command type 0x%X \n " ,
recvtype ) ;
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
break ;
}
setup_for_next :
2007-08-20 19:43:25 +04:00
if_usb_submit_rx_urb ( cardp ) ;
2007-02-10 17:25:27 +03:00
rx_exit :
2007-05-25 19:27:16 +04:00
lbs_deb_leave ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
}
/**
* @ brief This function downloads data to FW
2007-11-23 17:43:44 +03:00
* @ param priv pointer to struct lbs_private structure
2007-02-10 17:25:27 +03:00
* @ param type type of data
* @ param buf pointer to data buffer
* @ param len number of bytes
* @ return 0 or - 1
*/
2007-11-23 17:43:44 +03:00
static int if_usb_host_to_card ( struct lbs_private * priv ,
u8 type ,
u8 * payload ,
u16 nb )
2007-02-10 17:25:27 +03:00
{
2007-05-25 21:05:16 +04:00
struct usb_card_rec * cardp = ( struct usb_card_rec * ) priv - > card ;
2007-02-10 17:25:27 +03:00
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " *** type = %u \n " , type ) ;
lbs_deb_usbd ( & cardp - > udev - > dev , " size after = %d \n " , nb ) ;
2007-02-10 17:25:27 +03:00
if ( type = = MVMS_CMD ) {
2007-08-03 17:40:55 +04:00
__le32 tmp = cpu_to_le32 ( CMD_TYPE_REQUEST ) ;
2007-05-25 21:05:16 +04:00
priv - > dnld_sent = DNLD_CMD_SENT ;
2007-02-10 17:25:27 +03:00
memcpy ( cardp - > bulk_out_buffer , ( u8 * ) & tmp ,
MESSAGE_HEADER_LEN ) ;
} else {
2007-08-03 17:40:55 +04:00
__le32 tmp = cpu_to_le32 ( CMD_TYPE_DATA ) ;
2007-05-25 21:05:16 +04:00
priv - > dnld_sent = DNLD_DATA_SENT ;
2007-02-10 17:25:27 +03:00
memcpy ( cardp - > bulk_out_buffer , ( u8 * ) & tmp ,
MESSAGE_HEADER_LEN ) ;
}
memcpy ( ( cardp - > bulk_out_buffer + MESSAGE_HEADER_LEN ) , payload , nb ) ;
2007-08-20 19:43:25 +04:00
return usb_tx_block ( cardp , cardp - > bulk_out_buffer ,
2007-08-03 17:40:55 +04:00
nb + MESSAGE_HEADER_LEN ) ;
2007-02-10 17:25:27 +03:00
}
/* called with adapter->driver_lock held */
2007-11-23 17:43:44 +03:00
static int if_usb_get_int_status ( struct lbs_private * priv , u8 * ireg )
2007-02-10 17:25:27 +03:00
{
2007-05-25 21:05:16 +04:00
struct usb_card_rec * cardp = priv - > card ;
2007-02-10 17:25:27 +03:00
* ireg = cardp - > usb_int_cause ;
cardp - > usb_int_cause = 0 ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " Int cause is 0x%X \n " , * ireg ) ;
2007-02-10 17:25:27 +03:00
return 0 ;
}
2007-11-23 17:43:44 +03:00
static int if_usb_read_event_cause ( struct lbs_private * priv )
2007-02-10 17:25:27 +03:00
{
2007-05-25 21:05:16 +04:00
struct usb_card_rec * cardp = priv - > card ;
2007-08-20 19:43:25 +04:00
2007-02-10 17:25:27 +03:00
priv - > adapter - > eventcause = cardp - > usb_event_cause ;
/* Re-submit rx urb here to avoid event lost issue */
2007-08-20 19:43:25 +04:00
if_usb_submit_rx_urb ( cardp ) ;
2007-02-10 17:25:27 +03:00
return 0 ;
}
2007-08-02 19:14:49 +04:00
/**
* @ brief This function issues Boot command to the Boot2 code
* @ param ivalue 1 : Boot from FW by USB - Download
* 2 : Boot from FW in EEPROM
* @ return 0
*/
2007-08-20 19:43:25 +04:00
static int if_usb_issue_boot_command ( struct usb_card_rec * cardp , int ivalue )
2007-08-02 19:14:49 +04:00
{
2007-08-20 19:43:25 +04:00
struct bootcmdstr sbootcmd ;
2007-08-02 19:14:49 +04:00
int i ;
/* Prepare command */
sbootcmd . u32magicnumber = cpu_to_le32 ( BOOT_CMD_MAGIC_NUMBER ) ;
sbootcmd . u8cmd_tag = ivalue ;
for ( i = 0 ; i < 11 ; i + + )
sbootcmd . au8dumy [ i ] = 0x00 ;
memcpy ( cardp - > bulk_out_buffer , & sbootcmd , sizeof ( struct bootcmdstr ) ) ;
/* Issue command */
2007-08-20 19:43:25 +04:00
usb_tx_block ( cardp , cardp - > bulk_out_buffer , sizeof ( struct bootcmdstr ) ) ;
2007-08-02 19:14:49 +04:00
return 0 ;
}
2007-02-10 17:25:27 +03:00
2007-08-20 19:43:25 +04:00
/**
* @ brief This function checks the validity of Boot2 / FW image .
*
* @ param data pointer to image
* len image length
* @ return 0 or - 1
*/
static int check_fwfile_format ( u8 * data , u32 totlen )
{
u32 bincmd , exit ;
u32 blksize , offset , len ;
int ret ;
ret = 1 ;
exit = len = 0 ;
do {
struct fwheader * fwh = ( void * ) data ;
bincmd = le32_to_cpu ( fwh - > dnldcmd ) ;
blksize = le32_to_cpu ( fwh - > datalength ) ;
switch ( bincmd ) {
case FW_HAS_DATA_TO_RECV :
offset = sizeof ( struct fwheader ) + blksize ;
data + = offset ;
len + = offset ;
if ( len > = totlen )
exit = 1 ;
break ;
case FW_HAS_LAST_BLOCK :
exit = 1 ;
ret = 0 ;
break ;
default :
exit = 1 ;
break ;
}
} while ( ! exit ) ;
if ( ret )
lbs_pr_err ( " firmware file format check FAIL \n " ) ;
else
lbs_deb_fw ( " firmware file format check PASS \n " ) ;
return ret ;
}
static int if_usb_prog_firmware ( struct usb_card_rec * cardp )
2007-02-10 17:25:27 +03:00
{
int i = 0 ;
static int reset_count = 10 ;
2007-05-25 19:27:16 +04:00
int ret = 0 ;
2007-02-10 17:25:27 +03:00
2007-05-25 19:27:16 +04:00
lbs_deb_enter ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
2007-11-16 02:05:47 +03:00
if ( ( ret = request_firmware ( & cardp - > fw , lbs_fw_name ,
2007-08-20 19:43:25 +04:00
& cardp - > udev - > dev ) ) < 0 ) {
lbs_pr_err ( " request_firmware() failed with %#x \n " , ret ) ;
2007-11-16 02:05:47 +03:00
lbs_pr_err ( " firmware %s not found \n " , lbs_fw_name ) ;
2007-08-20 19:43:25 +04:00
goto done ;
}
if ( check_fwfile_format ( cardp - > fw - > data , cardp - > fw - > size ) )
goto release_fw ;
2007-02-10 17:25:27 +03:00
restart :
2007-08-20 19:43:25 +04:00
if ( if_usb_submit_rx_urb_fwload ( cardp ) < 0 ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " URB submission is failed \n " ) ;
ret = - 1 ;
2007-08-20 19:43:25 +04:00
goto release_fw ;
2007-02-10 17:25:27 +03:00
}
cardp - > bootcmdresp = 0 ;
do {
int j = 0 ;
i + + ;
/* Issue Boot command = 1, Boot from Download-FW */
2007-08-20 19:43:25 +04:00
if_usb_issue_boot_command ( cardp , BOOT_CMD_FW_BY_USB ) ;
2007-02-10 17:25:27 +03:00
/* wait for command response */
do {
j + + ;
msleep_interruptible ( 100 ) ;
} while ( cardp - > bootcmdresp = = 0 & & j < 10 ) ;
} while ( cardp - > bootcmdresp = = 0 & & i < 5 ) ;
if ( cardp - > bootcmdresp = = 0 ) {
if ( - - reset_count > = 0 ) {
2007-08-20 19:43:25 +04:00
if_usb_reset_device ( cardp ) ;
2007-02-10 17:25:27 +03:00
goto restart ;
}
return - 1 ;
}
i = 0 ;
cardp - > totalbytes = 0 ;
cardp - > fwlastblksent = 0 ;
cardp - > CRC_OK = 1 ;
cardp - > fwdnldover = 0 ;
cardp - > fwseqnum = - 1 ;
cardp - > totalbytes = 0 ;
cardp - > fwfinalblk = 0 ;
2007-08-20 19:43:25 +04:00
if_prog_firmware ( cardp ) ;
2007-02-10 17:25:27 +03:00
do {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " Wlan sched timeout \n " ) ;
2007-02-10 17:25:27 +03:00
i + + ;
msleep_interruptible ( 100 ) ;
2007-08-20 19:43:25 +04:00
if ( cardp - > surprise_removed | | i > = 20 )
2007-02-10 17:25:27 +03:00
break ;
} while ( ! cardp - > fwdnldover ) ;
if ( ! cardp - > fwdnldover ) {
lbs_pr_info ( " failed to load fw, resetting device! \n " ) ;
if ( - - reset_count > = 0 ) {
2007-08-20 19:43:25 +04:00
if_usb_reset_device ( cardp ) ;
2007-02-10 17:25:27 +03:00
goto restart ;
}
lbs_pr_info ( " FW download failure, time = %d ms \n " , i * 100 ) ;
2007-05-25 19:27:16 +04:00
ret = - 1 ;
2007-08-20 19:43:25 +04:00
goto release_fw ;
2007-02-10 17:25:27 +03:00
}
2007-08-20 19:43:25 +04:00
release_fw :
release_firmware ( cardp - > fw ) ;
cardp - > fw = NULL ;
2007-02-10 17:25:27 +03:00
2007-05-25 19:27:16 +04:00
done :
lbs_deb_leave_args ( LBS_DEB_USB , " ret %d " , ret ) ;
return ret ;
2007-02-10 17:25:27 +03:00
}
2007-08-02 19:45:12 +04:00
2007-02-10 17:25:27 +03:00
# ifdef CONFIG_PM
static int if_usb_suspend ( struct usb_interface * intf , pm_message_t message )
{
struct usb_card_rec * cardp = usb_get_intfdata ( intf ) ;
2007-11-23 17:43:44 +03:00
struct lbs_private * priv = cardp - > priv ;
2007-02-10 17:25:27 +03:00
2007-05-25 19:27:16 +04:00
lbs_deb_enter ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
if ( priv - > adapter - > psstate ! = PS_STATE_FULL_POWER )
return - 1 ;
2007-08-02 21:16:02 +04:00
if ( priv - > mesh_dev & & ! priv - > mesh_autostart_enabled ) {
/* Mesh autostart must be activated while sleeping
* On resume it will go back to the current state
*/
struct cmd_ds_mesh_access mesh_access ;
memset ( & mesh_access , 0 , sizeof ( mesh_access ) ) ;
mesh_access . data [ 0 ] = cpu_to_le32 ( 1 ) ;
2007-11-16 02:05:47 +03:00
lbs_prepare_and_send_command ( priv ,
2007-08-02 21:16:02 +04:00
CMD_MESH_ACCESS ,
CMD_ACT_MESH_SET_AUTOSTART_ENABLED ,
CMD_OPTION_WAITFORRSP , 0 , ( void * ) & mesh_access ) ;
}
2007-02-10 17:25:27 +03:00
netif_device_detach ( cardp - > eth_dev ) ;
2007-05-25 20:06:56 +04:00
netif_device_detach ( priv - > mesh_dev ) ;
2007-02-10 17:25:27 +03:00
/* Unlink tx & rx urb */
usb_kill_urb ( cardp - > tx_urb ) ;
usb_kill_urb ( cardp - > rx_urb ) ;
cardp - > rx_urb_recall = 1 ;
2007-05-25 19:27:16 +04:00
lbs_deb_leave ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
return 0 ;
}
static int if_usb_resume ( struct usb_interface * intf )
{
struct usb_card_rec * cardp = usb_get_intfdata ( intf ) ;
2007-11-23 17:43:44 +03:00
struct lbs_private * priv = cardp - > priv ;
2007-02-10 17:25:27 +03:00
2007-05-25 19:27:16 +04:00
lbs_deb_enter ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
cardp - > rx_urb_recall = 0 ;
if_usb_submit_rx_urb ( cardp - > priv ) ;
netif_device_attach ( cardp - > eth_dev ) ;
2007-05-25 20:06:56 +04:00
netif_device_attach ( priv - > mesh_dev ) ;
2007-02-10 17:25:27 +03:00
2007-08-02 21:16:02 +04:00
if ( priv - > mesh_dev & & ! priv - > mesh_autostart_enabled ) {
/* Mesh autostart was activated while sleeping
* Disable it if appropriate
*/
struct cmd_ds_mesh_access mesh_access ;
memset ( & mesh_access , 0 , sizeof ( mesh_access ) ) ;
mesh_access . data [ 0 ] = cpu_to_le32 ( 0 ) ;
2007-11-16 02:05:47 +03:00
lbs_prepare_and_send_command ( priv ,
2007-08-02 21:16:02 +04:00
CMD_MESH_ACCESS ,
CMD_ACT_MESH_SET_AUTOSTART_ENABLED ,
CMD_OPTION_WAITFORRSP , 0 , ( void * ) & mesh_access ) ;
}
2007-05-25 19:27:16 +04:00
lbs_deb_leave ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
return 0 ;
}
# else
# define if_usb_suspend NULL
# define if_usb_resume NULL
# endif
static struct usb_driver if_usb_driver = {
2007-11-21 01:44:04 +03:00
. name = DRV_NAME ,
2007-02-10 17:25:27 +03:00
. probe = if_usb_probe ,
. disconnect = if_usb_disconnect ,
. id_table = if_usb_table ,
. suspend = if_usb_suspend ,
. resume = if_usb_resume ,
} ;
2007-11-21 01:43:45 +03:00
static int __init if_usb_init_module ( void )
2007-02-10 17:25:27 +03:00
{
2007-05-25 20:37:58 +04:00
int ret = 0 ;
2007-02-10 17:25:27 +03:00
2007-05-25 20:37:58 +04:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
ret = usb_register ( & if_usb_driver ) ;
lbs_deb_leave_args ( LBS_DEB_MAIN , " ret %d " , ret ) ;
return ret ;
2007-02-10 17:25:27 +03:00
}
2007-11-21 01:43:45 +03:00
static void __exit if_usb_exit_module ( void )
2007-02-10 17:25:27 +03:00
{
2007-05-25 20:37:58 +04:00
lbs_deb_enter ( LBS_DEB_MAIN ) ;
2007-02-10 17:25:27 +03:00
usb_deregister ( & if_usb_driver ) ;
2007-05-25 20:37:58 +04:00
lbs_deb_leave ( LBS_DEB_MAIN ) ;
2007-02-10 17:25:27 +03:00
}
2007-05-25 20:37:58 +04:00
module_init ( if_usb_init_module ) ;
module_exit ( if_usb_exit_module ) ;
MODULE_DESCRIPTION ( " 8388 USB WLAN Driver " ) ;
MODULE_AUTHOR ( " Marvell International Ltd. " ) ;
MODULE_LICENSE ( " GPL " ) ;