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