diff options
-rw-r--r-- | drivers/net/wireless/libertas/decl.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/dev.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_cs.c | 54 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_usb.c | 365 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_usb.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 405 |
6 files changed, 334 insertions, 501 deletions
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 095edf6a4c29..87fea9d5b90a 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -72,8 +72,9 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no); wlan_private *libertas_add_card(void *card, struct device *dmdev); -int libertas_activate_card(wlan_private *priv); int libertas_remove_card(wlan_private *priv); +int libertas_start_card(wlan_private *priv); +int libertas_stop_card(wlan_private *priv); int libertas_add_mesh(wlan_private *priv, struct device *dev); void libertas_remove_mesh(wlan_private *priv); int libertas_reset_device(wlan_private *priv); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index a3c94d7388ab..1fb807aa91b9 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -143,7 +143,6 @@ struct _wlan_private { all other bits reserved 0 */ u8 dnld_sent; - const struct firmware *firmware; struct device *hotplug_device; /** thread to service interrupts */ @@ -156,9 +155,6 @@ struct _wlan_private { struct work_struct sync_channel; /** Hardware access */ - int (*hw_register_dev) (wlan_private * priv); - int (*hw_unregister_dev) (wlan_private *); - int (*hw_prog_firmware) (wlan_private *); int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb); int (*hw_get_int_status) (wlan_private * priv, u8 *); int (*hw_read_event_cause) (wlan_private *); diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 888f023a74e1..4dffc5cc0d1a 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -608,51 +608,6 @@ done: /* Callback functions for libertas.ko */ /********************************************************************/ -static int if_cs_register_dev(wlan_private *priv) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - - lbs_deb_enter(LBS_DEB_CS); - - card->priv = priv; - - return 0; -} - - -static int if_cs_unregister_dev(wlan_private *priv) -{ - lbs_deb_enter(LBS_DEB_CS); - - /* - * Nothing special here. Because the device's power gets turned off - * anyway, there's no need to send a RESET command like in if_usb.c - */ - - return 0; -} - - -/* - * This callback is a dummy. The reason is that the USB code needs - * to have various things set up in order to be able to download the - * firmware. That's not needed in our case. - * - * On the contrary, if libertas_add_card() has been called and we're - * then later called via libertas_activate_card(), but without a valid - * firmware, then it's quite tedious to tear down the half-installed - * card. Therefore, we download the firmware before calling adding/ - * activating the card in the first place. If that doesn't work, we - * won't call into libertas.ko at all. - */ - -static int if_cs_prog_firmware(wlan_private *priv) -{ - priv->adapter->fw_ready = 1; - return 0; -} - - /* Send commands or data packets to the card */ static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) { @@ -902,14 +857,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev) } /* Store pointers to our call-back functions */ + card->priv = priv; priv->card = card; - priv->hw_register_dev = if_cs_register_dev; - priv->hw_unregister_dev = if_cs_unregister_dev; - priv->hw_prog_firmware = if_cs_prog_firmware; priv->hw_host_to_card = if_cs_host_to_card; priv->hw_get_int_status = if_cs_get_int_status; priv->hw_read_event_cause = if_cs_read_event_cause; + priv->adapter->fw_ready = 1; + /* Now actually get the IRQ */ ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt, IRQF_SHARED, DRV_NAME, card); @@ -919,7 +874,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) } /* And finally bring the card up */ - if (libertas_activate_card(priv) != 0) { + if (libertas_start_card(priv) != 0) { lbs_pr_err("could not activate card\n"); goto out3; } @@ -951,6 +906,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev) lbs_deb_enter(LBS_DEB_CS); + libertas_stop_card(card->priv); libertas_remove_card(card->priv); if_cs_release(p_dev); kfree(card); diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 364eae374b93..105a00a7025d 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) diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index 8b3b4f1e47f6..e07a10ed28b5 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -38,7 +38,7 @@ struct bootcmdrespStr /* read callback private data */ struct read_cb_info { - wlan_private *priv; + struct usb_card_rec *cardp; struct sk_buff *skb; }; @@ -58,6 +58,7 @@ struct usb_card_rec { int bulk_out_size; u8 bulk_out_endpointAddr; + const struct firmware *fw; u8 CRC_OK; u32 fwseqnum; u32 lastseqnum; @@ -65,6 +66,7 @@ struct usb_card_rec { u32 fwlastblksent; u8 fwdnldover; u8 fwfinalblk; + u8 surprise_removed; u32 usb_event_cause; u8 usb_int_cause; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ce1c18ee6280..6304bd97d399 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -791,7 +791,6 @@ static int libertas_thread(void *data) } else spin_unlock_irq(&adapter->driver_lock); - lbs_deb_thread( "main-thread 222 (waking up): intcounter=%d currenttxskb=%p " "dnld_sent=%d\n", adapter->intcounter, @@ -926,7 +925,7 @@ static int libertas_thread(void *data) * @param priv A pointer to wlan_private structure * @return 0 or -1 */ -static int wlan_setup_station_hw(wlan_private * priv) +static int wlan_setup_firmware(wlan_private * priv) { int ret = -1; wlan_adapter *adapter = priv->adapter; @@ -934,14 +933,6 @@ static int wlan_setup_station_hw(wlan_private * priv) lbs_deb_enter(LBS_DEB_FW); - ret = priv->hw_prog_firmware(priv); - - if (ret) { - lbs_deb_fw("bootloader in invalid state\n"); - ret = -1; - goto done; - } - /* * Read MAC address from HW */ @@ -992,8 +983,6 @@ done: return ret; } -static void command_timer_fn(unsigned long data); - /** * This function handles the timeout of command sending. * It will re-send the same command again. @@ -1035,155 +1024,99 @@ static void command_timer_fn(unsigned long data) return; } -static void libertas_free_adapter(wlan_private * priv) +static int libertas_init_adapter(wlan_private * priv) { wlan_adapter *adapter = priv->adapter; - - if (!adapter) { - lbs_deb_fw("why double free adapter?\n"); - return; - } - - lbs_deb_fw("free command buffer\n"); - libertas_free_cmd_buffer(priv); - - lbs_deb_fw("free command_timer\n"); - del_timer(&adapter->command_timer); - - lbs_deb_fw("free scan results table\n"); - kfree(adapter->networks); - adapter->networks = NULL; - - /* Free the adapter object itself */ - lbs_deb_fw("free adapter\n"); - kfree(adapter); - priv->adapter = NULL; -} - -static int wlan_allocate_adapter(wlan_private * priv) -{ size_t bufsize; - wlan_adapter *adapter = priv->adapter; + int i, ret = 0; /* Allocate buffer to store the BSSID list */ bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); adapter->networks = kzalloc(bufsize, GFP_KERNEL); if (!adapter->networks) { lbs_pr_err("Out of memory allocating beacons\n"); - libertas_free_adapter(priv); - return -ENOMEM; + ret = -1; + goto out; } - /* Allocate the command buffers */ - libertas_allocate_cmd_buffer(priv); + /* Initialize scan result lists */ + INIT_LIST_HEAD(&adapter->network_free_list); + INIT_LIST_HEAD(&adapter->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) { + list_add_tail(&adapter->networks[i].list, + &adapter->network_free_list); + } - memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); adapter->libertas_ps_confirm_sleep.command = cpu_to_le16(CMD_802_11_PS_MODE); adapter->libertas_ps_confirm_sleep.size = cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.result = 0; adapter->libertas_ps_confirm_sleep.action = cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); - return 0; -} - -static void wlan_init_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int i; - - adapter->connect_status = LIBERTAS_DISCONNECTED; memset(adapter->current_addr, 0xff, ETH_ALEN); - /* 802.11 specific */ - adapter->secinfo.wep_enabled = 0; - for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); - i++) - memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key)); - adapter->wep_tx_keyidx = 0; + adapter->connect_status = LIBERTAS_DISCONNECTED; adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; adapter->mode = IW_MODE_INFRA; - - adapter->pending_assoc_req = NULL; - adapter->in_progress_assoc_req = NULL; - - /* Initialize scan result lists */ - INIT_LIST_HEAD(&adapter->network_free_list); - INIT_LIST_HEAD(&adapter->network_list); - for (i = 0; i < MAX_NETWORK_COUNT; i++) { - list_add_tail(&adapter->networks[i].list, - &adapter->network_free_list); - } - - mutex_init(&adapter->lock); - - memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; - - /* PnP and power profile */ - adapter->surpriseremoved = 0; - - adapter->currentpacketfilter = - CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; - + adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; adapter->radioon = RADIO_ON; - adapter->auto_rate = 1; - adapter->cur_rate = 0; - - // set default capabilities adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; - adapter->psmode = WLAN802_11POWERMODECAM; - adapter->psstate = PS_STATE_FULL_POWER; - adapter->needtowakeup = 0; - adapter->intcounter = 0; - - adapter->currenttxskb = NULL; + mutex_init(&adapter->lock); memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); adapter->tx_queue_idx = 0; spin_lock_init(&adapter->txqueue_lock); - return; -} + setup_timer(&adapter->command_timer, command_timer_fn, + (unsigned long)priv); -static int libertas_init_fw(wlan_private * priv) -{ - int ret = -1; - wlan_adapter *adapter = priv->adapter; + INIT_LIST_HEAD(&adapter->cmdfreeq); + INIT_LIST_HEAD(&adapter->cmdpendingq); - lbs_deb_enter(LBS_DEB_FW); + spin_lock_init(&adapter->driver_lock); + init_waitqueue_head(&adapter->cmd_pending); + adapter->nr_cmd_pending = 0; - /* Allocate adapter structure */ - if ((ret = wlan_allocate_adapter(priv)) != 0) - goto done; + /* Allocate the command buffers */ + if (libertas_allocate_cmd_buffer(priv)) { + lbs_pr_err("Out of memory allocating command buffers\n"); + ret = -1; + } - /* init adapter structure */ - wlan_init_adapter(priv); +out: + return ret; +} - /* init timer etc. */ - setup_timer(&adapter->command_timer, command_timer_fn, - (unsigned long)priv); +static void libertas_free_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; - /* download fimrware etc. */ - if ((ret = wlan_setup_station_hw(priv)) != 0) { - del_timer_sync(&adapter->command_timer); - goto done; + if (!adapter) { + lbs_deb_fw("why double free adapter?\n"); + return; } - /* init 802.11d */ - libertas_init_11d(priv); + lbs_deb_fw("free command buffer\n"); + libertas_free_cmd_buffer(priv); - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); - return ret; + lbs_deb_fw("free command_timer\n"); + del_timer(&adapter->command_timer); + + lbs_deb_fw("free scan results table\n"); + kfree(adapter->networks); + adapter->networks = NULL; + + /* Free the adapter object itself */ + lbs_deb_fw("free adapter\n"); + kfree(adapter); + priv->adapter = NULL; } /** @@ -1203,9 +1136,9 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) /* Allocate an Ethernet device and register it */ if (!(dev = alloc_etherdev(sizeof(wlan_private)))) { lbs_pr_err("init ethX device failed\n"); - return NULL; + goto done; } - priv = dev->priv; + dmdev->driver_data = priv = dev->priv; /* allocate buffer for wlan_adapter */ if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) { @@ -1213,10 +1146,16 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) goto err_kzalloc; } + if (libertas_init_adapter(priv)) { + lbs_pr_err("failed to initialize adapter structure.\n"); + goto err_init_adapter; + } + priv->dev = dev; priv->card = card; priv->mesh_open = 0; priv->infra_open = 0; + priv->hotplug_device = dmdev; SET_MODULE_OWNER(dev); @@ -1239,87 +1178,144 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) SET_NETDEV_DEV(dev, dmdev); - INIT_LIST_HEAD(&priv->adapter->cmdfreeq); - INIT_LIST_HEAD(&priv->adapter->cmdpendingq); - - spin_lock_init(&priv->adapter->driver_lock); - init_waitqueue_head(&priv->adapter->cmd_pending); - priv->adapter->nr_cmd_pending = 0; priv->rtap_net_dev = NULL; if (device_create_file(dmdev, &dev_attr_libertas_rtap)) - goto err_kzalloc; + goto err_init_adapter; + + lbs_deb_thread("Starting main thread...\n"); + init_waitqueue_head(&priv->waitq); + priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main"); + if (IS_ERR(priv->main_thread)) { + lbs_deb_thread("Error creating main thread.\n"); + goto err_kthread_run; + } + + priv->work_thread = create_singlethread_workqueue("libertas_worker"); + INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); + INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker); + INIT_WORK(&priv->sync_channel, libertas_sync_channel); + goto done; +err_kthread_run: + device_remove_file(dmdev, &dev_attr_libertas_rtap); + +err_init_adapter: + libertas_free_adapter(priv); + err_kzalloc: free_netdev(dev); priv = NULL; + done: lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv); return priv; } EXPORT_SYMBOL_GPL(libertas_add_card); -int libertas_activate_card(wlan_private *priv) + +int libertas_remove_card(wlan_private *priv) { + wlan_adapter *adapter = priv->adapter; struct net_device *dev = priv->dev; - int ret = -1; + union iwreq_data wrqu; lbs_deb_enter(LBS_DEB_MAIN); - lbs_deb_thread("Starting main thread...\n"); - init_waitqueue_head(&priv->waitq); - priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main"); - if (IS_ERR(priv->main_thread)) { - lbs_deb_thread("Error creating main thread.\n"); - goto done; - } + libertas_remove_rtap(priv); - priv->work_thread = create_singlethread_workqueue("libertas_worker"); - INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); - INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker); + dev = priv->dev; + device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); - INIT_WORK(&priv->sync_channel, libertas_sync_channel); + cancel_delayed_work(&priv->scan_work); + cancel_delayed_work(&priv->assoc_work); + destroy_workqueue(priv->work_thread); - /* - * Register the device. Fillup the private data structure with - * relevant information from the card and request for the required - * IRQ. - */ - if (priv->hw_register_dev(priv) < 0) { - lbs_pr_err("failed to register WLAN device\n"); - goto err_registerdev; + if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { + adapter->psmode = WLAN802_11POWERMODECAM; + libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } - /* init FW and HW */ - if (libertas_init_fw(priv)) { - lbs_pr_err("firmware init failed\n"); - goto err_registerdev; - } + memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + + /* Stop the thread servicing the interrupts */ + adapter->surpriseremoved = 1; + kthread_stop(priv->main_thread); + + libertas_free_adapter(priv); + + priv->dev = NULL; + free_netdev(dev); + + lbs_deb_leave(LBS_DEB_MAIN); + return 0; +} +EXPORT_SYMBOL_GPL(libertas_remove_card); + + +int libertas_start_card(wlan_private *priv) +{ + struct net_device *dev = priv->dev; + int ret = -1; + + lbs_deb_enter(LBS_DEB_MAIN); + + /* poke the firmware */ + ret = wlan_setup_firmware(priv); + if (ret) + goto done; + + /* init 802.11d */ + libertas_init_11d(priv); if (register_netdev(dev)) { lbs_pr_err("cannot register ethX device\n"); - goto err_init_fw; + goto done; } - lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); - libertas_debugfs_init_one(priv, dev); + lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); + ret = 0; - goto done; -err_init_fw: - priv->hw_unregister_dev(priv); -err_registerdev: - destroy_workqueue(priv->work_thread); - /* Stop the thread servicing the interrupts */ - wake_up_interruptible(&priv->waitq); - kthread_stop(priv->main_thread); done: - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(libertas_activate_card); +EXPORT_SYMBOL_GPL(libertas_start_card); + + +int libertas_stop_card(wlan_private *priv) +{ + struct net_device *dev = priv->dev; + int ret = -1; + struct cmd_ctrl_node *cmdnode; + unsigned long flags; + + lbs_deb_enter(LBS_DEB_MAIN); + + netif_stop_queue(priv->dev); + netif_carrier_off(priv->dev); + + libertas_debugfs_remove_one(priv); + + /* Flush pending command nodes */ + spin_lock_irqsave(&priv->adapter->driver_lock, flags); + list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { + cmdnode->cmdwaitqwoken = 1; + wake_up_interruptible(&cmdnode->cmdwait_q); + } + spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); + + unregister_netdev(dev); + + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); + return ret; +} +EXPORT_SYMBOL_GPL(libertas_stop_card); /** @@ -1389,89 +1385,12 @@ done: } EXPORT_SYMBOL_GPL(libertas_add_mesh); -static void wake_pending_cmdnodes(wlan_private *priv) -{ - struct cmd_ctrl_node *cmdnode; - unsigned long flags; - - lbs_deb_enter(LBS_DEB_HOST); - - spin_lock_irqsave(&priv->adapter->driver_lock, flags); - list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { - cmdnode->cmdwaitqwoken = 1; - wake_up_interruptible(&cmdnode->cmdwait_q); - } - spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); -} - - -int libertas_remove_card(wlan_private *priv) -{ - wlan_adapter *adapter; - struct net_device *dev; - union iwreq_data wrqu; - - lbs_deb_enter(LBS_DEB_NET); - - libertas_remove_rtap(priv); - if (!priv) - goto out; - - adapter = priv->adapter; - - if (!adapter) - goto out; - - dev = priv->dev; - device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); - - netif_stop_queue(priv->dev); - netif_carrier_off(priv->dev); - - wake_pending_cmdnodes(priv); - - unregister_netdev(dev); - - cancel_delayed_work(&priv->scan_work); - cancel_delayed_work(&priv->assoc_work); - destroy_workqueue(priv->work_thread); - - if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { - adapter->psmode = WLAN802_11POWERMODECAM; - libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); - } - - memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - adapter->surpriseremoved = 1; - - /* Stop the thread servicing the interrupts */ - kthread_stop(priv->main_thread); - - libertas_debugfs_remove_one(priv); - - lbs_deb_net("free adapter\n"); - libertas_free_adapter(priv); - - lbs_deb_net("unregister finish\n"); - - priv->dev = NULL; - free_netdev(dev); - -out: - lbs_deb_leave(LBS_DEB_NET); - return 0; -} -EXPORT_SYMBOL_GPL(libertas_remove_card); - void libertas_remove_mesh(wlan_private *priv) { struct net_device *mesh_dev; - lbs_deb_enter(LBS_DEB_NET); + lbs_deb_enter(LBS_DEB_MAIN); if (!priv) goto out; @@ -1488,7 +1407,7 @@ void libertas_remove_mesh(wlan_private *priv) free_netdev(mesh_dev); out: - lbs_deb_leave(LBS_DEB_NET); + lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(libertas_remove_mesh); |