aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/libertas/if_usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/libertas/if_usb.c')
-rw-r--r--drivers/net/wireless/libertas/if_usb.c365
1 files changed, 162 insertions, 203 deletions
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 364eae374b9..105a00a7025 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -45,14 +45,14 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
static void if_usb_receive(struct urb *urb);
static void if_usb_receive_fwload(struct urb *urb);
-static int if_usb_register_dev(wlan_private * priv);
-static int if_usb_unregister_dev(wlan_private *);
-static int if_usb_prog_firmware(wlan_private *);
+static int if_usb_prog_firmware(struct usb_card_rec *cardp);
static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
static int if_usb_get_int_status(wlan_private * priv, u8 *);
static int if_usb_read_event_cause(wlan_private *);
-static int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
+static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb);
static void if_usb_free(struct usb_card_rec *cardp);
+static int if_usb_submit_rx_urb(struct usb_card_rec *cardp);
+static int if_usb_reset_device(struct usb_card_rec *cardp);
/**
* @brief call back function to handle the status of the URB
@@ -61,29 +61,40 @@ static void if_usb_free(struct usb_card_rec *cardp);
*/
static void if_usb_write_bulk_callback(struct urb *urb)
{
- wlan_private *priv = (wlan_private *) (urb->context);
- wlan_adapter *adapter = priv->adapter;
- struct net_device *dev = priv->dev;
+ struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context;
/* handle the transmission complete validations */
- if (urb->status != 0) {
- /* print the failure status number for debug */
- lbs_pr_info("URB in failure status: %d\n", urb->status);
- } else {
+ if (urb->status == 0) {
+ wlan_private *priv = cardp->priv;
+
/*
lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n");
lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n",
urb->actual_length);
*/
- priv->dnld_sent = DNLD_RES_RECEIVED;
- /* Wake main thread if commands are pending */
- if (!adapter->cur_cmd)
- wake_up_interruptible(&priv->waitq);
- if ((adapter->connect_status == LIBERTAS_CONNECTED)) {
- netif_wake_queue(dev);
- netif_wake_queue(priv->mesh_dev);
+
+ /* Used for both firmware TX and regular TX. priv isn't
+ * valid at firmware load time.
+ */
+ if (priv) {
+ wlan_adapter *adapter = priv->adapter;
+ 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);
+
+ if ((adapter->connect_status == LIBERTAS_CONNECTED)) {
+ netif_wake_queue(dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
}
+ } else {
+ /* print the failure status number for debug */
+ lbs_pr_info("URB in failure status: %d\n", urb->status);
}
return;
@@ -205,24 +216,35 @@ static int if_usb_probe(struct usb_interface *intf,
}
}
+ /* Upload firmware */
+ cardp->rinfo.cardp = cardp;
+ if (if_usb_prog_firmware(cardp)) {
+ lbs_deb_usbd(&udev->dev, "FW upload failed");
+ goto err_prog_firmware;
+ }
+
if (!(priv = libertas_add_card(cardp, &udev->dev)))
- goto dealloc;
+ goto err_prog_firmware;
- udev->dev.driver_data = priv;
+ cardp->priv = priv;
if (libertas_add_mesh(priv, &udev->dev))
goto err_add_mesh;
- priv->hw_register_dev = if_usb_register_dev;
- priv->hw_unregister_dev = if_usb_unregister_dev;
- priv->hw_prog_firmware = if_usb_prog_firmware;
+ cardp->eth_dev = priv->dev;
+
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;
priv->boot2_version = udev->descriptor.bcdDevice;
- if (libertas_activate_card(priv))
- goto err_activate_card;
+ /* Delay 200 ms to waiting for the FW ready */
+ if_usb_submit_rx_urb(cardp);
+ msleep_interruptible(200);
+ priv->adapter->fw_ready = 1;
+
+ if (libertas_start_card(priv))
+ goto err_start_card;
list_add_tail(&cardp->list, &usb_devices);
@@ -231,11 +253,12 @@ static int if_usb_probe(struct usb_interface *intf,
return 0;
-err_activate_card:
+err_start_card:
libertas_remove_mesh(priv);
err_add_mesh:
- free_netdev(priv->dev);
- kfree(priv->adapter);
+ libertas_remove_card(priv);
+err_prog_firmware:
+ if_usb_reset_device(cardp);
dealloc:
if_usb_free(cardp);
@@ -252,21 +275,22 @@ static void if_usb_disconnect(struct usb_interface *intf)
{
struct usb_card_rec *cardp = usb_get_intfdata(intf);
wlan_private *priv = (wlan_private *) cardp->priv;
- wlan_adapter *adapter = NULL;
- adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_MAIN);
- /*
- * Update Surprise removed to TRUE
- */
- adapter->surpriseremoved = 1;
+ /* Update Surprise removed to TRUE */
+ cardp->surprise_removed = 1;
list_del(&cardp->list);
- /* card is removed and we can call wlan_remove_card */
- lbs_deb_usbd(&cardp->udev->dev, "call remove card\n");
- libertas_remove_mesh(priv);
- libertas_remove_card(priv);
+ if (priv) {
+ wlan_adapter *adapter = priv->adapter;
+
+ adapter->surpriseremoved = 1;
+ libertas_stop_card(priv);
+ libertas_remove_mesh(priv);
+ libertas_remove_card(priv);
+ }
/* Unlink and free urb */
if_usb_free(cardp);
@@ -274,7 +298,7 @@ static void if_usb_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
usb_put_dev(interface_to_usbdev(intf));
- return;
+ lbs_deb_leave(LBS_DEB_MAIN);
}
/**
@@ -282,12 +306,11 @@ static void if_usb_disconnect(struct usb_interface *intf)
* @param priv pointer to wlan_private
* @return 0
*/
-static int if_prog_firmware(wlan_private * priv)
+static int if_prog_firmware(struct usb_card_rec *cardp)
{
- struct usb_card_rec *cardp = priv->card;
struct FWData *fwdata;
struct fwheader *fwheader;
- u8 *firmware = priv->firmware->data;
+ u8 *firmware = cardp->fw->data;
fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
@@ -335,7 +358,7 @@ static int if_prog_firmware(wlan_private * priv)
cardp->totalbytes);
*/
memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
- usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+ usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
} else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
/*
@@ -345,7 +368,7 @@ static int if_prog_firmware(wlan_private * priv)
"Donwloading FW JUMP BLOCK\n");
*/
memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
- usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+ usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
cardp->fwfinalblk = 1;
}
@@ -360,10 +383,10 @@ static int if_prog_firmware(wlan_private * priv)
return 0;
}
-static int if_usb_reset_device(wlan_private *priv)
+static int if_usb_reset_device(struct usb_card_rec *cardp)
{
int ret;
- struct usb_card_rec *cardp = priv->card;
+ wlan_private * priv = cardp->priv;
lbs_deb_enter(LBS_DEB_USB);
@@ -371,7 +394,7 @@ static int if_usb_reset_device(wlan_private *priv)
* command to the firmware.
*/
ret = usb_reset_device(cardp->udev);
- if (!ret) {
+ if (!ret && priv) {
msleep(10);
ret = libertas_reset_device(priv);
msleep(10);
@@ -389,14 +412,12 @@ static int if_usb_reset_device(wlan_private *priv)
* @param nb data length
* @return 0 or -1
*/
-static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
+static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb)
{
- /* pointer to card structure */
- struct usb_card_rec *cardp = priv->card;
int ret = -1;
/* check if device is removed */
- if (priv->adapter->surpriseremoved) {
+ if (cardp->surprise_removed) {
lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
goto tx_ret;
}
@@ -404,7 +425,7 @@ static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
usb_sndbulkpipe(cardp->udev,
cardp->bulk_out_endpointAddr),
- payload, nb, if_usb_write_bulk_callback, priv);
+ payload, nb, if_usb_write_bulk_callback, cardp);
cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
@@ -421,11 +442,9 @@ tx_ret:
return ret;
}
-static int __if_usb_submit_rx_urb(wlan_private * priv,
- void (*callbackfn)
- (struct urb *urb))
+static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp,
+ void (*callbackfn)(struct urb *urb))
{
- struct usb_card_rec *cardp = priv->card;
struct sk_buff *skb;
struct read_cb_info *rinfo = &cardp->rinfo;
int ret = -1;
@@ -461,22 +480,21 @@ rx_ret:
return ret;
}
-static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
+static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp)
{
- return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
+ return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
}
-static inline int if_usb_submit_rx_urb(wlan_private * priv)
+static int if_usb_submit_rx_urb(struct usb_card_rec *cardp)
{
- return __if_usb_submit_rx_urb(priv, &if_usb_receive);
+ return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
}
static void if_usb_receive_fwload(struct urb *urb)
{
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
- wlan_private *priv = rinfo->priv;
struct sk_buff *skb = rinfo->skb;
- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp;
struct fwsyncheader *syncfwheader;
struct bootcmdrespStr bootcmdresp;
@@ -492,7 +510,7 @@ static void if_usb_receive_fwload(struct urb *urb)
sizeof(bootcmdresp));
if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
kfree_skb(skb);
- if_usb_submit_rx_urb_fwload(priv);
+ if_usb_submit_rx_urb_fwload(cardp);
cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev,
"Received valid boot command response\n");
@@ -516,7 +534,7 @@ static void if_usb_receive_fwload(struct urb *urb)
"Received valid boot command response\n");
}
kfree_skb(skb);
- if_usb_submit_rx_urb_fwload(priv);
+ if_usb_submit_rx_urb_fwload(cardp);
return;
}
@@ -552,9 +570,9 @@ static void if_usb_receive_fwload(struct urb *urb)
goto exit;
}
- if_prog_firmware(priv);
+ if_prog_firmware(cardp);
- if_usb_submit_rx_urb_fwload(priv);
+ if_usb_submit_rx_urb_fwload(cardp);
exit:
kfree(syncfwheader);
@@ -633,9 +651,9 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
static void if_usb_receive(struct urb *urb)
{
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
- wlan_private *priv = rinfo->priv;
struct sk_buff *skb = rinfo->skb;
- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+ struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp;
+ wlan_private * priv = cardp->priv;
int recvlength = urb->actual_length;
u8 *recvbuff = NULL;
@@ -696,7 +714,7 @@ static void if_usb_receive(struct urb *urb)
}
setup_for_next:
- if_usb_submit_rx_urb(priv);
+ if_usb_submit_rx_urb(cardp);
rx_exit:
lbs_deb_leave(LBS_DEB_USB);
}
@@ -731,7 +749,7 @@ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 n
memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
- return usb_tx_block(priv, cardp->bulk_out_buffer,
+ return usb_tx_block(cardp, cardp->bulk_out_buffer,
nb + MESSAGE_HEADER_LEN);
}
@@ -751,46 +769,10 @@ static int if_usb_get_int_status(wlan_private * priv, u8 * ireg)
static int if_usb_read_event_cause(wlan_private * priv)
{
struct usb_card_rec *cardp = priv->card;
+
priv->adapter->eventcause = cardp->usb_event_cause;
/* Re-submit rx urb here to avoid event lost issue */
- if_usb_submit_rx_urb(priv);
- return 0;
-}
-
-static int if_usb_unregister_dev(wlan_private * priv)
-{
- int ret = 0;
-
- /* Need to send a Reset command to device before USB resources freed
- * and wlan_remove_card() called, then device can handle FW download
- * again.
- */
- if (priv)
- libertas_reset_device(priv);
-
- return ret;
-}
-
-
-/**
- * @brief This function register usb device and initialize parameter
- * @param priv pointer to wlan_private
- * @return 0 or -1
- */
-static int if_usb_register_dev(wlan_private * priv)
-{
- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
-
- lbs_deb_enter(LBS_DEB_USB);
-
- cardp->priv = priv;
- cardp->eth_dev = priv->dev;
- priv->hotplug_device = &(cardp->udev->dev);
-
- lbs_deb_usbd(&cardp->udev->dev, "udev pointer is at %p\n",
- cardp->udev);
-
- lbs_deb_leave(LBS_DEB_USB);
+ if_usb_submit_rx_urb(cardp);
return 0;
}
@@ -800,10 +782,9 @@ static int if_usb_register_dev(wlan_private * priv)
* 2:Boot from FW in EEPROM
* @return 0
*/
-static int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
+static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue)
{
- struct usb_card_rec *cardp = priv->card;
- struct bootcmdstr sbootcmd;
+ struct bootcmdstr sbootcmd;
int i;
/* Prepare command */
@@ -814,28 +795,83 @@ static int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
/* Issue command */
- usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
+ usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
return 0;
}
-static int if_usb_do_prog_firmware(wlan_private * priv)
+/**
+ * @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)
{
- struct usb_card_rec *cardp = priv->card;
int i = 0;
static int reset_count = 10;
int ret = 0;
lbs_deb_enter(LBS_DEB_USB);
- cardp->rinfo.priv = priv;
+ if ((ret = request_firmware(&cardp->fw, libertas_fw_name,
+ &cardp->udev->dev)) < 0) {
+ lbs_pr_err("request_firmware() failed with %#x\n", ret);
+ lbs_pr_err("firmware %s not found\n", libertas_fw_name);
+ goto done;
+ }
+
+ if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
+ goto release_fw;
restart:
- if (if_usb_submit_rx_urb_fwload(priv) < 0) {
+ if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
ret = -1;
- goto done;
+ goto release_fw;
}
cardp->bootcmdresp = 0;
@@ -843,7 +879,7 @@ restart:
int j = 0;
i++;
/* Issue Boot command = 1, Boot from Download-FW */
- if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
+ if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
/* wait for command response */
do {
j++;
@@ -853,14 +889,13 @@ restart:
if (cardp->bootcmdresp == 0) {
if (--reset_count >= 0) {
- if_usb_reset_device(priv);
+ if_usb_reset_device(cardp);
goto restart;
}
return -1;
}
i = 0;
- priv->adapter->fw_ready = 0;
cardp->totalbytes = 0;
cardp->fwlastblksent = 0;
@@ -870,113 +905,37 @@ restart:
cardp->totalbytes = 0;
cardp->fwfinalblk = 0;
- if_prog_firmware(priv);
+ if_prog_firmware(cardp);
do {
lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n");
i++;
msleep_interruptible(100);
- if (priv->adapter->surpriseremoved || i >= 20)
+ if (cardp->surprise_removed || i >= 20)
break;
} while (!cardp->fwdnldover);
if (!cardp->fwdnldover) {
lbs_pr_info("failed to load fw, resetting device!\n");
if (--reset_count >= 0) {
- if_usb_reset_device(priv);
+ if_usb_reset_device(cardp);
goto restart;
}
lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
ret = -1;
- goto done;
+ goto release_fw;
}
- if_usb_submit_rx_urb(priv);
-
- /* Delay 200 ms to waiting for the FW ready */
- msleep_interruptible(200);
-
- priv->adapter->fw_ready = 1;
+release_fw:
+ release_firmware(cardp->fw);
+ cardp->fw = NULL;
done:
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
return ret;
}
-/**
- * @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(wlan_private *priv)
-{
- int ret = -1;
-
- lbs_deb_enter(LBS_DEB_FW);
-
- if ((ret = request_firmware(&priv->firmware, libertas_fw_name,
- priv->hotplug_device)) < 0) {
- lbs_pr_err("request_firmware() failed with %#x\n", ret);
- lbs_pr_err("firmware %s not found\n", libertas_fw_name);
- goto done;
- }
-
- if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
- release_firmware(priv->firmware);
- goto done;
- }
-
- ret = if_usb_do_prog_firmware(priv);
-
- release_firmware(priv->firmware);
-done:
- return ret;
-}
-
#ifdef CONFIG_PM
static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)