📄 if_usb.c
字号:
"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_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(cardp); if_usb_submit_rx_urb_fwload(cardp);exit: kfree(syncfwheader); return;}#define MRVDRV_MIN_PKT_LEN 30static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, struct usb_card_rec *cardp, wlan_private *priv){ 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"); kfree_skb(skb); return; } skb_reserve(skb, IPFIELD_ALIGN_OFFSET); skb_put(skb, recvlength); skb_pull(skb, MESSAGE_HEADER_LEN); libertas_process_rxed_packet(priv, skb); priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);}static inline void process_cmdrequest(int recvlength, u8 *recvbuff, struct sk_buff *skb, struct usb_card_rec *cardp, wlan_private *priv){ u8 *cmdbuf; if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) { lbs_deb_usbd(&cardp->udev->dev, "The receive buffer is too large\n"); kfree_skb(skb); return; } if (!in_interrupt()) BUG(); spin_lock(&priv->adapter->driver_lock); /* take care of cur_cmd = NULL case by reading the * data to clear the interrupt */ if (!priv->adapter->cur_cmd) { cmdbuf = priv->upld_buf; priv->adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; } else cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY; priv->upld_len = (recvlength - MESSAGE_HEADER_LEN); memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len); kfree_skb(skb); libertas_interrupt(priv->dev); spin_unlock(&priv->adapter->driver_lock); lbs_deb_usbd(&cardp->udev->dev, "Wake up main thread to handle cmd response\n"); return;}/** * @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){ struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; struct sk_buff *skb = rinfo->skb; struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp; wlan_private * priv = cardp->priv; int recvlength = urb->actual_length; u8 *recvbuff = NULL; u32 recvtype = 0; lbs_deb_enter(LBS_DEB_USB); if (recvlength) { __le32 tmp; if (urb->status) { lbs_deb_usbd(&cardp->udev->dev, "URB status is failed\n"); kfree_skb(skb); goto setup_for_next; } recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; memcpy(&tmp, recvbuff, sizeof(u32)); recvtype = le32_to_cpu(tmp); lbs_deb_usbd(&cardp->udev->dev, "Recv length = 0x%x, Recv type = 0x%X\n", recvlength, recvtype); } else if (urb->status) goto rx_exit; 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 */ spin_lock(&priv->adapter->driver_lock); cardp->usb_event_cause = le32_to_cpu(*(__le32 *) (recvbuff + MESSAGE_HEADER_LEN)); lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n", cardp->usb_event_cause); if (cardp->usb_event_cause & 0xffff0000) { libertas_send_tx_feedback(priv); spin_unlock(&priv->adapter->driver_lock); break; } cardp->usb_event_cause <<= 3; cardp->usb_int_cause |= MRVDRV_CARDEVENT; kfree_skb(skb); libertas_interrupt(priv->dev); spin_unlock(&priv->adapter->driver_lock); goto rx_exit; default: lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n", recvtype); kfree_skb(skb); break; }setup_for_next: if_usb_submit_rx_urb(cardp);rx_exit: lbs_deb_leave(LBS_DEB_USB);}/** * @brief This function downloads data to FW * @param priv pointer to wlan_private structure * @param type type of data * @param buf pointer to data buffer * @param len number of bytes * @return 0 or -1 */static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb){ struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type); lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb); if (type == MVMS_CMD) { __le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST); priv->dnld_sent = DNLD_CMD_SENT; memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, MESSAGE_HEADER_LEN); } else { __le32 tmp = cpu_to_le32(CMD_TYPE_DATA); priv->dnld_sent = DNLD_DATA_SENT; memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, MESSAGE_HEADER_LEN); } memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); return usb_tx_block(cardp, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);}/* called with adapter->driver_lock held */static int if_usb_get_int_status(wlan_private * priv, u8 * ireg){ struct usb_card_rec *cardp = priv->card; *ireg = cardp->usb_int_cause; cardp->usb_int_cause = 0; lbs_deb_usbd(&cardp->udev->dev,"Int cause is 0x%X\n", *ireg); return 0;}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(cardp); return 0;}/** * @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 */static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue){ struct bootcmdstr sbootcmd; int i; /* Prepare command */ sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); sbootcmd.u8cmd_tag = ivalue; for (i=0; i<11; i++) sbootcmd.au8dumy[i]=0x00; memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); /* Issue command */ usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); return 0;}/** * @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){ int i = 0; static int reset_count = 10; int ret = 0; lbs_deb_enter(LBS_DEB_USB); 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(cardp) < 0) { lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); ret = -1; goto release_fw; } cardp->bootcmdresp = 0; do { int j = 0; i++; /* Issue Boot command = 1, Boot from Download-FW */ if_usb_issue_boot_command(cardp, 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) { if_usb_reset_device(cardp); 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; if_prog_firmware(cardp); do { lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); i++; msleep_interruptible(100); 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(cardp); goto restart; } lbs_pr_info("FW download failure, time = %d ms\n", i * 100); ret = -1; goto release_fw; }release_fw: release_firmware(cardp->fw); cardp->fw = NULL;done: lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); return ret;}#ifdef CONFIG_PMstatic int if_usb_suspend(struct usb_interface *intf, pm_message_t message){ struct usb_card_rec *cardp = usb_get_intfdata(intf); wlan_private *priv = cardp->priv; lbs_deb_enter(LBS_DEB_USB); if (priv->adapter->psstate != PS_STATE_FULL_POWER) return -1; if (priv->mesh_dev && !priv->mesh_autostart_enabled) { /* Mesh autostart must be activated while sleeping * On resume it will go back to the current state */ struct cmd_ds_mesh_access mesh_access; memset(&mesh_access, 0, sizeof(mesh_access)); mesh_access.data[0] = cpu_to_le32(1); libertas_prepare_and_send_command(priv, CMD_MESH_ACCESS, CMD_ACT_MESH_SET_AUTOSTART_ENABLED, CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); } netif_device_detach(cardp->eth_dev); netif_device_detach(priv->mesh_dev); /* Unlink tx & rx urb */ usb_kill_urb(cardp->tx_urb); usb_kill_urb(cardp->rx_urb); cardp->rx_urb_recall = 1; lbs_deb_leave(LBS_DEB_USB); return 0;}static int if_usb_resume(struct usb_interface *intf){ struct usb_card_rec *cardp = usb_get_intfdata(intf); wlan_private *priv = cardp->priv; lbs_deb_enter(LBS_DEB_USB); cardp->rx_urb_recall = 0; if_usb_submit_rx_urb(cardp->priv); netif_device_attach(cardp->eth_dev); netif_device_attach(priv->mesh_dev); if (priv->mesh_dev && !priv->mesh_autostart_enabled) { /* Mesh autostart was activated while sleeping * Disable it if appropriate */ struct cmd_ds_mesh_access mesh_access; memset(&mesh_access, 0, sizeof(mesh_access)); mesh_access.data[0] = cpu_to_le32(0); libertas_prepare_and_send_command(priv, CMD_MESH_ACCESS, CMD_ACT_MESH_SET_AUTOSTART_ENABLED, CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); } lbs_deb_leave(LBS_DEB_USB); return 0;}#else#define if_usb_suspend NULL#define if_usb_resume NULL#endifstatic struct usb_driver if_usb_driver = { /* driver name */ .name = usbdriver_name, /* probe function name */ .probe = if_usb_probe, /* disconnect function name */ .disconnect = if_usb_disconnect, /* device signature table */ .id_table = if_usb_table, .suspend = if_usb_suspend, .resume = if_usb_resume,};static int if_usb_init_module(void){ int ret = 0; lbs_deb_enter(LBS_DEB_MAIN); if (libertas_fw_name == NULL) { libertas_fw_name = default_fw_name; } ret = usb_register(&if_usb_driver); lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret;}static void if_usb_exit_module(void){ struct usb_card_rec *cardp, *cardp_temp; lbs_deb_enter(LBS_DEB_MAIN); list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) { libertas_prepare_and_send_command(cardp->priv, CMD_802_11_RESET, CMD_ACT_HALT, 0, 0, NULL); } /* API unregisters the driver from USB subsystem */ usb_deregister(&if_usb_driver); lbs_deb_leave(LBS_DEB_MAIN);}module_init(if_usb_init_module);module_exit(if_usb_exit_module);MODULE_DESCRIPTION("8388 USB WLAN Driver");MODULE_AUTHOR("Marvell International Ltd.");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -