1c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/* 2c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * Copyright (C) 2008, cozybit Inc. 3c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * Copyright (C) 2003-2006, Marvell International Ltd. 4c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 5c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * This program is free software; you can redistribute it and/or modify 6c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * it under the terms of the GNU General Public License as published by 7c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * the Free Software Foundation; either version 2 of the License, or (at 8c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * your option) any later version. 9c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 10e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier#define DRV_NAME "lbtf_usb" 11e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 12edfcba15bdfa520d8c64b496c9260a9d9e0b6d18John W. Linville#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13edfcba15bdfa520d8c64b496c9260a9d9e0b6d18John W. Linville 14e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier#include "libertas_tf.h" 15e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier#include "if_usb.h" 16e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 17c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo#include <linux/delay.h> 18ac5c24e9e613df556f054f1fa811fca0c24fe500Paul Gortmaker#include <linux/module.h> 19c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo#include <linux/firmware.h> 20c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo#include <linux/netdevice.h> 215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 22c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo#include <linux/usb.h> 23c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 24e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier#define INSANEDEBUG 0 25e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier#define lbtf_deb_usb2(...) do { if (INSANEDEBUG) lbtf_deb_usbd(__VA_ARGS__); } while (0) 26c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 27c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo#define MESSAGE_HEADER_LEN 4 28c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 29c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic char *lbtf_fw_name = "lbtf_usb.bin"; 30c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobomodule_param_named(fw_name, lbtf_fw_name, charp, 0644); 31c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 32790e7560c09a0184afcc00ac0f8df95de7468accBen HutchingsMODULE_FIRMWARE("lbtf_usb.bin"); 33790e7560c09a0184afcc00ac0f8df95de7468accBen Hutchings 34c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic struct usb_device_id if_usb_table[] = { 35c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Enter the device signature inside */ 36c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo { USB_DEVICE(0x1286, 0x2001) }, 37c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo { USB_DEVICE(0x05a3, 0x8388) }, 38c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo {} /* Terminating entry */ 39c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo}; 40c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 41c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos CoboMODULE_DEVICE_TABLE(usb, if_usb_table); 42c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 43c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_receive(struct urb *urb); 44c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_receive_fwload(struct urb *urb); 45c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_prog_firmware(struct if_usb_card *cardp); 46c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type, 47c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo uint8_t *payload, uint16_t nb); 48c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, 49c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo uint16_t nb, u8 data); 50c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_free(struct if_usb_card *cardp); 51c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_submit_rx_urb(struct if_usb_card *cardp); 52c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_reset_device(struct if_usb_card *cardp); 53c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 54c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 55c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * if_usb_wrike_bulk_callback - call back to handle URB status 56c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 57422f8d19d68d0530dfd37be97bac431ca7435e69Thomas Klute * @param urb pointer to urb structure 58c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 59c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_write_bulk_callback(struct urb *urb) 60c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 61e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (urb->status != 0) { 62e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier /* print the failure status number for debug */ 63e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_info("URB in failure status: %d\n", urb->status); 64e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else { 65e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb2(&urb->dev->dev, "URB status is successful\n"); 66e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n", 67e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier urb->actual_length); 68e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 69c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 70c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 71c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 72c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * if_usb_free - free tx/rx urb, skb and rx buffer 73c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 74c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @param cardp pointer if_usb_card 75c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 76c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_free(struct if_usb_card *cardp) 77c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 78e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 79e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 80c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Unlink tx & rx urb */ 81c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_kill_urb(cardp->tx_urb); 82c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_kill_urb(cardp->rx_urb); 83c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_kill_urb(cardp->cmd_urb); 84c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 85c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_free_urb(cardp->tx_urb); 86c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->tx_urb = NULL; 87c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 88c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_free_urb(cardp->rx_urb); 89c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->rx_urb = NULL; 90c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 91c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_free_urb(cardp->cmd_urb); 92c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->cmd_urb = NULL; 93c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 94c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree(cardp->ep_out_buf); 95c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->ep_out_buf = NULL; 96e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 97e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 98c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 99c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 100c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_setup_firmware(struct lbtf_private *priv) 101c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 102c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct if_usb_card *cardp = priv->card; 103c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct cmd_ds_set_boot2_ver b2_cmd; 104c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 105e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 106e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 107c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_submit_rx_urb(cardp); 108c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd)); 109c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo b2_cmd.action = 0; 110c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo b2_cmd.version = cardp->boot2_version; 111c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 112c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (lbtf_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd)) 113e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb("Setting boot2 version failed\n"); 114e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 115e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 116c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 117c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 118c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_fw_timeo(unsigned long priv) 119c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 120c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct if_usb_card *cardp = (void *)priv; 121c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 122e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 123e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (!cardp->fwdnldover) { 124c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Download timed out */ 125c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->priv->surpriseremoved = 1; 126e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_err("Download timed out\n"); 127e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else { 128e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb("Download complete, no event. Assuming success\n"); 129e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 130c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo wake_up(&cardp->fw_wq); 131e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 132c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 133c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 134c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 135c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * if_usb_probe - sets the configuration values 136c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 137c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @ifnum interface number 138c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @id pointer to usb_device_id 139c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 140c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * Returns: 0 on success, error code on failure 141c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 142c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_probe(struct usb_interface *intf, 143c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo const struct usb_device_id *id) 144c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 145c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct usb_device *udev; 146c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct usb_host_interface *iface_desc; 147c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct usb_endpoint_descriptor *endpoint; 148c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct lbtf_private *priv; 149c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct if_usb_card *cardp; 150c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo int i; 151c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 152e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 153c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo udev = interface_to_usbdev(intf); 154c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 155c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL); 156e404decb0fb017be80552adee894b35307b6c7b4Joe Perches if (!cardp) 157c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto error; 158c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 159c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp); 160c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo init_waitqueue_head(&cardp->fw_wq); 161c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 162c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->udev = udev; 163c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo iface_desc = intf->cur_altsetting; 164c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 165e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X" 166e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", 167e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier le16_to_cpu(udev->descriptor.bcdUSB), 168e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier udev->descriptor.bDeviceClass, 169e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier udev->descriptor.bDeviceSubClass, 170e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier udev->descriptor.bDeviceProtocol); 171e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 172c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 173c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo endpoint = &iface_desc->endpoint[i].desc; 174c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (usb_endpoint_is_bulk_in(endpoint)) { 175c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->ep_in_size = 176c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo le16_to_cpu(endpoint->wMaxPacketSize); 177c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->ep_in = usb_endpoint_num(endpoint); 178e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 179139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n", 180139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute cardp->ep_in); 181139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n", 182139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute cardp->ep_in_size); 183c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } else if (usb_endpoint_is_bulk_out(endpoint)) { 184c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->ep_out_size = 185c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo le16_to_cpu(endpoint->wMaxPacketSize); 186c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->ep_out = usb_endpoint_num(endpoint); 187e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 188139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n", 189139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute cardp->ep_out); 190e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n", 191422f8d19d68d0530dfd37be97bac431ca7435e69Thomas Klute cardp->ep_out_size); 192c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 193c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 194e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (!cardp->ep_out_size || !cardp->ep_in_size) { 195e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&udev->dev, "Endpoints not found\n"); 196c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Endpoints not found */ 197c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto dealloc; 198e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 199c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 200c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 201e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (!cardp->rx_urb) { 202e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&udev->dev, "Rx URB allocation failed\n"); 203c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto dealloc; 204e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 205c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 206c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 207e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (!cardp->tx_urb) { 208e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&udev->dev, "Tx URB allocation failed\n"); 209c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto dealloc; 210e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 211c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 212c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->cmd_urb = usb_alloc_urb(0, GFP_KERNEL); 213e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (!cardp->cmd_urb) { 214e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&udev->dev, "Cmd URB allocation failed\n"); 215c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto dealloc; 216e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 217c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 218c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, 219c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo GFP_KERNEL); 220e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (!cardp->ep_out_buf) { 221e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&udev->dev, "Could not allocate buffer\n"); 222c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto dealloc; 223e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 224c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 225c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo priv = lbtf_add_card(cardp, &udev->dev); 226c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (!priv) 227c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto dealloc; 228c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 229c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->priv = priv; 230c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 231c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo priv->hw_host_to_card = if_usb_host_to_card; 232c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo priv->hw_prog_firmware = if_usb_prog_firmware; 233c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo priv->hw_reset_device = if_usb_reset_device; 234c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->boot2_version = udev->descriptor.bcdDevice; 235c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 236c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_get_dev(udev); 237c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_set_intfdata(intf, cardp); 238c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 239c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return 0; 240c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 241c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobodealloc: 242c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_free(cardp); 243c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Coboerror: 244e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosierlbtf_deb_leave(LBTF_DEB_MAIN); 245c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return -ENOMEM; 246c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 247c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 248c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 249c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * if_usb_disconnect - free resource and cleanup 250c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 251c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @intf USB interface structure 252c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 253c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_disconnect(struct usb_interface *intf) 254c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 255c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct if_usb_card *cardp = usb_get_intfdata(intf); 2562c208890c6d4e16076c6664137703ec813e8fa6cJoe Perches struct lbtf_private *priv = cardp->priv; 257c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 258e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_MAIN); 259e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 260c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_reset_device(cardp); 261c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 262c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (priv) 263c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo lbtf_remove_card(priv); 264c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 265c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Unlink and free urb */ 266c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_free(cardp); 267c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 268c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_set_intfdata(intf, NULL); 269c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_put_dev(interface_to_usbdev(intf)); 270e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 271e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_MAIN); 272c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 273c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 274c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 275c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * if_usb_send_fw_pkt - This function downloads the FW 276c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 277c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @priv pointer to struct lbtf_private 278c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 279c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * Returns: 0 280c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 281c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_send_fw_pkt(struct if_usb_card *cardp) 282c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 283c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct fwdata *fwdata = cardp->ep_out_buf; 284c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo u8 *firmware = (u8 *) cardp->fw->data; 285c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 286e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_FW); 287e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 288c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* If we got a CRC failure on the last block, back 289c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo up and retry it */ 290c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (!cardp->CRC_OK) { 291c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->totalbytes = cardp->fwlastblksent; 292c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fwseqnum--; 293c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 294c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 295e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n", 296e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier cardp->totalbytes); 297e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 298c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* struct fwdata (which we sent to the card) has an 299c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo extra __le32 field in between the header and the data, 300c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo which is not in the struct fwheader in the actual 301c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo firmware binary. Insert the seqnum in the middle... */ 302c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo memcpy(&fwdata->hdr, &firmware[cardp->totalbytes], 303c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo sizeof(struct fwheader)); 304c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 305c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fwlastblksent = cardp->totalbytes; 306c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->totalbytes += sizeof(struct fwheader); 307c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 308c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo memcpy(fwdata->data, &firmware[cardp->totalbytes], 309c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo le32_to_cpu(fwdata->hdr.datalength)); 310c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 311e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb2(&cardp->udev->dev, "Data length = %d\n", 312e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier le32_to_cpu(fwdata->hdr.datalength)); 313e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 314c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum); 315c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength); 316c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 317c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) + 318c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo le32_to_cpu(fwdata->hdr.datalength), 0); 319c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 320e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) { 321e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb2(&cardp->udev->dev, "There are data to follow\n"); 322139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usb2(&cardp->udev->dev, 323139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute "seqnum = %d totalbytes = %d\n", 324139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute cardp->fwseqnum, cardp->totalbytes); 325e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) { 326139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usb2(&cardp->udev->dev, 327139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute "Host has finished FW downloading\n"); 328e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n"); 329e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 330c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Host has finished FW downloading 331c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * Donwloading FW JUMP BLOCK 332c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 333c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fwfinalblk = 1; 334e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 335c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 336e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n", 337e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier cardp->totalbytes); 338e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 339e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_FW); 340c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return 0; 341c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 342c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 343c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_reset_device(struct if_usb_card *cardp) 344c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 345c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct cmd_ds_802_11_reset *cmd = cardp->ep_out_buf + 4; 346c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo int ret; 347c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 348e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 349e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 350c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); 351c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 352c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cmd->hdr.command = cpu_to_le16(CMD_802_11_RESET); 353c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset)); 354c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cmd->hdr.result = cpu_to_le16(0); 355c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cmd->hdr.seqnum = cpu_to_le16(0x5a5a); 356c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cmd->action = cpu_to_le16(CMD_ACT_HALT); 357c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_tx_block(cardp, cardp->ep_out_buf, 358c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 4 + sizeof(struct cmd_ds_802_11_reset), 0); 359c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 360c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo msleep(100); 361c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo ret = usb_reset_device(cardp->udev); 362c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo msleep(100); 363c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 364e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave_args(LBTF_DEB_USB, "ret %d", ret); 365e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 366c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return ret; 367c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 368c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos CoboEXPORT_SYMBOL_GPL(if_usb_reset_device); 369c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 370c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 371c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * usb_tx_block - transfer data to the device 372c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 373422f8d19d68d0530dfd37be97bac431ca7435e69Thomas Klute * @priv pointer to struct lbtf_private 374c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @payload pointer to payload data 375c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @nb data length 376c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @data non-zero for data, zero for commands 377c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 378c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * Returns: 0 on success, nonzero otherwise. 379c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 380c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, 381c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo uint16_t nb, u8 data) 382c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 383e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier int ret = -1; 384c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct urb *urb; 385c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 386e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 387c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* check if device is removed */ 388e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (cardp->priv->surpriseremoved) { 389e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, "Device removed\n"); 390e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier goto tx_ret; 391e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 392c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 393c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (data) 394c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo urb = cardp->tx_urb; 395c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo else 396c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo urb = cardp->cmd_urb; 397c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 398c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_fill_bulk_urb(urb, cardp->udev, 399c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_sndbulkpipe(cardp->udev, 400c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->ep_out), 401c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo payload, nb, if_usb_write_bulk_callback, cardp); 402c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 403c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo urb->transfer_flags |= URB_ZERO_PACKET; 404c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 405e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (usb_submit_urb(urb, GFP_ATOMIC)) { 406139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usbd(&cardp->udev->dev, 407139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute "usb_submit_urb failed: %d\n", ret); 408e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier goto tx_ret; 409e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 410e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 411e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n"); 412e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 413e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier ret = 0; 414e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 415e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosiertx_ret: 416e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 417e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier return ret; 418c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 419c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 420c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int __if_usb_submit_rx_urb(struct if_usb_card *cardp, 421c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo void (*callbackfn)(struct urb *urb)) 422c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 423c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct sk_buff *skb; 424e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier int ret = -1; 425e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 426e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 427c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 428c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); 429e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (!skb) { 430e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_err("No free skb\n"); 431e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 432c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return -1; 433e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 434c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 435c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->rx_skb = skb; 436c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 437c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Fill the receive configuration URB and initialise the Rx call back */ 438c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, 439c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_rcvbulkpipe(cardp->udev, cardp->ep_in), 4409b44fb89cab6e01816cdc05d6b59fdcf8100b8c3Johannes Berg skb_tail_pointer(skb), 441c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp); 442c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 443c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; 444c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 445139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", 446139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute cardp->rx_urb); 447e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC); 448e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (ret) { 449139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usbd(&cardp->udev->dev, 450139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute "Submit Rx URB failed: %d\n", ret); 451c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 452c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->rx_skb = NULL; 453e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 454c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return -1; 455e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else { 456e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n"); 457e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 458c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return 0; 459e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 460c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 461c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 462c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp) 463c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 464c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload); 465c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 466c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 467c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_submit_rx_urb(struct if_usb_card *cardp) 468c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 469c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return __if_usb_submit_rx_urb(cardp, &if_usb_receive); 470c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 471c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 472c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_receive_fwload(struct urb *urb) 473c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 474c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct if_usb_card *cardp = urb->context; 475c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct sk_buff *skb = cardp->rx_skb; 476c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct fwsyncheader *syncfwheader; 477c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct bootcmdresp bcmdresp; 478c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 479e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 480c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (urb->status) { 481e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, 482e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier "URB status is failed during fw load\n"); 483c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 484e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 485c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return; 486c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 487c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 488c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (cardp->fwdnldover) { 489c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo __le32 *tmp = (__le32 *)(skb->data); 490c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 491c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) && 492e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) { 493c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Firmware ready event received */ 494e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_info("Firmware ready event received\n"); 495c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo wake_up(&cardp->fw_wq); 496e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else { 497e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usb("Waiting for confirmation; got %x %x\n", 498e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1])); 499c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_submit_rx_urb_fwload(cardp); 500e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 501c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 502e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 503c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return; 504c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 505c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (cardp->bootcmdresp <= 0) { 506c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo memcpy(&bcmdresp, skb->data, sizeof(bcmdresp)); 507c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 508c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { 509c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 510c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_submit_rx_urb_fwload(cardp); 511c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->bootcmdresp = 1; 512c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Received valid boot command response */ 513e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, 514e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier "Received valid boot command response\n"); 515e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 516c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return; 517c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 518c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (bcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) { 519c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (bcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) || 520c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo bcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) || 521e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) { 522e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (!cardp->bootcmdresp) 523e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_info("Firmware already seems alive; resetting\n"); 524c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->bootcmdresp = -1; 525e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else { 526e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_info("boot cmd response wrong magic number (0x%x)\n", 527e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier le32_to_cpu(bcmdresp.magic)); 528e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 529e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else if (bcmdresp.cmd != BOOT_CMD_FW_BY_USB) { 530e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_info("boot cmd response cmd_tag error (%d)\n", 531139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute bcmdresp.cmd); 532e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else if (bcmdresp.result != BOOT_CMD_RESP_OK) { 533e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_info("boot cmd response result error (%d)\n", 534139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute bcmdresp.result); 535e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else { 536c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->bootcmdresp = 1; 537e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, 538139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute "Received valid boot command response\n"); 539e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 540c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 541c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 542c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_submit_rx_urb_fwload(cardp); 543e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 544c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return; 545c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 546c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 54702730029530e7ca2a4d413d6afa67bbc9548c8c2Julia Lawall syncfwheader = kmemdup(skb->data, sizeof(struct fwsyncheader), 54802730029530e7ca2a4d413d6afa67bbc9548c8c2Julia Lawall GFP_ATOMIC); 549c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (!syncfwheader) { 550139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usbd(&cardp->udev->dev, 551139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute "Failure to allocate syncfwheader\n"); 552c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 553e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 554c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return; 555c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 556c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 557e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier if (!syncfwheader->cmd) { 558139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usb2(&cardp->udev->dev, 559139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute "FW received Blk with correct CRC\n"); 560139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usb2(&cardp->udev->dev, 561139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute "FW received Blk seqnum = %d\n", 562139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute le32_to_cpu(syncfwheader->seqnum)); 563c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->CRC_OK = 1; 564e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } else { 565139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usbd(&cardp->udev->dev, 566139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute "FW received Blk with CRC error\n"); 567c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->CRC_OK = 0; 568e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier } 569e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 570c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 571c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 572c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* reschedule timer for 200ms hence */ 573c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo mod_timer(&cardp->fw_timeout, jiffies + (HZ/5)); 574c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 575c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (cardp->fwfinalblk) { 576c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fwdnldover = 1; 577c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto exit; 578c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 579c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 580c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_send_fw_pkt(cardp); 581c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 582c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo exit: 583c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_submit_rx_urb_fwload(cardp); 584c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 585c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree(syncfwheader); 586c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 587e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 588c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 589c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 590c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo#define MRVDRV_MIN_PKT_LEN 30 591c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 592c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, 593c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct if_usb_card *cardp, 594c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct lbtf_private *priv) 595c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 596c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN 597c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo || recvlength < MRVDRV_MIN_PKT_LEN) { 598e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n"); 599c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 600c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return; 601c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 602c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 603c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo skb_put(skb, recvlength); 604c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo skb_pull(skb, MESSAGE_HEADER_LEN); 605c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo lbtf_rx(priv, skb); 606c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 607c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 608c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, 609c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct sk_buff *skb, 610c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct if_usb_card *cardp, 611c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct lbtf_private *priv) 612c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 613c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (recvlength > LBS_CMD_BUFFER_SIZE) { 614e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, 615e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier "The receive buffer is too large\n"); 616c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 617c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return; 618c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 619c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 6200ee904c35cc3fdd26a9c76077d9692d458309186Alexander Beregalov BUG_ON(!in_interrupt()); 621c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 622c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo spin_lock(&priv->driver_lock); 623c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN, 624c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo recvlength - MESSAGE_HEADER_LEN); 625c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 626c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo lbtf_cmd_response_rx(priv); 627c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo spin_unlock(&priv->driver_lock); 628c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 629c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 630c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 631c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * if_usb_receive - read data received from the device. 632c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 633c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @urb pointer to struct urb 634c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 635c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic void if_usb_receive(struct urb *urb) 636c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 637c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct if_usb_card *cardp = urb->context; 638c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct sk_buff *skb = cardp->rx_skb; 639c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct lbtf_private *priv = cardp->priv; 640c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo int recvlength = urb->actual_length; 641c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo uint8_t *recvbuff = NULL; 642c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo uint32_t recvtype = 0; 643c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo __le32 *pkt = (__le32 *) skb->data; 644c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 645e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 646e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 647c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (recvlength) { 648c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (urb->status) { 649e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n", 650e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier urb->status); 651c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 652c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto setup_for_next; 653c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 654c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 655c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo recvbuff = skb->data; 656c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo recvtype = le32_to_cpu(pkt[0]); 657e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, 658e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier "Recv length = 0x%x, Recv type = 0x%X\n", 659e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier recvlength, recvtype); 660c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } else if (urb->status) { 661c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 662e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 663c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return; 664c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 665c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 666c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo switch (recvtype) { 667c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo case CMD_TYPE_DATA: 668c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo process_cmdtypedata(recvlength, skb, cardp, priv); 669c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo break; 670c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 671c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo case CMD_TYPE_REQUEST: 672c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo process_cmdrequest(recvlength, recvbuff, skb, cardp, priv); 673c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo break; 674c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 675c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo case CMD_TYPE_INDICATION: 676c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo { 677c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Event cause handling */ 678c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo u32 event_cause = le32_to_cpu(pkt[1]); 679139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute lbtf_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", 680139455c3912bfed4bd42824d59c82113cc667f91Thomas Klute event_cause); 681c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 682c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Icky undocumented magic special case */ 683c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (event_cause & 0xffff0000) { 684c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo u16 tmp; 685c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo u8 retrycnt; 686c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo u8 failure; 687c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 688c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo tmp = event_cause >> 16; 689c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo retrycnt = tmp & 0x00ff; 690c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo failure = (tmp & 0xff00) >> 8; 691c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo lbtf_send_tx_feedback(priv, retrycnt, failure); 692c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } else if (event_cause == LBTF_EVENT_BCN_SENT) 693c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo lbtf_bcn_sent(priv); 694c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo else 695e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, 696c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo "Unsupported notification %d received\n", 697c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo event_cause); 698c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 699c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo break; 700c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 701c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo default: 702e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, 703422f8d19d68d0530dfd37be97bac431ca7435e69Thomas Klute "libertastf: unknown command type 0x%X\n", recvtype); 704c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo kfree_skb(skb); 705c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo break; 706c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 707c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 708c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobosetup_for_next: 709c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_submit_rx_urb(cardp); 710e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave(LBTF_DEB_USB); 711c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 712c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 713c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 714c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * if_usb_host_to_card - Download data to the device 715c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 716c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @priv pointer to struct lbtf_private structure 717c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @type type of data 718c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @buf pointer to data buffer 719c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @len number of bytes 720c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 721c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * Returns: 0 on success, nonzero otherwise 722c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 723c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type, 724c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo uint8_t *payload, uint16_t nb) 725c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 726c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct if_usb_card *cardp = priv->card; 727c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo u8 data = 0; 728c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 729e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, "*** type = %u\n", type); 730e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, "size after = %d\n", nb); 731e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 732c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (type == MVMS_CMD) { 733c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); 734c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } else { 735c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA); 736c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo data = 1; 737c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 738c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 739c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb); 740c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 741c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN, 742c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo data); 743c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 744c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 745c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 746c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * if_usb_issue_boot_command - Issue boot command to Boot2. 747c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 748c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @ivalue 1 boots from FW by USB-Download, 2 boots from FW in EEPROM. 749c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 750c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * Returns: 0 751c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 752c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) 753c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 754c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct bootcmd *bootcmd = cardp->ep_out_buf; 755c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 756c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Prepare command */ 757c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); 758c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo bootcmd->cmd = ivalue; 759c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo memset(bootcmd->pad, 0, sizeof(bootcmd->pad)); 760c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 761c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Issue command */ 762c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd), 0); 763c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 764c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return 0; 765c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 766c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 767c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 768c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo/** 769c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * check_fwfile_format - Check the validity of Boot2/FW image. 770c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 771c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @data pointer to image 772c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * @totlen image length 773c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * 774c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo * Returns: 0 if the image is valid, nonzero otherwise. 775c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo */ 776c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int check_fwfile_format(const u8 *data, u32 totlen) 777c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 778c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo u32 bincmd, exit; 779c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo u32 blksize, offset, len; 780c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo int ret; 781c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 782c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo ret = 1; 783c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo exit = len = 0; 784c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 785c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo do { 786c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo struct fwheader *fwh = (void *) data; 787c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 788c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo bincmd = le32_to_cpu(fwh->dnldcmd); 789c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo blksize = le32_to_cpu(fwh->datalength); 790c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo switch (bincmd) { 791c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo case FW_HAS_DATA_TO_RECV: 792c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo offset = sizeof(struct fwheader) + blksize; 793c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo data += offset; 794c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo len += offset; 795c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (len >= totlen) 796c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo exit = 1; 797c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo break; 798c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo case FW_HAS_LAST_BLOCK: 799c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo exit = 1; 800c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo ret = 0; 801c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo break; 802c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo default: 803c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo exit = 1; 804c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo break; 805c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 806c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } while (!exit); 807c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 808c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (ret) 809e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_err("firmware file format check FAIL\n"); 810e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier else 811e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_fw("firmware file format check PASS\n"); 812e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 813c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return ret; 814c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 815c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 816c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 817c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic int if_usb_prog_firmware(struct if_usb_card *cardp) 818c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo{ 819c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo int i = 0; 820c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo static int reset_count = 10; 821c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo int ret = 0; 822c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 823e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_enter(LBTF_DEB_USB); 824e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier 825d6d1b650ae6acce73d55dd0246de22180303ae73Rusty Russell kparam_block_sysfs_write(fw_name); 826c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev); 827c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (ret < 0) { 828e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_err("request_firmware() failed with %#x\n", ret); 829e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_err("firmware %s not found\n", lbtf_fw_name); 830d6d1b650ae6acce73d55dd0246de22180303ae73Rusty Russell kparam_unblock_sysfs_write(fw_name); 831c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto done; 832c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 833d6d1b650ae6acce73d55dd0246de22180303ae73Rusty Russell kparam_unblock_sysfs_write(fw_name); 834c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 835c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) 836c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto release_fw; 837c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 838c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Coborestart: 839c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (if_usb_submit_rx_urb_fwload(cardp) < 0) { 840e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); 841c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo ret = -1; 842c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto release_fw; 843c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 844c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 845c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->bootcmdresp = 0; 846c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo do { 847c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo int j = 0; 848c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo i++; 849c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Issue Boot command = 1, Boot from Download-FW */ 850c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); 851c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* wait for command response */ 852c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo do { 853c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo j++; 854c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo msleep_interruptible(100); 855c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } while (cardp->bootcmdresp == 0 && j < 10); 856c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } while (cardp->bootcmdresp == 0 && i < 5); 857c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 858c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (cardp->bootcmdresp <= 0) { 859c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (--reset_count >= 0) { 860c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_reset_device(cardp); 861c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto restart; 862c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 863c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return -1; 864c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 865c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 866c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo i = 0; 867c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 868c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->totalbytes = 0; 869c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fwlastblksent = 0; 870c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->CRC_OK = 1; 871c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fwdnldover = 0; 872c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fwseqnum = -1; 873c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->totalbytes = 0; 874c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fwfinalblk = 0; 875c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 876c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* Send the first firmware packet... */ 877c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_send_fw_pkt(cardp); 878c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 879c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo /* ... and wait for the process to complete */ 880c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo wait_event_interruptible(cardp->fw_wq, cardp->priv->surpriseremoved || 881c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fwdnldover); 882c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 883c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo del_timer_sync(&cardp->fw_timeout); 884c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo usb_kill_urb(cardp->rx_urb); 885c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 886c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (!cardp->fwdnldover) { 887e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_info("failed to load fw, resetting device!\n"); 888c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if (--reset_count >= 0) { 889c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_reset_device(cardp); 890c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto restart; 891c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 892c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 893e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier pr_info("FW download failure, time = %d ms\n", i * 100); 894c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo ret = -1; 895c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo goto release_fw; 896c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo } 897c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 898c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->priv->fw_ready = 1; 899c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 900c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo release_fw: 901c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo release_firmware(cardp->fw); 902c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo cardp->fw = NULL; 903c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 904c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo if_usb_setup_firmware(cardp->priv); 905c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 906c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo done: 907e9bd5bcde7af27ebb92bb866afde5ef5e4f3dc6cSteve deRosier lbtf_deb_leave_args(LBTF_DEB_USB, "ret %d", ret); 908c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo return ret; 909c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo} 910c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos CoboEXPORT_SYMBOL_GPL(if_usb_prog_firmware); 911c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 912c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 913c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo#define if_usb_suspend NULL 914c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo#define if_usb_resume NULL 915c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 916c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobostatic struct usb_driver if_usb_driver = { 917c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo .name = DRV_NAME, 918c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo .probe = if_usb_probe, 919c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo .disconnect = if_usb_disconnect, 920c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo .id_table = if_usb_table, 921c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo .suspend = if_usb_suspend, 922c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo .resume = if_usb_resume, 923e1f12eb6ba6f1e74007eb01ed26fad7c5239d62bSarah Sharp .disable_hub_initiated_lpm = 1, 924c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo}; 925c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 926d632eb1bf22e11def74e4e53cc47d790fbdba105Greg Kroah-Hartmanmodule_usb_driver(if_usb_driver); 927c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos Cobo 928c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos CoboMODULE_DESCRIPTION("8388 USB WLAN Thinfirm Driver"); 929c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos CoboMODULE_AUTHOR("Cozybit Inc."); 930c305a19a0d0a47ac59a58865a4a63be65b1bf7c8Luis Carlos CoboMODULE_LICENSE("GPL"); 931