1/* 2 * 3 * Broadcom Blutonium firmware driver 4 * 5 * Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com> 6 * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 * 23 */ 24 25#include <linux/module.h> 26 27#include <linux/atomic.h> 28#include <linux/kernel.h> 29#include <linux/init.h> 30#include <linux/slab.h> 31#include <linux/types.h> 32#include <linux/errno.h> 33 34#include <linux/device.h> 35#include <linux/firmware.h> 36 37#include <linux/usb.h> 38 39#include <net/bluetooth/bluetooth.h> 40 41#define VERSION "1.2" 42 43static const struct usb_device_id bcm203x_table[] = { 44 /* Broadcom Blutonium (BCM2033) */ 45 { USB_DEVICE(0x0a5c, 0x2033) }, 46 47 { } /* Terminating entry */ 48}; 49 50MODULE_DEVICE_TABLE(usb, bcm203x_table); 51 52#define BCM203X_ERROR 0 53#define BCM203X_RESET 1 54#define BCM203X_LOAD_MINIDRV 2 55#define BCM203X_SELECT_MEMORY 3 56#define BCM203X_CHECK_MEMORY 4 57#define BCM203X_LOAD_FIRMWARE 5 58#define BCM203X_CHECK_FIRMWARE 6 59 60#define BCM203X_IN_EP 0x81 61#define BCM203X_OUT_EP 0x02 62 63struct bcm203x_data { 64 struct usb_device *udev; 65 66 unsigned long state; 67 68 struct work_struct work; 69 atomic_t shutdown; 70 71 struct urb *urb; 72 unsigned char *buffer; 73 74 unsigned char *fw_data; 75 unsigned int fw_size; 76 unsigned int fw_sent; 77}; 78 79static void bcm203x_complete(struct urb *urb) 80{ 81 struct bcm203x_data *data = urb->context; 82 struct usb_device *udev = urb->dev; 83 int len; 84 85 BT_DBG("udev %p urb %p", udev, urb); 86 87 if (urb->status) { 88 BT_ERR("URB failed with status %d", urb->status); 89 data->state = BCM203X_ERROR; 90 return; 91 } 92 93 switch (data->state) { 94 case BCM203X_LOAD_MINIDRV: 95 memcpy(data->buffer, "#", 1); 96 97 usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), 98 data->buffer, 1, bcm203x_complete, data); 99 100 data->state = BCM203X_SELECT_MEMORY; 101 102 /* use workqueue to have a small delay */ 103 schedule_work(&data->work); 104 break; 105 106 case BCM203X_SELECT_MEMORY: 107 usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), 108 data->buffer, 32, bcm203x_complete, data, 1); 109 110 data->state = BCM203X_CHECK_MEMORY; 111 112 if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) 113 BT_ERR("Can't submit URB"); 114 break; 115 116 case BCM203X_CHECK_MEMORY: 117 if (data->buffer[0] != '#') { 118 BT_ERR("Memory select failed"); 119 data->state = BCM203X_ERROR; 120 break; 121 } 122 123 data->state = BCM203X_LOAD_FIRMWARE; 124 125 case BCM203X_LOAD_FIRMWARE: 126 if (data->fw_sent == data->fw_size) { 127 usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), 128 data->buffer, 32, bcm203x_complete, data, 1); 129 130 data->state = BCM203X_CHECK_FIRMWARE; 131 } else { 132 len = min_t(uint, data->fw_size - data->fw_sent, 4096); 133 134 usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), 135 data->fw_data + data->fw_sent, len, bcm203x_complete, data); 136 137 data->fw_sent += len; 138 } 139 140 if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) 141 BT_ERR("Can't submit URB"); 142 break; 143 144 case BCM203X_CHECK_FIRMWARE: 145 if (data->buffer[0] != '.') { 146 BT_ERR("Firmware loading failed"); 147 data->state = BCM203X_ERROR; 148 break; 149 } 150 151 data->state = BCM203X_RESET; 152 break; 153 } 154} 155 156static void bcm203x_work(struct work_struct *work) 157{ 158 struct bcm203x_data *data = 159 container_of(work, struct bcm203x_data, work); 160 161 if (atomic_read(&data->shutdown)) 162 return; 163 164 if (usb_submit_urb(data->urb, GFP_KERNEL) < 0) 165 BT_ERR("Can't submit URB"); 166} 167 168static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id) 169{ 170 const struct firmware *firmware; 171 struct usb_device *udev = interface_to_usbdev(intf); 172 struct bcm203x_data *data; 173 int size; 174 175 BT_DBG("intf %p id %p", intf, id); 176 177 if (intf->cur_altsetting->desc.bInterfaceNumber != 0) 178 return -ENODEV; 179 180 data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); 181 if (!data) { 182 BT_ERR("Can't allocate memory for data structure"); 183 return -ENOMEM; 184 } 185 186 data->udev = udev; 187 data->state = BCM203X_LOAD_MINIDRV; 188 189 data->urb = usb_alloc_urb(0, GFP_KERNEL); 190 if (!data->urb) { 191 BT_ERR("Can't allocate URB"); 192 return -ENOMEM; 193 } 194 195 if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) { 196 BT_ERR("Mini driver request failed"); 197 usb_free_urb(data->urb); 198 return -EIO; 199 } 200 201 BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size); 202 203 size = max_t(uint, firmware->size, 4096); 204 205 data->buffer = kmalloc(size, GFP_KERNEL); 206 if (!data->buffer) { 207 BT_ERR("Can't allocate memory for mini driver"); 208 release_firmware(firmware); 209 usb_free_urb(data->urb); 210 return -ENOMEM; 211 } 212 213 memcpy(data->buffer, firmware->data, firmware->size); 214 215 usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), 216 data->buffer, firmware->size, bcm203x_complete, data); 217 218 release_firmware(firmware); 219 220 if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) { 221 BT_ERR("Firmware request failed"); 222 usb_free_urb(data->urb); 223 kfree(data->buffer); 224 return -EIO; 225 } 226 227 BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); 228 229 data->fw_data = kmemdup(firmware->data, firmware->size, GFP_KERNEL); 230 if (!data->fw_data) { 231 BT_ERR("Can't allocate memory for firmware image"); 232 release_firmware(firmware); 233 usb_free_urb(data->urb); 234 kfree(data->buffer); 235 return -ENOMEM; 236 } 237 238 data->fw_size = firmware->size; 239 data->fw_sent = 0; 240 241 release_firmware(firmware); 242 243 INIT_WORK(&data->work, bcm203x_work); 244 245 usb_set_intfdata(intf, data); 246 247 /* use workqueue to have a small delay */ 248 schedule_work(&data->work); 249 250 return 0; 251} 252 253static void bcm203x_disconnect(struct usb_interface *intf) 254{ 255 struct bcm203x_data *data = usb_get_intfdata(intf); 256 257 BT_DBG("intf %p", intf); 258 259 atomic_inc(&data->shutdown); 260 cancel_work_sync(&data->work); 261 262 usb_kill_urb(data->urb); 263 264 usb_set_intfdata(intf, NULL); 265 266 usb_free_urb(data->urb); 267 kfree(data->fw_data); 268 kfree(data->buffer); 269} 270 271static struct usb_driver bcm203x_driver = { 272 .name = "bcm203x", 273 .probe = bcm203x_probe, 274 .disconnect = bcm203x_disconnect, 275 .id_table = bcm203x_table, 276 .disable_hub_initiated_lpm = 1, 277}; 278 279module_usb_driver(bcm203x_driver); 280 281MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); 282MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION); 283MODULE_VERSION(VERSION); 284MODULE_LICENSE("GPL"); 285MODULE_FIRMWARE("BCM2033-MD.hex"); 286MODULE_FIRMWARE("BCM2033-FW.bin"); 287