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