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