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