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