static void if_usb_receive_fwload(struct urb *urb) { struct if_usb_card *cardp = urb->context; struct sk_buff *skb = cardp->rx_skb; struct fwsyncheader *syncfwheader; struct bootcmdresp bootcmdresp; if (urb->status) { lbs_deb_usbd(&cardp->udev->dev, "URB status is failed during fw load\n"); kfree_skb(skb); return; } 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 { lbs_deb_usb("Waiting for confirmation; got %x %x\n", le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1])); if_usb_submit_rx_urb_fwload(cardp); } kfree_skb(skb); return; } if (cardp->bootcmdresp <= 0) { memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET, sizeof(bootcmdresp)); if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { kfree_skb(skb); if_usb_submit_rx_urb_fwload(cardp); cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, "Received valid boot command response\n"); return; } 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)) { if (!cardp->bootcmdresp) lbs_pr_info("Firmware already seems alive; resetting\n"); cardp->bootcmdresp = -1; } else { lbs_pr_info("boot cmd response wrong magic number (0x%x)\n", le32_to_cpu(bootcmdresp.magic)); } } 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); } else { cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, "Received valid boot command response\n"); } kfree_skb(skb); if_usb_submit_rx_urb_fwload(cardp); return; } syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC); if (!syncfwheader) { lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n"); kfree_skb(skb); return; } memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET, sizeof(struct fwsyncheader)); if (!syncfwheader->cmd) { 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)); cardp->CRC_OK = 1; } else { lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n"); cardp->CRC_OK = 0; } kfree_skb(skb); /* reschedule timer for 200ms hence */ mod_timer(&cardp->fw_timeout, jiffies + (HZ/5)); if (cardp->fwfinalblk) { cardp->fwdnldover = 1; goto exit; } if_usb_send_fw_pkt(cardp); exit: if_usb_submit_rx_urb_fwload(cardp); kfree(syncfwheader); return; }
static int if_usb_prog_firmware(wlan_private * priv) { 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; restart: if (if_usb_submit_rx_urb_fwload(priv) < 0) { lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); ret = -1; goto done; } cardp->bootcmdresp = 0; do { int j = 0; i++; /* Issue Boot command = 1, Boot from Download-FW */ if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB); /* wait for command response */ do { j++; msleep_interruptible(100); } while (cardp->bootcmdresp == 0 && j < 10); } while (cardp->bootcmdresp == 0 && i < 5); if (cardp->bootcmdresp == 0) { if (--reset_count >= 0) { libertas_do_reset(priv); goto restart; } return -1; } i = 0; priv->adapter->fw_ready = 0; cardp->totalbytes = 0; cardp->fwlastblksent = 0; cardp->CRC_OK = 1; cardp->fwdnldover = 0; cardp->fwseqnum = -1; cardp->totalbytes = 0; cardp->fwfinalblk = 0; if_prog_firmware(priv); do { lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); i++; msleep_interruptible(100); if (priv->adapter->surpriseremoved || i >= 20) break; } while (!cardp->fwdnldover); if (!cardp->fwdnldover) { lbs_pr_info("failed to load fw, resetting device!\n"); if (--reset_count >= 0) { libertas_do_reset(priv); goto restart; } lbs_pr_info("FW download failure, time = %d ms\n", i * 100); ret = -1; goto done; } if_usb_submit_rx_urb(priv); /* Delay 200 ms to waiting for the FW ready */ msleep_interruptible(200); priv->adapter->fw_ready = 1; done: lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); return ret; }
static void if_usb_receive_fwload(struct urb *urb) { struct if_usb_card *cardp = urb->context; struct sk_buff *skb = cardp->rx_skb; struct fwsyncheader *syncfwheader; struct bootcmdresp bcmdresp; if (urb->status) { kfree_skb(skb); return; } if (cardp->fwdnldover) { __le32 *tmp = (__le32 *)(skb->data); if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) && tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) /* Firmware ready event received */ wake_up(&cardp->fw_wq); else if_usb_submit_rx_urb_fwload(cardp); kfree_skb(skb); return; } if (cardp->bootcmdresp <= 0) { memcpy(&bcmdresp, skb->data, sizeof(bcmdresp)); if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { kfree_skb(skb); if_usb_submit_rx_urb_fwload(cardp); cardp->bootcmdresp = 1; /* Received valid boot command response */ return; } if (bcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) { if (bcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) || bcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) || bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) cardp->bootcmdresp = -1; } else if (bcmdresp.cmd == BOOT_CMD_FW_BY_USB && bcmdresp.result == BOOT_CMD_RESP_OK) cardp->bootcmdresp = 1; kfree_skb(skb); if_usb_submit_rx_urb_fwload(cardp); return; } syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC); if (!syncfwheader) { kfree_skb(skb); return; } memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader)); if (!syncfwheader->cmd) cardp->CRC_OK = 1; else cardp->CRC_OK = 0; kfree_skb(skb); /* reschedule timer for 200ms hence */ mod_timer(&cardp->fw_timeout, jiffies + (HZ/5)); if (cardp->fwfinalblk) { cardp->fwdnldover = 1; goto exit; } if_usb_send_fw_pkt(cardp); exit: if_usb_submit_rx_urb_fwload(cardp); kfree(syncfwheader); return; }
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 fwsyncheader *syncfwheader; struct bootcmdrespStr bootcmdresp; if (urb->status) { lbs_deb_usbd(&cardp->udev->dev, "URB status is failed during fw load\n"); kfree_skb(skb); return; } if (cardp->bootcmdresp == 0) { memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET, sizeof(bootcmdresp)); if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { kfree_skb(skb); if_usb_submit_rx_urb_fwload(priv); cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, "Received valid boot command response\n"); return; } if (bootcmdresp.u32magicnumber != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) { lbs_pr_info( "boot cmd response wrong magic number (0x%x)\n", le32_to_cpu(bootcmdresp.u32magicnumber)); } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) { lbs_pr_info( "boot cmd response cmd_tag error (%d)\n", bootcmdresp.u8cmd_tag); } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) { lbs_pr_info( "boot cmd response result error (%d)\n", bootcmdresp.u8result); } else { cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, "Received valid boot command response\n"); } kfree_skb(skb); if_usb_submit_rx_urb_fwload(priv); return; } syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC); if (!syncfwheader) { lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n"); kfree_skb(skb); return; } memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET, sizeof(struct fwsyncheader)); if (!syncfwheader->cmd) { /* lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with correct CRC\n"); lbs_deb_usbd(&cardp->udev->dev, "FW received Blk seqnum = %d\n", syncfwheader->seqnum); */ cardp->CRC_OK = 1; } else { lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n"); cardp->CRC_OK = 0; } kfree_skb(skb); if (cardp->fwfinalblk) { cardp->fwdnldover = 1; goto exit; } if_prog_firmware(priv); if_usb_submit_rx_urb_fwload(priv); exit: kfree(syncfwheader); return; }