Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 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 = kmalloc(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         memcpy(data->fw_data, firmware->data, firmware->size);
238         data->fw_size = firmware->size;
239         data->fw_sent = 0;
240 
241         release_firmware(firmware);
242 
243         INIT_WORK(&data->work, bcm203x_work);
244 
245         usb_set_intfdata(intf, data);
246 
247         schedule_work(&data->work);
248 
249         return 0;
250 }
251 
252 static void bcm203x_disconnect(struct usb_interface *intf)
253 {
254         struct bcm203x_data *data = usb_get_intfdata(intf);
255 
256         BT_DBG("intf %p", intf);
257 
258         usb_kill_urb(data->urb);
259 
260         usb_set_intfdata(intf, NULL);
261 
262         usb_free_urb(data->urb);
263         kfree(data->fw_data);
264         kfree(data->buffer);
265         kfree(data);
266 }
267 
268 static struct usb_driver bcm203x_driver = {
269         .name           = "bcm203x",
270         .probe          = bcm203x_probe,
271         .disconnect     = bcm203x_disconnect,
272         .id_table       = bcm203x_table,
273 };
274 
275 static int __init bcm203x_init(void)
276 {
277         int err;
278 
279         BT_INFO("Broadcom Blutonium firmware driver ver %s", VERSION);
280 
281         err = usb_register(&bcm203x_driver);
282         if (err < 0)
283                 BT_ERR("Failed to register USB driver");
284 
285         return err;
286 }
287 
288 static void __exit bcm203x_exit(void)
289 {
290         usb_deregister(&bcm203x_driver);
291 }
292 
293 module_init(bcm203x_init);
294 module_exit(bcm203x_exit);
295 
296 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
297 MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
298 MODULE_VERSION(VERSION);
299 MODULE_LICENSE("GPL");
300 MODULE_FIRMWARE("BCM2033-MD.hex");
301 MODULE_FIRMWARE("BCM2033-FW.bin");
302 
  This page was automatically generated by the LXR engine.