📄 if_usb.c
字号:
/** * This file contains functions used in USB interface module. */#include <linux/delay.h>#include <linux/moduleparam.h>#include <linux/firmware.h>#include <linux/netdevice.h>#include <linux/list.h>#include <linux/usb.h>#define DRV_NAME "usb8xxx"#include "host.h"#include "decl.h"#include "defs.h"#include "dev.h"#include "if_usb.h"#define MESSAGE_HEADER_LEN 4static const char usbdriver_name[] = "usb8xxx";static u8 *default_fw_name = "usb8388.bin";static char *libertas_fw_name = NULL;module_param_named(fw_name, libertas_fw_name, charp, 0644);/* * We need to send a RESET command to all USB devices before * we tear down the USB connection. Otherwise we would not * be able to re-init device the device if the module gets * loaded again. This is a list of all initialized USB devices, * for the reset code see if_usb_reset_device()*/static LIST_HEAD(usb_devices);static struct usb_device_id if_usb_table[] = { /* Enter the device signature inside */ { USB_DEVICE(0x1286, 0x2001) }, { USB_DEVICE(0x05a3, 0x8388) }, {} /* Terminating entry */};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_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(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 * @param urb pointer to urb structure * @return N/A */static void if_usb_write_bulk_callback(struct urb *urb){ struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context; /* handle the transmission complete validations */ 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); */ /* 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;}/** * @brief free tx/rx urb, skb and rx buffer * @param cardp pointer usb_card_rec * @return N/A */static void if_usb_free(struct usb_card_rec *cardp){ lbs_deb_enter(LBS_DEB_USB); /* Unlink tx & rx urb */ usb_kill_urb(cardp->tx_urb); usb_kill_urb(cardp->rx_urb); usb_free_urb(cardp->tx_urb); cardp->tx_urb = NULL; usb_free_urb(cardp->rx_urb); cardp->rx_urb = NULL; kfree(cardp->bulk_out_buffer); cardp->bulk_out_buffer = NULL; lbs_deb_leave(LBS_DEB_USB);}/** * @brief sets the configuration values * @param ifnum interface number * @param id pointer to usb_device_id * @return 0 on success, error code on failure */static int if_usb_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *udev; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; wlan_private *priv; struct usb_card_rec *cardp; int i; udev = interface_to_usbdev(intf); cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); if (!cardp) { lbs_pr_err("Out of memory allocating private data.\n"); goto error; } cardp->udev = udev; iface_desc = intf->cur_altsetting; lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X" " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", le16_to_cpu(udev->descriptor.bcdUSB), udev->descriptor.bDeviceClass, udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceProtocol); for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { /* we found a bulk in endpoint */ lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", le16_to_cpu(endpoint->wMaxPacketSize)); if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) { lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n"); goto dealloc; } cardp->rx_urb_recall = 0; cardp->bulk_in_size = le16_to_cpu(endpoint->wMaxPacketSize); cardp->bulk_in_endpointAddr = (endpoint-> bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", endpoint->bEndpointAddress); } if (((endpoint-> bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { /* We found bulk out endpoint */ if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) { lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n"); goto dealloc; } cardp->bulk_out_size = le16_to_cpu(endpoint->wMaxPacketSize); lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", le16_to_cpu(endpoint->wMaxPacketSize)); cardp->bulk_out_endpointAddr = endpoint->bEndpointAddress; lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", endpoint->bEndpointAddress); cardp->bulk_out_buffer = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL); if (!cardp->bulk_out_buffer) { lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n"); goto dealloc; } } } /* 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 err_prog_firmware; cardp->priv = priv; if (libertas_add_mesh(priv, &udev->dev)) goto err_add_mesh; 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; /* 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); usb_get_dev(udev); usb_set_intfdata(intf, cardp); return 0;err_start_card: libertas_remove_mesh(priv);err_add_mesh: libertas_remove_card(priv);err_prog_firmware: if_usb_reset_device(cardp);dealloc: if_usb_free(cardp);error: return -ENOMEM;}/** * @brief free resource and cleanup * @param intf USB interface structure * @return N/A */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; lbs_deb_enter(LBS_DEB_MAIN); /* Update Surprise removed to TRUE */ cardp->surprise_removed = 1; list_del(&cardp->list); 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); usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); lbs_deb_leave(LBS_DEB_MAIN);}/** * @brief This function download FW * @param priv pointer to wlan_private * @return 0 */static int if_prog_firmware(struct usb_card_rec *cardp){ struct FWData *fwdata; struct fwheader *fwheader; u8 *firmware = cardp->fw->data; fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); if (!fwdata) return -1; fwheader = &fwdata->fwheader; if (!cardp->CRC_OK) { cardp->totalbytes = cardp->fwlastblksent; cardp->fwseqnum = cardp->lastseqnum - 1; } /* lbs_deb_usbd(&cardp->udev->dev, "totalbytes = %d\n", cardp->totalbytes); */ memcpy(fwheader, &firmware[cardp->totalbytes], sizeof(struct fwheader)); cardp->fwlastblksent = cardp->totalbytes; cardp->totalbytes += sizeof(struct fwheader); /* lbs_deb_usbd(&cardp->udev->dev,"Copy Data\n"); */ memcpy(fwdata->data, &firmware[cardp->totalbytes], le32_to_cpu(fwdata->fwheader.datalength)); /* lbs_deb_usbd(&cardp->udev->dev, "Data length = %d\n", le32_to_cpu(fwdata->fwheader.datalength)); */ cardp->fwseqnum = cardp->fwseqnum + 1; fwdata->seqnum = cpu_to_le32(cardp->fwseqnum); cardp->lastseqnum = cardp->fwseqnum; cardp->totalbytes += le32_to_cpu(fwdata->fwheader.datalength); if (fwheader->dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) { /* lbs_deb_usbd(&cardp->udev->dev, "There are data to follow\n"); lbs_deb_usbd(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n", cardp->fwseqnum, cardp->totalbytes); */ memcpy(cardp->bulk_out_buffer, fwheader, 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)) { /* lbs_deb_usbd(&cardp->udev->dev, "Host has finished FW downloading\n"); lbs_deb_usbd(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n"); */ memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); cardp->fwfinalblk = 1; } /* lbs_deb_usbd(&cardp->udev->dev, "The firmware download is done size is %d\n", cardp->totalbytes); */ kfree(fwdata); return 0;}static int if_usb_reset_device(struct usb_card_rec *cardp){ int ret; wlan_private * priv = cardp->priv; lbs_deb_enter(LBS_DEB_USB); /* Try a USB port reset first, if that fails send the reset * command to the firmware. */ ret = usb_reset_device(cardp->udev); if (!ret && priv) { msleep(10); ret = libertas_reset_device(priv); msleep(10); } lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); return ret;}/** * @brief This function transfer the data to the device. * @param priv pointer to wlan_private * @param payload pointer to payload data * @param nb data length * @return 0 or -1 */static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 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->bulk_out_endpointAddr), 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))) { /* transfer failed */ lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed\n"); ret = -1; } else { /* lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb success\n"); */ ret = 0; }tx_ret: return ret;}static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp, void (*callbackfn)(struct urb *urb)){ struct sk_buff *skb; struct read_cb_info *rinfo = &cardp->rinfo; int ret = -1; if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { lbs_pr_err("No free skb\n"); goto rx_ret; } rinfo->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->bulk_in_endpointAddr), (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET), MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, rinfo); cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; /* lbs_deb_usbd(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); */ if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { /* handle failure conditions */ lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed\n"); ret = -1; } else { /* lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB success\n"); */ ret = 0; }rx_ret: return ret;}static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp){ return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);}static int if_usb_submit_rx_urb(struct usb_card_rec *cardp){ 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; struct sk_buff *skb = rinfo->skb; struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp; 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(cardp); 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -