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 43 static const struct usb_device_id bcm203x_table[] = { 44 /* Broadcom Blutonium (BCM2033) */ 45 { USB_DEVICE(0x0a5c, 0x2033) }, 46 47 { } /* Terminating entry */ 48 }; 49 50 MODULE_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 63 struct 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 79 static 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 156 static 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 168 static 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 = kzalloc(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 kfree(data); 193 return -ENOMEM; 194 } 195 196 if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) { 197 BT_ERR("Mini driver request failed"); 198 usb_free_urb(data->urb); 199 kfree(data); 200 return -EIO; 201 } 202 203 BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size); 204 205 size = max_t(uint, firmware->size, 4096); 206 207 data->buffer = kmalloc(size, GFP_KERNEL); 208 if (!data->buffer) { 209 BT_ERR("Can't allocate memory for mini driver"); 210 release_firmware(firmware); 211 usb_free_urb(data->urb); 212 kfree(data); 213 return -ENOMEM; 214 } 215 216 memcpy(data->buffer, firmware->data, firmware->size); 217 218 usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), 219 data->buffer, firmware->size, bcm203x_complete, data); 220 221 release_firmware(firmware); 222 223 if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) { 224 BT_ERR("Firmware request failed"); 225 usb_free_urb(data->urb); 226 kfree(data->buffer); 227 kfree(data); 228 return -EIO; 229 } 230 231 BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); 232 233 data->fw_data = kmemdup(firmware->data, firmware->size, GFP_KERNEL); 234 if (!data->fw_data) { 235 BT_ERR("Can't allocate memory for firmware image"); 236 release_firmware(firmware); 237 usb_free_urb(data->urb); 238 kfree(data->buffer); 239 kfree(data); 240 return -ENOMEM; 241 } 242 243 data->fw_size = firmware->size; 244 data->fw_sent = 0; 245 246 release_firmware(firmware); 247 248 INIT_WORK(&data->work, bcm203x_work); 249 250 usb_set_intfdata(intf, data); 251 252 /* use workqueue to have a small delay */ 253 schedule_work(&data->work); 254 255 return 0; 256 } 257 258 static void bcm203x_disconnect(struct usb_interface *intf) 259 { 260 struct bcm203x_data *data = usb_get_intfdata(intf); 261 262 BT_DBG("intf %p", intf); 263 264 atomic_inc(&data->shutdown); 265 cancel_work_sync(&data->work); 266 267 usb_kill_urb(data->urb); 268 269 usb_set_intfdata(intf, NULL); 270 271 usb_free_urb(data->urb); 272 kfree(data->fw_data); 273 kfree(data->buffer); 274 kfree(data); 275 } 276 277 static struct usb_driver bcm203x_driver = { 278 .name = "bcm203x", 279 .probe = bcm203x_probe, 280 .disconnect = bcm203x_disconnect, 281 .id_table = bcm203x_table, 282 }; 283 284 module_usb_driver(bcm203x_driver); 285 286 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); 287 MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION); 288 MODULE_VERSION(VERSION); 289 MODULE_LICENSE("GPL"); 290 MODULE_FIRMWARE("BCM2033-MD.hex"); 291 MODULE_FIRMWARE("BCM2033-FW.bin"); 292