Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at eedd726efbc439dbed94fb8577e5533a986b341f 306 lines 7.1 kB view raw
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/kernel.h> 28#include <linux/init.h> 29#include <linux/slab.h> 30#include <linux/types.h> 31#include <linux/errno.h> 32 33#include <linux/device.h> 34#include <linux/firmware.h> 35 36#include <linux/usb.h> 37 38#include <net/bluetooth/bluetooth.h> 39 40#ifndef CONFIG_BT_HCIBCM203X_DEBUG 41#undef BT_DBG 42#define BT_DBG(D...) 43#endif 44 45#define VERSION "1.2" 46 47static struct usb_device_id bcm203x_table[] = { 48 /* Broadcom Blutonium (BCM2033) */ 49 { USB_DEVICE(0x0a5c, 0x2033) }, 50 51 { } /* Terminating entry */ 52}; 53 54MODULE_DEVICE_TABLE(usb, bcm203x_table); 55 56#define BCM203X_ERROR 0 57#define BCM203X_RESET 1 58#define BCM203X_LOAD_MINIDRV 2 59#define BCM203X_SELECT_MEMORY 3 60#define BCM203X_CHECK_MEMORY 4 61#define BCM203X_LOAD_FIRMWARE 5 62#define BCM203X_CHECK_FIRMWARE 6 63 64#define BCM203X_IN_EP 0x81 65#define BCM203X_OUT_EP 0x02 66 67struct bcm203x_data { 68 struct usb_device *udev; 69 70 unsigned long state; 71 72 struct work_struct work; 73 74 struct urb *urb; 75 unsigned char *buffer; 76 77 unsigned char *fw_data; 78 unsigned int fw_size; 79 unsigned int fw_sent; 80}; 81 82static void bcm203x_complete(struct urb *urb) 83{ 84 struct bcm203x_data *data = urb->context; 85 struct usb_device *udev = urb->dev; 86 int len; 87 88 BT_DBG("udev %p urb %p", udev, urb); 89 90 if (urb->status) { 91 BT_ERR("URB failed with status %d", urb->status); 92 data->state = BCM203X_ERROR; 93 return; 94 } 95 96 switch (data->state) { 97 case BCM203X_LOAD_MINIDRV: 98 memcpy(data->buffer, "#", 1); 99 100 usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), 101 data->buffer, 1, bcm203x_complete, data); 102 103 data->state = BCM203X_SELECT_MEMORY; 104 105 schedule_work(&data->work); 106 break; 107 108 case BCM203X_SELECT_MEMORY: 109 usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), 110 data->buffer, 32, bcm203x_complete, data, 1); 111 112 data->state = BCM203X_CHECK_MEMORY; 113 114 if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) 115 BT_ERR("Can't submit URB"); 116 break; 117 118 case BCM203X_CHECK_MEMORY: 119 if (data->buffer[0] != '#') { 120 BT_ERR("Memory select failed"); 121 data->state = BCM203X_ERROR; 122 break; 123 } 124 125 data->state = BCM203X_LOAD_FIRMWARE; 126 127 case BCM203X_LOAD_FIRMWARE: 128 if (data->fw_sent == data->fw_size) { 129 usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), 130 data->buffer, 32, bcm203x_complete, data, 1); 131 132 data->state = BCM203X_CHECK_FIRMWARE; 133 } else { 134 len = min_t(uint, data->fw_size - data->fw_sent, 4096); 135 136 usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), 137 data->fw_data + data->fw_sent, len, bcm203x_complete, data); 138 139 data->fw_sent += len; 140 } 141 142 if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) 143 BT_ERR("Can't submit URB"); 144 break; 145 146 case BCM203X_CHECK_FIRMWARE: 147 if (data->buffer[0] != '.') { 148 BT_ERR("Firmware loading failed"); 149 data->state = BCM203X_ERROR; 150 break; 151 } 152 153 data->state = BCM203X_RESET; 154 break; 155 } 156} 157 158static void bcm203x_work(struct work_struct *work) 159{ 160 struct bcm203x_data *data = 161 container_of(work, struct bcm203x_data, work); 162 163 if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) 164 BT_ERR("Can't submit URB"); 165} 166 167static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id) 168{ 169 const struct firmware *firmware; 170 struct usb_device *udev = interface_to_usbdev(intf); 171 struct bcm203x_data *data; 172 int size; 173 174 BT_DBG("intf %p id %p", intf, id); 175 176 if (intf->cur_altsetting->desc.bInterfaceNumber != 0) 177 return -ENODEV; 178 179 data = kzalloc(sizeof(*data), GFP_KERNEL); 180 if (!data) { 181 BT_ERR("Can't allocate memory for data structure"); 182 return -ENOMEM; 183 } 184 185 data->udev = udev; 186 data->state = BCM203X_LOAD_MINIDRV; 187 188 data->urb = usb_alloc_urb(0, GFP_KERNEL); 189 if (!data->urb) { 190 BT_ERR("Can't allocate URB"); 191 kfree(data); 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 kfree(data); 199 return -EIO; 200 } 201 202 BT_DBG("minidrv data %p size %d", firmware->data, firmware->size); 203 204 size = max_t(uint, firmware->size, 4096); 205 206 data->buffer = kmalloc(size, GFP_KERNEL); 207 if (!data->buffer) { 208 BT_ERR("Can't allocate memory for mini driver"); 209 release_firmware(firmware); 210 usb_free_urb(data->urb); 211 kfree(data); 212 return -ENOMEM; 213 } 214 215 memcpy(data->buffer, firmware->data, firmware->size); 216 217 usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), 218 data->buffer, firmware->size, bcm203x_complete, data); 219 220 release_firmware(firmware); 221 222 if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) { 223 BT_ERR("Firmware request failed"); 224 usb_free_urb(data->urb); 225 kfree(data->buffer); 226 kfree(data); 227 return -EIO; 228 } 229 230 BT_DBG("firmware data %p size %d", firmware->data, firmware->size); 231 232 data->fw_data = kmalloc(firmware->size, GFP_KERNEL); 233 if (!data->fw_data) { 234 BT_ERR("Can't allocate memory for firmware image"); 235 release_firmware(firmware); 236 usb_free_urb(data->urb); 237 kfree(data->buffer); 238 kfree(data); 239 return -ENOMEM; 240 } 241 242 memcpy(data->fw_data, firmware->data, firmware->size); 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 schedule_work(&data->work); 253 254 return 0; 255} 256 257static void bcm203x_disconnect(struct usb_interface *intf) 258{ 259 struct bcm203x_data *data = usb_get_intfdata(intf); 260 261 BT_DBG("intf %p", intf); 262 263 usb_kill_urb(data->urb); 264 265 usb_set_intfdata(intf, NULL); 266 267 usb_free_urb(data->urb); 268 kfree(data->fw_data); 269 kfree(data->buffer); 270 kfree(data); 271} 272 273static struct usb_driver bcm203x_driver = { 274 .name = "bcm203x", 275 .probe = bcm203x_probe, 276 .disconnect = bcm203x_disconnect, 277 .id_table = bcm203x_table, 278}; 279 280static int __init bcm203x_init(void) 281{ 282 int err; 283 284 BT_INFO("Broadcom Blutonium firmware driver ver %s", VERSION); 285 286 err = usb_register(&bcm203x_driver); 287 if (err < 0) 288 BT_ERR("Failed to register USB driver"); 289 290 return err; 291} 292 293static void __exit bcm203x_exit(void) 294{ 295 usb_deregister(&bcm203x_driver); 296} 297 298module_init(bcm203x_init); 299module_exit(bcm203x_exit); 300 301MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); 302MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION); 303MODULE_VERSION(VERSION); 304MODULE_LICENSE("GPL"); 305MODULE_FIRMWARE("BCM2033-MD.hex"); 306MODULE_FIRMWARE("BCM2033-FW.bin");