/** * @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) { struct if_usb_card *cardp = (struct if_usb_card *) urb->context; /* handle the transmission complete validations */ if (urb->status == 0) { struct lbs_private *priv = cardp->priv; 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); /* Used for both firmware TX and regular TX. priv isn't * valid at firmware load time. */ if (priv) lbs_host_to_card_done(priv); } else { /* print the failure status number for debug */ lbs_pr_info("URB in failure status: %d\n", urb->status); } return; }
/** * @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) { struct if_usb_card *cardp = (struct if_usb_card *) urb->context; /* handle the transmission complete validations */ if (urb->status == 0) { struct lbs_private *priv = cardp->priv; 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); /* Boot commands such as UPDATE_FW and UPDATE_BOOT2 are not * passed up to the lbs level. */ if (priv && priv->dnld_sent != DNLD_BOOTCMD_SENT) lbs_host_to_card_done(priv); } else { /* print the failure status number for debug */ lbs_pr_info("URB in failure status: %d\n", urb->status); } return; }
/** * @brief This function transfer the data to the device. * @param priv pointer to struct lbs_private * @param payload pointer to payload data * @param nb data length * @return 0 or -1 */ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb) { int ret = -1; /* check if device is removed */ if (cardp->surprise_removed) { lbs_deb_usbd(&cardp->udev->dev, "Device removed\n"); goto tx_ret; } usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, usb_sndbulkpipe(cardp->udev, cardp->ep_out), payload, nb, if_usb_write_bulk_callback, cardp); cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret); ret = -1; } else { lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n"); ret = 0; } tx_ret: return ret; }
/** * @brief This function download FW * @param priv pointer to struct lbs_private * @return 0 */ static int if_usb_send_fw_pkt(struct if_usb_card *cardp) { struct fwdata *fwdata = cardp->ep_out_buf; const uint8_t *firmware = cardp->fw->data; /* If we got a CRC failure on the last block, back up and retry it */ if (!cardp->CRC_OK) { cardp->totalbytes = cardp->fwlastblksent; cardp->fwseqnum--; } lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n", cardp->totalbytes); /* 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], sizeof(struct fwheader)); cardp->fwlastblksent = cardp->totalbytes; cardp->totalbytes += sizeof(struct fwheader); memcpy(fwdata->data, &firmware[cardp->totalbytes], le32_to_cpu(fwdata->hdr.datalength)); lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n", le32_to_cpu(fwdata->hdr.datalength)); fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum); cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength); 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"); cardp->fwfinalblk = 1; } lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n", cardp->totalbytes); return 0; }
static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, void (*callbackfn)(struct urb *urb)) { 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; } cardp->rx_skb = skb; /* Fill the receive configuration URB and initialise the Rx call back */ usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, usb_rcvbulkpipe(cardp->udev, cardp->ep_in), (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET), MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp); cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret); kfree_skb(skb); cardp->rx_skb = NULL; ret = -1; } else { lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n"); ret = 0; } rx_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 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; }