OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * |
| 3 * Generic Bluetooth USB DFU driver to download firmware to target RAM |
| 4 * |
| 5 * Copyright (c) 2009-2010 Atheros Communications Inc. |
| 6 * |
| 7 * This program is free software; you can redistribute it and/or modify |
| 8 * it under the terms of the GNU General Public License as published by |
| 9 * the Free Software Foundation; either version 2 of the License, or |
| 10 * (at your option) any later version. |
| 11 * |
| 12 * This program is distributed in the hope that it will be useful, |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 * GNU General Public License for more details. |
| 16 * |
| 17 * You should have received a copy of the GNU General Public License |
| 18 * along with this program; if not, write to the Free Software |
| 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 * |
| 21 */ |
| 22 |
| 23 #include <linux/module.h> |
| 24 #include <linux/kernel.h> |
| 25 #include <linux/init.h> |
| 26 #include <linux/slab.h> |
| 27 #include <linux/types.h> |
| 28 #include <linux/device.h> |
| 29 #include <linux/firmware.h> |
| 30 #include <linux/usb.h> |
| 31 #include <net/bluetooth/bluetooth.h> |
| 32 |
| 33 #define USB_REQ_DFU_DNLOAD 1 |
| 34 #define USB_REQ_GET_STATE 5 |
| 35 #define USB_FIRMWARE_RAM_MODE 11 |
| 36 #define USB_FIRMWARE_FLASH_MODE 12 |
| 37 #define BULK_SIZE 4096 |
| 38 #define VERSION "1.0" |
| 39 |
| 40 struct firmware_data { |
| 41 struct usb_device *udev; |
| 42 u8 *fw_data; |
| 43 u32 fw_size; |
| 44 u32 fw_sent; |
| 45 }; |
| 46 |
| 47 static int load_firmware(struct firmware_data *data, |
| 48 unsigned char *firmware, |
| 49 int count) |
| 50 { |
| 51 u8 *send_buf; |
| 52 int err, pipe, len, size, sent = 0; |
| 53 char ucFirmware = 0; |
| 54 |
| 55 BT_DBG("ath3k %p udev %p", data, data->udev); |
| 56 |
| 57 if ((usb_control_msg(data->udev, usb_rcvctrlpipe(data->udev, 0), |
| 58 USB_REQ_GET_STATE, |
| 59 USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, |
| 60 &ucFirmware, 1, USB_CTRL_SET_TIMEOUT)) < 0) { |
| 61 BT_ERR("Can't change to loading configuration err"); |
| 62 return -EBUSY; |
| 63 } |
| 64 |
| 65 if (ucFirmware == USB_FIRMWARE_RAM_MODE) { |
| 66 /* RAM based firmware is available in the target. |
| 67 * No need to load the firmware to RAM */ |
| 68 BT_DBG("RAM based firmware is available"); |
| 69 return 0; |
| 70 } |
| 71 |
| 72 pipe = usb_sndctrlpipe(data->udev, 0); |
| 73 if ((usb_control_msg(data->udev, pipe, |
| 74 USB_REQ_DFU_DNLOAD, |
| 75 USB_TYPE_VENDOR, 0, 0, |
| 76 firmware, 20, USB_CTRL_SET_TIMEOUT)) < 0) { |
| 77 BT_ERR("Can't change to loading configuration err"); |
| 78 return -EBUSY; |
| 79 } |
| 80 sent += 20; |
| 81 count -= 20; |
| 82 |
| 83 send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC); |
| 84 if (!send_buf) { |
| 85 BT_ERR("Can't allocate memory chunk for firmware"); |
| 86 return -ENOMEM; |
| 87 } |
| 88 |
| 89 while (count) { |
| 90 size = min_t(uint, count, BULK_SIZE); |
| 91 pipe = usb_sndbulkpipe(data->udev, 0x02); |
| 92 memcpy(send_buf, firmware + sent, size); |
| 93 |
| 94 err = usb_bulk_msg(data->udev, pipe, send_buf, size, |
| 95 &len, 3000); |
| 96 |
| 97 if (err || (len != size)) { |
| 98 BT_ERR("Error in firmware loading err = %d," |
| 99 "len = %d, size = %d", err, len, size); |
| 100 goto error; |
| 101 } |
| 102 |
| 103 sent += size; |
| 104 count -= size; |
| 105 } |
| 106 |
| 107 kfree(send_buf); |
| 108 return 0; |
| 109 |
| 110 error: |
| 111 kfree(send_buf); |
| 112 return err; |
| 113 } |
| 114 |
| 115 void *ath_fw_load(struct usb_interface *intf, |
| 116 const char *fwfile, bool *suspend) |
| 117 { |
| 118 const struct firmware *firmware; |
| 119 struct usb_device *udev = interface_to_usbdev(intf); |
| 120 static struct firmware_data *data; |
| 121 int size; |
| 122 |
| 123 BT_DBG("\nintf %p suspend %d\n", intf, *suspend); |
| 124 |
| 125 if (*suspend) { |
| 126 load_firmware(data, data->fw_data, data->fw_size); |
| 127 *suspend = 0; |
| 128 return data; |
| 129 } |
| 130 |
| 131 if (intf->cur_altsetting->desc.bInterfaceNumber != 0) |
| 132 return NULL; |
| 133 |
| 134 data = kzalloc(sizeof(*data), GFP_KERNEL); |
| 135 if (!data) |
| 136 return NULL; |
| 137 data->udev = udev; |
| 138 |
| 139 if (request_firmware(&firmware, fwfile, &udev->dev) < 0) { |
| 140 kfree(data); |
| 141 return NULL; |
| 142 } |
| 143 |
| 144 size = max_t(uint, firmware->size, 4096); |
| 145 data->fw_data = kmalloc(size, GFP_KERNEL); |
| 146 if (!data->fw_data) { |
| 147 release_firmware(firmware); |
| 148 kfree(data); |
| 149 return NULL; |
| 150 } |
| 151 |
| 152 memcpy(data->fw_data, firmware->data, firmware->size); |
| 153 data->fw_size = firmware->size; |
| 154 data->fw_sent = 0; |
| 155 release_firmware(firmware); |
| 156 |
| 157 if (load_firmware(data, data->fw_data, data->fw_size)) { |
| 158 kfree(data->fw_data); |
| 159 kfree(data); |
| 160 return NULL; |
| 161 } |
| 162 return data; |
| 163 } |
| 164 EXPORT_SYMBOL(ath_fw_load); |
| 165 |
| 166 void ath_fw_unload(void *pdata, bool bsuspend) |
| 167 { |
| 168 struct firmware_data *data = (struct firmware_data *)pdata; |
| 169 |
| 170 if (data == NULL) |
| 171 return; |
| 172 |
| 173 /* do not free the data on suspend as we will |
| 174 * use it on resume */ |
| 175 if (!bsuspend) { |
| 176 kfree(data->fw_data); |
| 177 kfree(data); |
| 178 } |
| 179 } |
| 180 EXPORT_SYMBOL(ath_fw_unload); |
| 181 |
| 182 static int __init fwload_init(void) |
| 183 { |
| 184 BT_INFO("Firmware load driver init. Version:%s", VERSION); |
| 185 return 0; |
| 186 } |
| 187 |
| 188 static void __exit fwload_deinit(void) |
| 189 { |
| 190 BT_INFO("Firmware load driver deinit"); |
| 191 } |
| 192 |
| 193 module_init(fwload_init); |
| 194 module_exit(fwload_deinit); |
| 195 |
| 196 MODULE_AUTHOR("Atheros Communications"); |
| 197 MODULE_DESCRIPTION("Firmware load driver"); |
| 198 MODULE_VERSION(VERSION); |
| 199 MODULE_LICENSE("GPL"); |
OLD | NEW |