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