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"
2007-12-10 23:11:23 +03:00
# include "cmd.h"
2007-02-10 17:25:27 +03:00
# include "if_usb.h"
2007-12-14 08:47:05 +03:00
# define INSANEDEBUG 0
# define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0)
2007-02-10 17:25:27 +03:00
# 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-12-14 08:47:05 +03:00
static int if_usb_prog_firmware ( struct if_usb_card * cardp ) ;
static int if_usb_host_to_card ( struct lbs_private * priv , uint8_t type ,
uint8_t * payload , uint16_t nb ) ;
static int if_usb_get_int_status ( struct lbs_private * priv , uint8_t * ) ;
2007-11-23 17:43:44 +03:00
static int if_usb_read_event_cause ( struct lbs_private * ) ;
2007-12-14 08:47:05 +03:00
static int usb_tx_block ( struct if_usb_card * cardp , uint8_t * payload ,
uint16_t nb ) ;
static void if_usb_free ( struct if_usb_card * cardp ) ;
static int if_usb_submit_rx_urb ( struct if_usb_card * cardp ) ;
static int if_usb_reset_device ( struct if_usb_card * 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-12-14 08:47:05 +03:00
struct if_usb_card * cardp = ( struct if_usb_card * ) 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-12-14 08:47:05 +03:00
lbs_deb_usb2 ( & urb - > dev - > dev , " URB status is successful \n " ) ;
lbs_deb_usb2 ( & urb - > dev - > dev , " Actual length transmitted %d \n " ,
urb - > actual_length ) ;
2007-08-20 19:43:25 +04:00
/* Used for both firmware TX and regular TX. priv isn't
* valid at firmware load time .
*/
2007-12-06 17:36:11 +03:00
if ( priv )
lbs_host_to_card_done ( priv ) ;
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
2007-12-14 08:47:05 +03:00
* @ param cardp pointer if_usb_card
2007-02-10 17:25:27 +03:00
* @ return N / A
*/
2007-12-14 08:47:05 +03:00
static void if_usb_free ( struct if_usb_card * 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 ;
2007-12-14 08:47:05 +03:00
kfree ( cardp - > ep_out_buf ) ;
cardp - > ep_out_buf = NULL ;
2007-02-10 17:25:27 +03:00
2007-05-25 19:27:16 +04:00
lbs_deb_leave ( LBS_DEB_USB ) ;
2007-02-10 17:25:27 +03:00
}
2007-12-06 15:51:00 +03:00
static void if_usb_set_boot2_ver ( struct lbs_private * priv )
{
struct cmd_ds_set_boot2_ver b2_cmd ;
b2_cmd . action = 0 ;
2007-12-07 18:30:44 +03:00
b2_cmd . version = priv - > boot2_version ;
2007-12-06 15:51:00 +03:00
2007-12-15 09:22:09 +03:00
if ( lbs_cmd_with_response ( priv , CMD_SET_BOOT2_VER , & b2_cmd ) )
2007-12-06 15:51:00 +03:00
lbs_deb_usb ( " Setting boot2 version failed \n " ) ;
}
2007-12-12 01:44:10 +03:00
static void if_usb_fw_timeo ( unsigned long priv )
2007-12-11 08:07:58 +03:00
{
2007-12-14 08:47:05 +03:00
struct if_usb_card * cardp = ( void * ) priv ;
2007-12-06 15:51:00 +03:00
2007-12-11 08:07:58 +03:00
if ( cardp - > fwdnldover ) {
lbs_deb_usb ( " Download complete, no event. Assuming success \n " ) ;
} else {
lbs_pr_err ( " Download timed out \n " ) ;
cardp - > surprise_removed = 1 ;
}
wake_up ( & cardp - > fw_wq ) ;
}
2007-12-14 08:47:05 +03:00
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-12-14 08:47:05 +03:00
struct if_usb_card * cardp ;
2007-02-10 17:25:27 +03:00
int i ;
udev = interface_to_usbdev ( intf ) ;
2007-12-14 08:47:05 +03:00
cardp = kzalloc ( sizeof ( struct if_usb_card ) , GFP_KERNEL ) ;
2007-05-25 20:41:52 +04:00
if ( ! cardp ) {
2007-02-10 17:25:27 +03:00
lbs_pr_err ( " Out of memory allocating private data. \n " ) ;
goto error ;
}
2007-12-11 08:07:58 +03:00
setup_timer ( & cardp - > fw_timeout , if_usb_fw_timeo , ( unsigned long ) cardp ) ;
init_waitqueue_head ( & cardp - > fw_wq ) ;
2007-12-15 06:53:41 +03:00
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-12-14 08:47:05 +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 ;
2007-12-14 08:47:05 +03:00
if ( usb_endpoint_is_bulk_in ( endpoint ) ) {
cardp - > ep_in_size = le16_to_cpu ( endpoint - > wMaxPacketSize ) ;
cardp - > ep_in = usb_endpoint_num ( endpoint ) ;
2007-02-10 17:25:27 +03:00
2007-12-14 08:47:05 +03:00
lbs_deb_usbd ( & udev - > dev , " in_endpoint = %d \n " , cardp - > ep_in ) ;
lbs_deb_usbd ( & udev - > dev , " Bulk in size is %d \n " , cardp - > ep_in_size ) ;
2007-02-10 17:25:27 +03:00
2007-12-14 08:47:05 +03:00
} else if ( usb_endpoint_is_bulk_out ( endpoint ) ) {
cardp - > ep_out_size = le16_to_cpu ( endpoint - > wMaxPacketSize ) ;
cardp - > ep_out = usb_endpoint_num ( endpoint ) ;
lbs_deb_usbd ( & udev - > dev , " out_endpoint = %d \n " , cardp - > ep_out ) ;
lbs_deb_usbd ( & udev - > dev , " Bulk out size is %d \n " , cardp - > ep_out_size ) ;
2007-02-10 17:25:27 +03:00
}
}
2007-12-14 08:47:05 +03:00
if ( ! cardp - > ep_out_size | | ! cardp - > ep_in_size ) {
lbs_deb_usbd ( & udev - > dev , " Endpoints not found \n " ) ;
goto dealloc ;
}
if ( ! ( cardp - > rx_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ) ) {
lbs_deb_usbd ( & udev - > dev , " Rx URB allocation failed \n " ) ;
goto dealloc ;
}
if ( ! ( cardp - > tx_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ) ) {
lbs_deb_usbd ( & udev - > dev , " Tx URB allocation failed \n " ) ;
goto dealloc ;
}
cardp - > ep_out_buf = kmalloc ( MRVDRV_ETH_TX_PACKET_BUFFER_SIZE , GFP_KERNEL ) ;
if ( ! cardp - > ep_out_buf ) {
lbs_deb_usbd ( & udev - > dev , " Could not allocate buffer \n " ) ;
goto dealloc ;
}
2007-02-10 17:25:27 +03:00
2007-08-20 19:43:25 +04:00
/* Upload firmware */
if ( if_usb_prog_firmware ( cardp ) ) {
2007-12-12 08:14:21 +03:00
lbs_deb_usbd ( & udev - > dev , " FW upload failed \n " ) ;
2007-08-20 19:43:25 +04:00
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-12-11 21:15:25 +03:00
cardp - > priv - > fw_ready = 1 ;
2007-08-02 21:16:55 +04:00
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-12-07 18:30:44 +03:00
priv - > boot2_version = udev - > descriptor . bcdDevice ;
2007-05-25 20:17:06 +04:00
2007-08-20 19:43:25 +04:00
if_usb_submit_rx_urb ( cardp ) ;
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-12-06 15:51:00 +03:00
if_usb_set_boot2_ver ( priv ) ;
2007-12-06 17:41:08 +03:00
2007-12-13 04:06:06 +03:00
priv - > wol_gpio = 2 ; /* Wake via GPIO2... */
priv - > wol_gap = 20 ; /* ... after 20ms */
lbs_host_sleep_cfg ( priv , EHS_WAKE_ON_UNICAST_DATA ) ;
2007-12-13 01:40:56 +03: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_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 )
{
2007-12-14 08:47:05 +03:00
struct if_usb_card * 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
cardp - > surprise_removed = 1 ;
2007-02-10 17:25:27 +03:00
2007-08-20 19:43:25 +04:00
if ( priv ) {
2007-12-08 23:04:36 +03:00
priv - > surpriseremoved = 1 ;
2007-11-16 02:05:47 +03:00
lbs_stop_card ( priv ) ;
lbs_remove_card ( priv ) ;
2007-08-20 19:43:25 +04:00
}
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-12-14 08:47:05 +03:00
static int if_usb_send_fw_pkt ( struct if_usb_card * cardp )
2007-02-10 17:25:27 +03:00
{
2007-12-14 08:47:05 +03:00
struct fwdata * fwdata = cardp - > ep_out_buf ;
uint8_t * firmware = cardp - > fw - > data ;
2007-02-10 17:25:27 +03:00
2007-12-14 08:47:05 +03:00
/* If we got a CRC failure on the last block, back
up and retry it */
2007-02-10 17:25:27 +03:00
if ( ! cardp - > CRC_OK ) {
cardp - > totalbytes = cardp - > fwlastblksent ;
2007-12-14 08:47:05 +03:00
cardp - > fwseqnum - - ;
2007-02-10 17:25:27 +03:00
}
2007-12-14 08:47:05 +03:00
lbs_deb_usb2 ( & cardp - > udev - > dev , " totalbytes = %d \n " ,
cardp - > totalbytes ) ;
2007-02-10 17:25:27 +03:00
2007-12-14 08:47:05 +03:00
/* struct fwdata (which we sent to the card) has an
extra __le32 field in between the header and the data ,
which is not in the struct fwheader in the actual
firmware binary . Insert the seqnum in the middle . . . */
memcpy ( & fwdata - > hdr , & firmware [ cardp - > totalbytes ] ,
2007-02-10 17:25:27 +03:00
sizeof ( struct fwheader ) ) ;
cardp - > fwlastblksent = cardp - > totalbytes ;
cardp - > totalbytes + = sizeof ( struct fwheader ) ;
memcpy ( fwdata - > data , & firmware [ cardp - > totalbytes ] ,
2007-12-14 08:47:05 +03:00
le32_to_cpu ( fwdata - > hdr . datalength ) ) ;
2007-02-10 17:25:27 +03:00
2007-12-14 08:47:05 +03:00
lbs_deb_usb2 ( & cardp - > udev - > dev , " Data length = %d \n " ,
le32_to_cpu ( fwdata - > hdr . datalength ) ) ;
2007-02-10 17:25:27 +03:00
2007-12-14 08:47:05 +03:00
fwdata - > seqnum = cpu_to_le32 ( + + cardp - > fwseqnum ) ;
cardp - > totalbytes + = le32_to_cpu ( fwdata - > hdr . datalength ) ;
2007-02-10 17:25:27 +03:00
2007-12-14 08:47:05 +03:00
usb_tx_block ( cardp , cardp - > ep_out_buf , sizeof ( struct fwdata ) +
le32_to_cpu ( fwdata - > hdr . datalength ) ) ;
if ( fwdata - > hdr . dnldcmd = = cpu_to_le32 ( FW_HAS_DATA_TO_RECV ) ) {
lbs_deb_usb2 ( & cardp - > udev - > dev , " There are data to follow \n " ) ;
lbs_deb_usb2 ( & cardp - > udev - > dev , " seqnum = %d totalbytes = %d \n " ,
cardp - > fwseqnum , cardp - > totalbytes ) ;
} else if ( fwdata - > hdr . dnldcmd = = cpu_to_le32 ( FW_HAS_LAST_BLOCK ) ) {
lbs_deb_usb2 ( & cardp - > udev - > dev , " Host has finished FW downloading \n " ) ;
lbs_deb_usb2 ( & cardp - > udev - > dev , " Donwloading FW JUMP BLOCK \n " ) ;
2007-02-10 17:25:27 +03:00
cardp - > fwfinalblk = 1 ;
}
2007-12-14 08:47:05 +03:00
lbs_deb_usb2 ( & cardp - > udev - > dev , " Firmware download done; size %d \n " ,
cardp - > totalbytes ) ;
2007-02-10 17:25:27 +03:00
return 0 ;
}
2007-12-14 08:47:05 +03:00
static int if_usb_reset_device ( struct if_usb_card * cardp )
2007-02-10 17:25:27 +03:00
{
2007-12-14 08:47:05 +03:00
struct cmd_ds_command * cmd = cardp - > ep_out_buf + 4 ;
2007-02-10 17:25:27 +03:00
int ret ;
2007-05-25 20:01:42 +04:00
lbs_deb_enter ( LBS_DEB_USB ) ;
2007-12-14 08:47:05 +03:00
* ( __le32 * ) cardp - > ep_out_buf = cpu_to_le32 ( CMD_TYPE_REQUEST ) ;
2007-12-09 02:49:06 +03:00
cmd - > command = cpu_to_le16 ( CMD_802_11_RESET ) ;
cmd - > size = cpu_to_le16 ( sizeof ( struct cmd_ds_802_11_reset ) + S_DS_GEN ) ;
cmd - > result = cpu_to_le16 ( 0 ) ;
cmd - > seqnum = cpu_to_le16 ( 0x5a5a ) ;
cmd - > params . reset . action = cpu_to_le16 ( CMD_ACT_HALT ) ;
2007-12-14 08:47:05 +03:00
usb_tx_block ( cardp , cardp - > ep_out_buf , 4 + S_DS_GEN + sizeof ( struct cmd_ds_802_11_reset ) ) ;
2007-12-09 02:49:06 +03:00
2007-12-11 02:53:34 +03:00
msleep ( 100 ) ;
2007-02-10 17:25:27 +03:00
ret = usb_reset_device ( cardp - > udev ) ;
2007-12-11 02:53:34 +03:00
msleep ( 100 ) ;
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-12-14 08:47:05 +03:00
static int usb_tx_block ( struct if_usb_card * cardp , uint8_t * payload , uint16_t 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 ,
2007-12-14 08:47:05 +03:00
cardp - > ep_out ) ,
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 ) ) ) {
2007-12-07 18:12:26 +03:00
lbs_deb_usbd ( & cardp - > udev - > dev , " usb_submit_urb failed: %d \n " , ret ) ;
2007-02-10 17:25:27 +03:00
ret = - 1 ;
} else {
2007-12-14 08:47:05 +03:00
lbs_deb_usb2 ( & cardp - > udev - > dev , " usb_submit_urb success \n " ) ;
2007-02-10 17:25:27 +03:00
ret = 0 ;
}
tx_ret :
return ret ;
}
2007-12-14 08:47:05 +03:00
static int __if_usb_submit_rx_urb ( struct if_usb_card * cardp ,
2007-08-20 19:43:25 +04:00
void ( * callbackfn ) ( struct urb * urb ) )
2007-02-10 17:25:27 +03:00
{
struct sk_buff * skb ;
int ret = - 1 ;
if ( ! ( skb = dev_alloc_skb ( MRVDRV_ETH_RX_PACKET_BUFFER_SIZE ) ) ) {
lbs_pr_err ( " No free skb \n " ) ;
goto rx_ret ;
}
2007-12-14 08:47:05 +03:00
cardp - > rx_skb = skb ;
2007-02-10 17:25:27 +03:00
/* Fill the receive configuration URB and initialise the Rx call back */
usb_fill_bulk_urb ( cardp - > rx_urb , cardp - > udev ,
2007-12-14 08:47:05 +03:00
usb_rcvbulkpipe ( cardp - > udev , cardp - > ep_in ) ,
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 ,
2007-12-14 08:47:05 +03:00
cardp ) ;
2007-02-10 17:25:27 +03:00
cardp - > rx_urb - > transfer_flags | = URB_ZERO_PACKET ;
2007-12-14 08:47:05 +03:00
lbs_deb_usb2 ( & 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 ) ) ) {
2007-12-07 18:12:26 +03:00
lbs_deb_usbd ( & cardp - > udev - > dev , " Submit Rx URB failed: %d \n " , ret ) ;
2007-11-28 19:20:51 +03:00
kfree_skb ( skb ) ;
2007-12-14 08:47:05 +03:00
cardp - > rx_skb = NULL ;
2007-02-10 17:25:27 +03:00
ret = - 1 ;
} else {
2007-12-14 08:47:05 +03:00
lbs_deb_usb2 ( & cardp - > udev - > dev , " Submit Rx URB success \n " ) ;
2007-02-10 17:25:27 +03:00
ret = 0 ;
}
rx_ret :
return ret ;
}
2007-12-14 08:47:05 +03:00
static int if_usb_submit_rx_urb_fwload ( struct if_usb_card * 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-12-14 08:47:05 +03:00
static int if_usb_submit_rx_urb ( struct if_usb_card * 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 )
{
2007-12-14 08:47:05 +03:00
struct if_usb_card * cardp = urb - > context ;
struct sk_buff * skb = cardp - > rx_skb ;
2007-02-10 17:25:27 +03:00
struct fwsyncheader * syncfwheader ;
2007-12-14 08:47:05 +03:00
struct bootcmdresp bootcmdresp ;
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-12-14 08:47:05 +03:00
" URB status is failed during fw load \n " ) ;
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
return ;
}
2007-12-11 21:15:25 +03:00
if ( cardp - > fwdnldover ) {
__le32 * tmp = ( __le32 * ) ( skb - > data + IPFIELD_ALIGN_OFFSET ) ;
if ( tmp [ 0 ] = = cpu_to_le32 ( CMD_TYPE_INDICATION ) & &
tmp [ 1 ] = = cpu_to_le32 ( MACREG_INT_CODE_FIRMWARE_READY ) ) {
lbs_pr_info ( " Firmware ready event received \n " ) ;
wake_up ( & cardp - > fw_wq ) ;
} else {
2007-12-14 08:47:05 +03:00
lbs_deb_usb ( " Waiting for confirmation; got %x %x \n " ,
le32_to_cpu ( tmp [ 0 ] ) , le32_to_cpu ( tmp [ 1 ] ) ) ;
2007-12-11 21:15:25 +03:00
if_usb_submit_rx_urb_fwload ( cardp ) ;
}
kfree_skb ( skb ) ;
return ;
}
2007-12-11 02:53:34 +03:00
if ( cardp - > bootcmdresp < = 0 ) {
2007-02-10 17:25:27 +03:00
memcpy ( & bootcmdresp , skb - > data + IPFIELD_ALIGN_OFFSET ,
sizeof ( bootcmdresp ) ) ;
2007-12-14 08:47:05 +03:00
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-12-14 08:47:05 +03:00
" Received valid boot command response \n " ) ;
2007-02-10 17:25:27 +03:00
return ;
}
2007-12-14 08:47:05 +03:00
if ( bootcmdresp . magic ! = cpu_to_le32 ( BOOT_CMD_MAGIC_NUMBER ) ) {
if ( bootcmdresp . magic = = cpu_to_le32 ( CMD_TYPE_REQUEST ) | |
bootcmdresp . magic = = cpu_to_le32 ( CMD_TYPE_DATA ) | |
bootcmdresp . magic = = cpu_to_le32 ( CMD_TYPE_INDICATION ) ) {
2007-12-11 21:15:25 +03:00
if ( ! cardp - > bootcmdresp )
lbs_pr_info ( " Firmware already seems alive; resetting \n " ) ;
2007-12-09 02:49:06 +03:00
cardp - > bootcmdresp = - 1 ;
} else {
lbs_pr_info ( " boot cmd response wrong magic number (0x%x) \n " ,
2007-12-14 08:47:05 +03:00
le32_to_cpu ( bootcmdresp . magic ) ) ;
2007-12-09 02:49:06 +03:00
}
2007-12-14 08:47:05 +03:00
} else if ( bootcmdresp . cmd ! = BOOT_CMD_FW_BY_USB ) {
lbs_pr_info ( " boot cmd response cmd_tag error (%d) \n " ,
bootcmdresp . cmd ) ;
} else if ( bootcmdresp . result ! = BOOT_CMD_RESP_OK ) {
lbs_pr_info ( " boot cmd response result error (%d) \n " ,
bootcmdresp . result ) ;
2007-02-10 17:25:27 +03:00
} else {
cardp - > bootcmdresp = 1 ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-12-14 08:47:05 +03:00
" Received valid boot command response \n " ) ;
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
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 ,
2007-12-14 08:47:05 +03:00
sizeof ( struct fwsyncheader ) ) ;
2007-02-10 17:25:27 +03:00
if ( ! syncfwheader - > cmd ) {
2007-12-14 08:47:05 +03:00
lbs_deb_usb2 ( & cardp - > udev - > dev , " FW received Blk with correct CRC \n " ) ;
lbs_deb_usb2 ( & cardp - > udev - > dev , " FW received Blk seqnum = %d \n " ,
le32_to_cpu ( syncfwheader - > seqnum ) ) ;
2007-02-10 17:25:27 +03:00
cardp - > CRC_OK = 1 ;
} else {
2007-12-14 08:47:05 +03:00
lbs_deb_usbd ( & cardp - > udev - > dev , " FW received Blk with CRC error \n " ) ;
2007-02-10 17:25:27 +03:00
cardp - > CRC_OK = 0 ;
}
kfree_skb ( skb ) ;
2007-12-11 08:07:58 +03:00
/* reschedule timer for 200ms hence */
mod_timer ( & cardp - > fw_timeout , jiffies + ( HZ / 5 ) ) ;
2007-02-10 17:25:27 +03:00
if ( cardp - > fwfinalblk ) {
cardp - > fwdnldover = 1 ;
goto exit ;
}
2007-12-11 08:07:58 +03:00
if_usb_send_fw_pkt ( cardp ) ;
2007-02-10 17:25:27 +03:00
2007-12-11 08:07:58 +03:00
exit :
2007-12-11 21:15:25 +03:00
if_usb_submit_rx_urb_fwload ( cardp ) ;
2007-02-10 17:25:27 +03:00
kfree ( syncfwheader ) ;
return ;
}
# define MRVDRV_MIN_PKT_LEN 30
static inline void process_cmdtypedata ( int recvlength , struct sk_buff * skb ,
2007-12-14 08:47:05 +03:00
struct if_usb_card * cardp ,
2007-11-23 17:43:44 +03:00
struct lbs_private * priv )
2007-02-10 17:25:27 +03:00
{
2007-12-14 08:47:05 +03:00
if ( recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
| | recvlength < MRVDRV_MIN_PKT_LEN ) {
lbs_deb_usbd ( & cardp - > udev - > dev , " Packet length is Invalid \n " ) ;
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
return ;
}
skb_reserve ( skb , IPFIELD_ALIGN_OFFSET ) ;
skb_put ( skb , recvlength ) ;
skb_pull ( skb , MESSAGE_HEADER_LEN ) ;
2007-12-14 08:47:05 +03:00
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
}
2007-12-14 08:47:05 +03:00
static inline void process_cmdrequest ( int recvlength , uint8_t * recvbuff ,
2007-02-10 17:25:27 +03:00
struct sk_buff * skb ,
2007-12-14 08:47:05 +03:00
struct if_usb_card * cardp ,
2007-11-23 17:43:44 +03:00
struct lbs_private * priv )
2007-02-10 17:25:27 +03:00
{
2007-12-14 08:47:05 +03:00
uint8_t * cmdbuf ;
2007-12-11 21:49:39 +03:00
if ( recvlength > LBS_CMD_BUFFER_SIZE ) {
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev ,
2007-12-14 08:47:05 +03:00
" The receive buffer is too large \n " ) ;
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
return ;
}
if ( ! in_interrupt ( ) )
BUG ( ) ;
2007-12-08 23:04:36 +03:00
spin_lock ( & priv - > driver_lock ) ;
2007-02-10 17:25:27 +03:00
/* take care of cur_cmd = NULL case by reading the
* data to clear the interrupt */
2007-12-08 23:04:36 +03:00
if ( ! priv - > cur_cmd ) {
2007-12-14 08:47:05 +03:00
lbs_deb_hex ( LBS_DEB_HOST , " Unsolicited CMD_RESP " ,
( void * ) recvbuff + MESSAGE_HEADER_LEN , priv - > upld_len ) ;
2007-05-25 21:05:16 +04:00
cmdbuf = priv - > upld_buf ;
2007-12-08 23:04:36 +03:00
priv - > hisregcpy & = ~ MRVDRV_CMD_UPLD_RDY ;
2007-02-10 17:25:27 +03:00
} else
2007-12-14 08:47:05 +03:00
cmdbuf = ( uint8_t * ) priv - > cur_cmd - > cmdbuf ;
2007-02-10 17:25:27 +03:00
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-12-14 08:47:05 +03:00
memcpy ( cmdbuf , recvbuff + MESSAGE_HEADER_LEN , priv - > upld_len ) ;
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
2007-12-10 22:58:37 +03:00
lbs_interrupt ( priv ) ;
2007-12-08 23:04:36 +03:00
spin_unlock ( & priv - > driver_lock ) ;
2007-02-10 17:25:27 +03:00
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 " ) ;
}
/**
* @ 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 )
{
2007-12-14 08:47:05 +03:00
struct if_usb_card * cardp = urb - > context ;
struct sk_buff * skb = cardp - > rx_skb ;
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 ;
2007-12-14 08:47:05 +03:00
uint8_t * recvbuff = NULL ;
uint32_t recvtype = 0 ;
__le32 * pkt = ( __le32 * ) ( skb - > data + IPFIELD_ALIGN_OFFSET ) ;
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 ) {
if ( urb - > status ) {
2007-12-14 08:47:05 +03:00
lbs_deb_usbd ( & cardp - > udev - > dev , " RX URB failed: %d \n " ,
urb - > status ) ;
2007-02-10 17:25:27 +03:00
kfree_skb ( skb ) ;
goto setup_for_next ;
}
recvbuff = skb - > data + IPFIELD_ALIGN_OFFSET ;
2007-12-14 08:47:05 +03:00
recvtype = le32_to_cpu ( pkt [ 0 ] ) ;
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-11-28 19:20:51 +03:00
} else if ( urb - > status ) {
kfree_skb ( skb ) ;
2007-02-10 17:25:27 +03:00
goto rx_exit ;
2007-11-28 19:20:51 +03:00
}
2007-02-10 17:25:27 +03:00
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 */
2007-12-08 23:04:36 +03:00
spin_lock ( & priv - > driver_lock ) ;
2007-12-14 08:47:05 +03:00
cardp - > usb_event_cause = le32_to_cpu ( pkt [ 1 ] ) ;
2007-05-25 19:27:16 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " **EVENT** 0x%X \n " ,
2007-12-14 08:47:05 +03:00
cardp - > usb_event_cause ) ;
/* Icky undocumented magic special case */
2007-02-10 17:25:27 +03:00
if ( cardp - > usb_event_cause & 0xffff0000 ) {
2007-11-16 02:05:47 +03:00
lbs_send_tx_feedback ( priv ) ;
2007-12-08 23:04:36 +03:00
spin_unlock ( & priv - > 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-12-10 22:58:37 +03:00
lbs_interrupt ( priv ) ;
2007-12-08 23:04:36 +03:00
spin_unlock ( & priv - > driver_lock ) ;
2007-02-10 17:25:27 +03:00
goto rx_exit ;
default :
2007-08-03 17:40:55 +04:00
lbs_deb_usbd ( & cardp - > udev - > dev , " Unknown command type 0x%X \n " ,
2007-12-14 08:47:05 +03:00
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-12-14 08:47:05 +03:00
static int if_usb_host_to_card ( struct lbs_private * priv , uint8_t type ,
uint8_t * payload , uint16_t nb )
2007-02-10 17:25:27 +03:00
{
2007-12-14 08:47:05 +03:00
struct if_usb_card * cardp = 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-12-14 08:47:05 +03:00
* ( __le32 * ) cardp - > ep_out_buf = 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
} else {
2007-12-14 08:47:05 +03:00
* ( __le32 * ) cardp - > ep_out_buf = 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
}
2007-12-14 08:47:05 +03:00
memcpy ( ( cardp - > ep_out_buf + MESSAGE_HEADER_LEN ) , payload , nb ) ;
2007-02-10 17:25:27 +03:00
2007-12-14 08:47:05 +03:00
return usb_tx_block ( cardp , cardp - > ep_out_buf , nb + MESSAGE_HEADER_LEN ) ;
2007-02-10 17:25:27 +03:00
}
2007-12-08 23:04:36 +03:00
/* called with priv->driver_lock held */
2007-12-14 08:47:05 +03:00
static int if_usb_get_int_status ( struct lbs_private * priv , uint8_t * ireg )
2007-02-10 17:25:27 +03:00
{
2007-12-14 08:47:05 +03:00
struct if_usb_card * cardp = priv - > card ;
2007-02-10 17:25:27 +03:00
* ireg = cardp - > usb_int_cause ;
cardp - > usb_int_cause = 0 ;
2007-12-14 08:47:05 +03: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-12-14 08:47:05 +03:00
struct if_usb_card * cardp = priv - > card ;
2007-08-20 19:43:25 +04:00
2007-12-08 23:04:36 +03:00
priv - > eventcause = cardp - > usb_event_cause ;
2007-02-10 17:25:27 +03:00
/* 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-12-14 08:47:05 +03:00
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-12-14 08:47:05 +03:00
static int if_usb_issue_boot_command ( struct if_usb_card * cardp , int ivalue )
2007-08-02 19:14:49 +04:00
{
2007-12-14 08:47:05 +03:00
struct bootcmd * bootcmd = cardp - > ep_out_buf ;
2007-08-02 19:14:49 +04:00
/* Prepare command */
2007-12-14 08:47:05 +03:00
bootcmd - > magic = cpu_to_le32 ( BOOT_CMD_MAGIC_NUMBER ) ;
bootcmd - > cmd = ivalue ;
memset ( bootcmd - > pad , 0 , sizeof ( bootcmd - > pad ) ) ;
2007-08-02 19:14:49 +04:00
/* Issue command */
2007-12-14 08:47:05 +03:00
usb_tx_block ( cardp , cardp - > ep_out_buf , sizeof ( * bootcmd ) ) ;
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
*/
2007-12-14 08:47:05 +03:00
static int check_fwfile_format ( uint8_t * data , uint32_t totlen )
2007-08-20 19:43:25 +04:00
{
2007-12-14 08:47:05 +03:00
uint32_t bincmd , exit ;
uint32_t blksize , offset , len ;
2007-08-20 19:43:25 +04:00
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 ;
}
2007-12-14 08:47:05 +03:00
static int if_usb_prog_firmware ( struct if_usb_card * 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 ) ;
2007-12-09 02:49:06 +03:00
if ( cardp - > bootcmdresp < = 0 ) {
2007-02-10 17:25:27 +03:00
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-12-11 08:07:58 +03:00
/* Send the first firmware packet... */
if_usb_send_fw_pkt ( cardp ) ;
2007-02-10 17:25:27 +03:00
2007-12-11 08:07:58 +03:00
/* ... and wait for the process to complete */
wait_event_interruptible ( cardp - > fw_wq , cardp - > surprise_removed | | cardp - > fwdnldover ) ;
2007-12-15 06:53:41 +03:00
2007-12-11 08:07:58 +03:00
del_timer_sync ( & cardp - > fw_timeout ) ;
2007-12-11 21:15:25 +03:00
usb_kill_urb ( cardp - > rx_urb ) ;
2007-02-10 17:25:27 +03:00
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-12-14 08:47:05 +03:00
release_fw :
2007-08-20 19:43:25 +04:00
release_firmware ( cardp - > fw ) ;
cardp - > fw = NULL ;
2007-02-10 17:25:27 +03:00
2007-12-14 08:47:05 +03:00
done :
2007-05-25 19:27:16 +04:00
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 )
{
2007-12-14 08:47:05 +03:00
struct if_usb_card * cardp = usb_get_intfdata ( intf ) ;
2007-11-23 17:43:44 +03:00
struct lbs_private * priv = cardp - > priv ;
2007-12-13 01:40:56 +03:00
int ret ;
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-12-08 23:04:36 +03:00
if ( priv - > psstate ! = PS_STATE_FULL_POWER )
2007-02-10 17:25:27 +03:00
return - 1 ;
2007-12-13 01:40:56 +03:00
ret = lbs_suspend ( priv ) ;
if ( ret )
goto out ;
2007-02-10 17:25:27 +03:00
/* Unlink tx & rx urb */
usb_kill_urb ( cardp - > tx_urb ) ;
usb_kill_urb ( cardp - > rx_urb ) ;
2007-12-13 01:40:56 +03:00
out :
2007-05-25 19:27:16 +04:00
lbs_deb_leave ( LBS_DEB_USB ) ;
2007-12-13 01:40:56 +03:00
return ret ;
2007-02-10 17:25:27 +03:00
}
static int if_usb_resume ( struct usb_interface * intf )
{
2007-12-14 08:47:05 +03:00
struct if_usb_card * 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
2007-12-11 20:53:43 +03:00
if_usb_submit_rx_urb ( cardp ) ;
2007-02-10 17:25:27 +03:00
2007-12-13 01:40:56 +03:00
lbs_resume ( priv ) ;
2007-02-10 17:25:27 +03:00
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 " ) ;
2007-12-14 08:47:05 +03:00
MODULE_AUTHOR ( " Marvell International Ltd. and Red Hat, Inc. " ) ;
2007-05-25 20:37:58 +04:00
MODULE_LICENSE ( " GPL " ) ;