Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bcm203x.c
Go to the documentation of this file.
1 /*
2  *
3  * Broadcom Blutonium firmware driver
4  *
5  * Copyright (C) 2003 Maxim Krasnyansky <[email protected]>
6  * Copyright (C) 2003 Marcel Holtmann <[email protected]>
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/atomic.h>
28 #include <linux/kernel.h>
29 #include <linux/init.h>
30 #include <linux/slab.h>
31 #include <linux/types.h>
32 #include <linux/errno.h>
33 
34 #include <linux/device.h>
35 #include <linux/firmware.h>
36 
37 #include <linux/usb.h>
38 
40 
41 #define VERSION "1.2"
42 
43 static const struct usb_device_id bcm203x_table[] = {
44  /* Broadcom Blutonium (BCM2033) */
45  { USB_DEVICE(0x0a5c, 0x2033) },
46 
47  { } /* Terminating entry */
48 };
49 
50 MODULE_DEVICE_TABLE(usb, bcm203x_table);
51 
52 #define BCM203X_ERROR 0
53 #define BCM203X_RESET 1
54 #define BCM203X_LOAD_MINIDRV 2
55 #define BCM203X_SELECT_MEMORY 3
56 #define BCM203X_CHECK_MEMORY 4
57 #define BCM203X_LOAD_FIRMWARE 5
58 #define BCM203X_CHECK_FIRMWARE 6
59 
60 #define BCM203X_IN_EP 0x81
61 #define BCM203X_OUT_EP 0x02
62 
63 struct bcm203x_data {
64  struct usb_device *udev;
65 
66  unsigned long state;
67 
68  struct work_struct work;
70 
71  struct urb *urb;
72  unsigned char *buffer;
73 
74  unsigned char *fw_data;
75  unsigned int fw_size;
76  unsigned int fw_sent;
77 };
78 
79 static void bcm203x_complete(struct urb *urb)
80 {
81  struct bcm203x_data *data = urb->context;
82  struct usb_device *udev = urb->dev;
83  int len;
84 
85  BT_DBG("udev %p urb %p", udev, urb);
86 
87  if (urb->status) {
88  BT_ERR("URB failed with status %d", urb->status);
89  data->state = BCM203X_ERROR;
90  return;
91  }
92 
93  switch (data->state) {
95  memcpy(data->buffer, "#", 1);
96 
97  usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP),
98  data->buffer, 1, bcm203x_complete, data);
99 
101 
102  /* use workqueue to have a small delay */
103  schedule_work(&data->work);
104  break;
105 
107  usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP),
108  data->buffer, 32, bcm203x_complete, data, 1);
109 
110  data->state = BCM203X_CHECK_MEMORY;
111 
112  if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
113  BT_ERR("Can't submit URB");
114  break;
115 
117  if (data->buffer[0] != '#') {
118  BT_ERR("Memory select failed");
119  data->state = BCM203X_ERROR;
120  break;
121  }
122 
124 
126  if (data->fw_sent == data->fw_size) {
127  usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP),
128  data->buffer, 32, bcm203x_complete, data, 1);
129 
131  } else {
132  len = min_t(uint, data->fw_size - data->fw_sent, 4096);
133 
134  usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP),
135  data->fw_data + data->fw_sent, len, bcm203x_complete, data);
136 
137  data->fw_sent += len;
138  }
139 
140  if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
141  BT_ERR("Can't submit URB");
142  break;
143 
145  if (data->buffer[0] != '.') {
146  BT_ERR("Firmware loading failed");
147  data->state = BCM203X_ERROR;
148  break;
149  }
150 
151  data->state = BCM203X_RESET;
152  break;
153  }
154 }
155 
156 static void bcm203x_work(struct work_struct *work)
157 {
158  struct bcm203x_data *data =
159  container_of(work, struct bcm203x_data, work);
160 
161  if (atomic_read(&data->shutdown))
162  return;
163 
164  if (usb_submit_urb(data->urb, GFP_KERNEL) < 0)
165  BT_ERR("Can't submit URB");
166 }
167 
168 static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id)
169 {
170  const struct firmware *firmware;
171  struct usb_device *udev = interface_to_usbdev(intf);
172  struct bcm203x_data *data;
173  int size;
174 
175  BT_DBG("intf %p id %p", intf, id);
176 
177  if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
178  return -ENODEV;
179 
180  data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
181  if (!data) {
182  BT_ERR("Can't allocate memory for data structure");
183  return -ENOMEM;
184  }
185 
186  data->udev = udev;
187  data->state = BCM203X_LOAD_MINIDRV;
188 
189  data->urb = usb_alloc_urb(0, GFP_KERNEL);
190  if (!data->urb) {
191  BT_ERR("Can't allocate URB");
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  return -EIO;
199  }
200 
201  BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size);
202 
203  size = max_t(uint, firmware->size, 4096);
204 
205  data->buffer = kmalloc(size, GFP_KERNEL);
206  if (!data->buffer) {
207  BT_ERR("Can't allocate memory for mini driver");
208  release_firmware(firmware);
209  usb_free_urb(data->urb);
210  return -ENOMEM;
211  }
212 
213  memcpy(data->buffer, firmware->data, firmware->size);
214 
215  usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP),
216  data->buffer, firmware->size, bcm203x_complete, data);
217 
218  release_firmware(firmware);
219 
220  if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) {
221  BT_ERR("Firmware request failed");
222  usb_free_urb(data->urb);
223  kfree(data->buffer);
224  return -EIO;
225  }
226 
227  BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
228 
229  data->fw_data = kmemdup(firmware->data, firmware->size, GFP_KERNEL);
230  if (!data->fw_data) {
231  BT_ERR("Can't allocate memory for firmware image");
232  release_firmware(firmware);
233  usb_free_urb(data->urb);
234  kfree(data->buffer);
235  return -ENOMEM;
236  }
237 
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  /* use workqueue to have a small delay */
248  schedule_work(&data->work);
249 
250  return 0;
251 }
252 
253 static void bcm203x_disconnect(struct usb_interface *intf)
254 {
255  struct bcm203x_data *data = usb_get_intfdata(intf);
256 
257  BT_DBG("intf %p", intf);
258 
259  atomic_inc(&data->shutdown);
260  cancel_work_sync(&data->work);
261 
262  usb_kill_urb(data->urb);
263 
264  usb_set_intfdata(intf, NULL);
265 
266  usb_free_urb(data->urb);
267  kfree(data->fw_data);
268  kfree(data->buffer);
269 }
270 
271 static struct usb_driver bcm203x_driver = {
272  .name = "bcm203x",
273  .probe = bcm203x_probe,
274  .disconnect = bcm203x_disconnect,
275  .id_table = bcm203x_table,
276  .disable_hub_initiated_lpm = 1,
277 };
278 
279 module_usb_driver(bcm203x_driver);
280 
281 MODULE_AUTHOR("Marcel Holtmann <[email protected]>");
282 MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
284 MODULE_LICENSE("GPL");
285 MODULE_FIRMWARE("BCM2033-MD.hex");
286 MODULE_FIRMWARE("BCM2033-FW.bin");