Commit | Line | Data |
---|---|---|
876c9d3a MT |
1 | /** |
2 | * This file contains functions used in USB interface module. | |
3 | */ | |
4 | #include <linux/delay.h> | |
5 | #include <linux/firmware.h> | |
6 | #include <linux/netdevice.h> | |
7 | #include <linux/usb.h> | |
8 | ||
9 | #include "host.h" | |
876c9d3a MT |
10 | #include "decl.h" |
11 | #include "defs.h" | |
12 | #include "dev.h" | |
13 | #include "if_usb.h" | |
14 | ||
15 | #define MESSAGE_HEADER_LEN 4 | |
16 | ||
17 | static const char usbdriver_name[] = "usb8xxx"; | |
18 | ||
3874d0fe HS |
19 | #define MAX_DEVS 5 |
20 | static struct net_device *libertas_devs[MAX_DEVS]; | |
21 | static int libertas_found = 0; | |
22 | ||
876c9d3a MT |
23 | static struct usb_device_id if_usb_table[] = { |
24 | /* Enter the device signature inside */ | |
66fcc559 HS |
25 | { USB_DEVICE(0x1286, 0x2001) }, |
26 | { USB_DEVICE(0x05a3, 0x8388) }, | |
876c9d3a MT |
27 | {} /* Terminating entry */ |
28 | }; | |
29 | ||
30 | MODULE_DEVICE_TABLE(usb, if_usb_table); | |
31 | ||
32 | static void if_usb_receive(struct urb *urb); | |
33 | static void if_usb_receive_fwload(struct urb *urb); | |
3874d0fe | 34 | static int reset_device(wlan_private *priv); |
208fdd2f HS |
35 | static int if_usb_register_dev(wlan_private * priv); |
36 | static int if_usb_unregister_dev(wlan_private *); | |
37 | static int if_usb_prog_firmware(wlan_private *); | |
38 | static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); | |
39 | static int if_usb_get_int_status(wlan_private * priv, u8 *); | |
40 | static int if_usb_read_event_cause(wlan_private *); | |
876c9d3a MT |
41 | |
42 | /** | |
43 | * @brief call back function to handle the status of the URB | |
44 | * @param urb pointer to urb structure | |
45 | * @return N/A | |
46 | */ | |
47 | static void if_usb_write_bulk_callback(struct urb *urb) | |
48 | { | |
49 | wlan_private *priv = (wlan_private *) (urb->context); | |
50 | wlan_adapter *adapter = priv->adapter; | |
51 | struct net_device *dev = priv->wlan_dev.netdev; | |
52 | ||
53 | /* handle the transmission complete validations */ | |
54 | ||
55 | if (urb->status != 0) { | |
56 | /* print the failure status number for debug */ | |
57 | lbs_pr_info("URB in failure status\n"); | |
58 | } else { | |
9012b28a HS |
59 | /* |
60 | lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n"); | |
61 | lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n", | |
876c9d3a | 62 | urb->actual_length); |
9012b28a | 63 | */ |
876c9d3a MT |
64 | priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; |
65 | /* Wake main thread if commands are pending */ | |
66 | if (!adapter->cur_cmd) | |
67 | wake_up_interruptible(&priv->mainthread.waitq); | |
51d84f50 | 68 | if ((adapter->connect_status == libertas_connected)) { |
876c9d3a | 69 | netif_wake_queue(dev); |
51d84f50 JC |
70 | netif_wake_queue(priv->mesh_dev); |
71 | } | |
876c9d3a MT |
72 | } |
73 | ||
74 | return; | |
75 | } | |
76 | ||
77 | /** | |
78 | * @brief free tx/rx urb, skb and rx buffer | |
79 | * @param cardp pointer usb_card_rec | |
80 | * @return N/A | |
81 | */ | |
82 | void if_usb_free(struct usb_card_rec *cardp) | |
83 | { | |
9012b28a | 84 | lbs_deb_enter(LBS_DEB_USB); |
876c9d3a MT |
85 | |
86 | /* Unlink tx & rx urb */ | |
87 | usb_kill_urb(cardp->tx_urb); | |
88 | usb_kill_urb(cardp->rx_urb); | |
89 | ||
90 | usb_free_urb(cardp->tx_urb); | |
91 | cardp->tx_urb = NULL; | |
92 | ||
93 | usb_free_urb(cardp->rx_urb); | |
94 | cardp->rx_urb = NULL; | |
95 | ||
96 | kfree(cardp->bulk_out_buffer); | |
97 | cardp->bulk_out_buffer = NULL; | |
98 | ||
9012b28a | 99 | lbs_deb_leave(LBS_DEB_USB); |
876c9d3a MT |
100 | } |
101 | ||
102 | /** | |
103 | * @brief sets the configuration values | |
104 | * @param ifnum interface number | |
105 | * @param id pointer to usb_device_id | |
106 | * @return 0 on success, error code on failure | |
107 | */ | |
108 | static int if_usb_probe(struct usb_interface *intf, | |
109 | const struct usb_device_id *id) | |
110 | { | |
111 | struct usb_device *udev; | |
112 | struct usb_host_interface *iface_desc; | |
113 | struct usb_endpoint_descriptor *endpoint; | |
78523daa | 114 | wlan_private *priv; |
876c9d3a MT |
115 | struct usb_card_rec *usb_cardp; |
116 | int i; | |
117 | ||
118 | udev = interface_to_usbdev(intf); | |
119 | ||
120 | usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); | |
121 | if (!usb_cardp) { | |
122 | lbs_pr_err("Out of memory allocating private data.\n"); | |
123 | goto error; | |
124 | } | |
125 | ||
126 | usb_cardp->udev = udev; | |
127 | iface_desc = intf->cur_altsetting; | |
128 | ||
9012b28a | 129 | lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X" |
876c9d3a MT |
130 | " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", |
131 | udev->descriptor.bcdUSB, | |
132 | udev->descriptor.bDeviceClass, | |
133 | udev->descriptor.bDeviceSubClass, | |
134 | udev->descriptor.bDeviceProtocol); | |
135 | ||
136 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | |
137 | endpoint = &iface_desc->endpoint[i].desc; | |
138 | if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) | |
139 | && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | |
140 | USB_ENDPOINT_XFER_BULK)) { | |
141 | /* we found a bulk in endpoint */ | |
9012b28a | 142 | lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", |
876c9d3a MT |
143 | endpoint->wMaxPacketSize); |
144 | if (! | |
145 | (usb_cardp->rx_urb = | |
146 | usb_alloc_urb(0, GFP_KERNEL))) { | |
9012b28a | 147 | lbs_deb_usbd(&udev->dev, |
876c9d3a MT |
148 | "Rx URB allocation failed\n"); |
149 | goto dealloc; | |
150 | } | |
151 | usb_cardp->rx_urb_recall = 0; | |
152 | ||
153 | usb_cardp->bulk_in_size = | |
154 | endpoint->wMaxPacketSize; | |
155 | usb_cardp->bulk_in_endpointAddr = | |
156 | (endpoint-> | |
157 | bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | |
9012b28a | 158 | lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", |
876c9d3a MT |
159 | endpoint->bEndpointAddress); |
160 | } | |
161 | ||
162 | if (((endpoint-> | |
163 | bEndpointAddress & USB_ENDPOINT_DIR_MASK) == | |
164 | USB_DIR_OUT) | |
165 | && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | |
166 | USB_ENDPOINT_XFER_BULK)) { | |
167 | /* We found bulk out endpoint */ | |
168 | if (! | |
169 | (usb_cardp->tx_urb = | |
170 | usb_alloc_urb(0, GFP_KERNEL))) { | |
9012b28a | 171 | lbs_deb_usbd(&udev->dev, |
876c9d3a MT |
172 | "Tx URB allocation failed\n"); |
173 | goto dealloc; | |
174 | } | |
175 | ||
176 | usb_cardp->bulk_out_size = | |
177 | endpoint->wMaxPacketSize; | |
9012b28a | 178 | lbs_deb_usbd(&udev->dev, |
876c9d3a MT |
179 | "Bulk out size is %d\n", |
180 | endpoint->wMaxPacketSize); | |
181 | usb_cardp->bulk_out_endpointAddr = | |
182 | endpoint->bEndpointAddress; | |
9012b28a | 183 | lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", |
876c9d3a MT |
184 | endpoint->bEndpointAddress); |
185 | usb_cardp->bulk_out_buffer = | |
186 | kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, | |
187 | GFP_KERNEL); | |
188 | ||
189 | if (!usb_cardp->bulk_out_buffer) { | |
9012b28a | 190 | lbs_deb_usbd(&udev->dev, |
876c9d3a MT |
191 | "Could not allocate buffer\n"); |
192 | goto dealloc; | |
193 | } | |
194 | } | |
195 | } | |
196 | ||
197 | ||
198 | /* At this point wlan_add_card() will be called. Don't worry | |
199 | * about keeping pwlanpriv around since it will be set on our | |
208fdd2f | 200 | * usb device data in -> add() -> hw_register_dev() -> if_usb_register_dev. |
876c9d3a | 201 | */ |
78523daa HS |
202 | if (!(priv = wlan_add_card(usb_cardp))) |
203 | goto dealloc; | |
3874d0fe | 204 | |
51d84f50 | 205 | if (wlan_add_mesh(priv)) |
6a812157 | 206 | goto err_add_mesh; |
51d84f50 | 207 | |
208fdd2f HS |
208 | priv->hw_register_dev = if_usb_register_dev; |
209 | priv->hw_unregister_dev = if_usb_unregister_dev; | |
210 | priv->hw_prog_firmware = if_usb_prog_firmware; | |
211 | priv->hw_host_to_card = if_usb_host_to_card; | |
212 | priv->hw_get_int_status = if_usb_get_int_status; | |
213 | priv->hw_read_event_cause = if_usb_read_event_cause; | |
214 | ||
32a74b7c | 215 | if (libertas_activate_card(priv)) |
6a812157 | 216 | goto err_activate_card; |
32a74b7c | 217 | |
3874d0fe HS |
218 | if (libertas_found < MAX_DEVS) { |
219 | libertas_devs[libertas_found] = priv->wlan_dev.netdev; | |
220 | libertas_found++; | |
221 | } | |
222 | ||
876c9d3a MT |
223 | usb_get_dev(udev); |
224 | usb_set_intfdata(intf, usb_cardp); | |
225 | ||
226 | /* | |
227 | * return card structure, which can be got back in the | |
228 | * diconnect function as the ptr | |
229 | * argument. | |
230 | */ | |
231 | return 0; | |
232 | ||
6a812157 MT |
233 | err_activate_card: |
234 | unregister_netdev(priv->mesh_dev); | |
235 | free_netdev(priv->mesh_dev); | |
236 | err_add_mesh: | |
237 | free_netdev(priv->wlan_dev.netdev); | |
238 | kfree(priv->adapter); | |
876c9d3a MT |
239 | dealloc: |
240 | if_usb_free(usb_cardp); | |
241 | ||
242 | error: | |
243 | return -ENOMEM; | |
244 | } | |
245 | ||
246 | /** | |
247 | * @brief free resource and cleanup | |
248 | * @param udev pointer to usb_device | |
249 | * @param ptr pointer to usb_cardp | |
250 | * @return N/A | |
251 | */ | |
252 | static void if_usb_disconnect(struct usb_interface *intf) | |
253 | { | |
254 | struct usb_card_rec *cardp = usb_get_intfdata(intf); | |
255 | wlan_private *priv = (wlan_private *) cardp->priv; | |
256 | wlan_adapter *adapter = NULL; | |
3874d0fe | 257 | int i; |
876c9d3a MT |
258 | |
259 | adapter = priv->adapter; | |
260 | ||
261 | /* | |
262 | * Update Surprise removed to TRUE | |
263 | */ | |
264 | adapter->surpriseremoved = 1; | |
265 | ||
3874d0fe HS |
266 | for (i = 0; i<libertas_found; i++) { |
267 | if (libertas_devs[i]==priv->wlan_dev.netdev) { | |
268 | libertas_devs[i] = libertas_devs[--libertas_found]; | |
269 | libertas_devs[libertas_found] = NULL ; | |
270 | break; | |
271 | } | |
272 | } | |
273 | ||
876c9d3a | 274 | /* card is removed and we can call wlan_remove_card */ |
9012b28a | 275 | lbs_deb_usbd(&cardp->udev->dev, "call remove card\n"); |
78523daa | 276 | wlan_remove_mesh(priv); |
1ac812f1 | 277 | wlan_remove_card(priv); |
876c9d3a MT |
278 | |
279 | /* Unlink and free urb */ | |
280 | if_usb_free(cardp); | |
281 | ||
282 | usb_set_intfdata(intf, NULL); | |
283 | usb_put_dev(interface_to_usbdev(intf)); | |
284 | ||
285 | return; | |
286 | } | |
287 | ||
288 | /** | |
289 | * @brief This function download FW | |
290 | * @param priv pointer to wlan_private | |
291 | * @return 0 | |
292 | */ | |
293 | static int if_prog_firmware(wlan_private * priv) | |
294 | { | |
295 | struct usb_card_rec *cardp = priv->wlan_dev.card; | |
296 | struct FWData *fwdata; | |
297 | struct fwheader *fwheader; | |
298 | u8 *firmware = priv->firmware->data; | |
299 | ||
300 | fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); | |
301 | ||
302 | if (!fwdata) | |
303 | return -1; | |
304 | ||
305 | fwheader = &fwdata->fwheader; | |
306 | ||
307 | if (!cardp->CRC_OK) { | |
308 | cardp->totalbytes = cardp->fwlastblksent; | |
309 | cardp->fwseqnum = cardp->lastseqnum - 1; | |
310 | } | |
311 | ||
9012b28a HS |
312 | /* |
313 | lbs_deb_usbd(&cardp->udev->dev, "totalbytes = %d\n", | |
876c9d3a | 314 | cardp->totalbytes); |
9012b28a | 315 | */ |
876c9d3a MT |
316 | |
317 | memcpy(fwheader, &firmware[cardp->totalbytes], | |
318 | sizeof(struct fwheader)); | |
319 | ||
320 | cardp->fwlastblksent = cardp->totalbytes; | |
321 | cardp->totalbytes += sizeof(struct fwheader); | |
322 | ||
9012b28a | 323 | /* lbs_deb_usbd(&cardp->udev->dev,"Copy Data\n"); */ |
876c9d3a MT |
324 | memcpy(fwdata->data, &firmware[cardp->totalbytes], |
325 | fwdata->fwheader.datalength); | |
326 | ||
9012b28a HS |
327 | /* |
328 | lbs_deb_usbd(&cardp->udev->dev, | |
876c9d3a | 329 | "Data length = %d\n", fwdata->fwheader.datalength); |
9012b28a | 330 | */ |
876c9d3a MT |
331 | |
332 | cardp->fwseqnum = cardp->fwseqnum + 1; | |
333 | ||
334 | fwdata->seqnum = cardp->fwseqnum; | |
335 | cardp->lastseqnum = fwdata->seqnum; | |
336 | cardp->totalbytes += fwdata->fwheader.datalength; | |
337 | ||
338 | if (fwheader->dnldcmd == FW_HAS_DATA_TO_RECV) { | |
9012b28a HS |
339 | /* |
340 | lbs_deb_usbd(&cardp->udev->dev, "There is data to follow\n"); | |
341 | lbs_deb_usbd(&cardp->udev->dev, | |
876c9d3a MT |
342 | "seqnum = %d totalbytes = %d\n", cardp->fwseqnum, |
343 | cardp->totalbytes); | |
9012b28a | 344 | */ |
876c9d3a MT |
345 | memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); |
346 | usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); | |
347 | ||
348 | } else if (fwdata->fwheader.dnldcmd == FW_HAS_LAST_BLOCK) { | |
9012b28a HS |
349 | /* |
350 | lbs_deb_usbd(&cardp->udev->dev, | |
876c9d3a | 351 | "Host has finished FW downloading\n"); |
9012b28a | 352 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a | 353 | "Donwloading FW JUMP BLOCK\n"); |
9012b28a | 354 | */ |
876c9d3a MT |
355 | memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); |
356 | usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); | |
357 | cardp->fwfinalblk = 1; | |
358 | } | |
359 | ||
9012b28a HS |
360 | /* |
361 | lbs_deb_usbd(&cardp->udev->dev, | |
876c9d3a MT |
362 | "The firmware download is done size is %d\n", |
363 | cardp->totalbytes); | |
9012b28a | 364 | */ |
876c9d3a MT |
365 | |
366 | kfree(fwdata); | |
367 | ||
368 | return 0; | |
369 | } | |
370 | ||
371 | static int libertas_do_reset(wlan_private *priv) | |
372 | { | |
373 | int ret; | |
374 | struct usb_card_rec *cardp = priv->wlan_dev.card; | |
375 | ||
3874d0fe HS |
376 | lbs_deb_enter(LBS_DEB_USB); |
377 | ||
876c9d3a MT |
378 | ret = usb_reset_device(cardp->udev); |
379 | if (!ret) { | |
380 | msleep(10); | |
381 | reset_device(priv); | |
382 | msleep(10); | |
383 | } | |
3874d0fe HS |
384 | |
385 | lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); | |
386 | ||
876c9d3a MT |
387 | return ret; |
388 | } | |
389 | ||
390 | /** | |
391 | * @brief This function transfer the data to the device. | |
392 | * @param priv pointer to wlan_private | |
393 | * @param payload pointer to payload data | |
394 | * @param nb data length | |
395 | * @return 0 or -1 | |
396 | */ | |
397 | int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) | |
398 | { | |
399 | /* pointer to card structure */ | |
400 | struct usb_card_rec *cardp = priv->wlan_dev.card; | |
401 | int ret = -1; | |
402 | ||
403 | /* check if device is removed */ | |
404 | if (priv->adapter->surpriseremoved) { | |
9012b28a | 405 | lbs_deb_usbd(&cardp->udev->dev, "Device removed\n"); |
876c9d3a MT |
406 | goto tx_ret; |
407 | } | |
408 | ||
409 | usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, | |
410 | usb_sndbulkpipe(cardp->udev, | |
411 | cardp->bulk_out_endpointAddr), | |
412 | payload, nb, if_usb_write_bulk_callback, priv); | |
413 | ||
414 | cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; | |
415 | ||
416 | if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { | |
417 | /* transfer failed */ | |
9012b28a | 418 | lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed\n"); |
876c9d3a MT |
419 | ret = -1; |
420 | } else { | |
9012b28a | 421 | /* lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb success\n"); */ |
876c9d3a MT |
422 | ret = 0; |
423 | } | |
424 | ||
425 | tx_ret: | |
426 | return ret; | |
427 | } | |
428 | ||
429 | static int __if_usb_submit_rx_urb(wlan_private * priv, | |
430 | void (*callbackfn) | |
431 | (struct urb *urb)) | |
432 | { | |
433 | struct usb_card_rec *cardp = priv->wlan_dev.card; | |
434 | struct sk_buff *skb; | |
435 | struct read_cb_info *rinfo = &cardp->rinfo; | |
436 | int ret = -1; | |
437 | ||
438 | if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { | |
439 | lbs_pr_err("No free skb\n"); | |
440 | goto rx_ret; | |
441 | } | |
442 | ||
443 | rinfo->skb = skb; | |
444 | ||
445 | /* Fill the receive configuration URB and initialise the Rx call back */ | |
446 | usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, | |
447 | usb_rcvbulkpipe(cardp->udev, | |
448 | cardp->bulk_in_endpointAddr), | |
4269e2ad | 449 | (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET), |
876c9d3a MT |
450 | MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, |
451 | rinfo); | |
452 | ||
453 | cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; | |
454 | ||
9012b28a | 455 | /* lbs_deb_usbd(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); */ |
876c9d3a MT |
456 | if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { |
457 | /* handle failure conditions */ | |
9012b28a | 458 | lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed\n"); |
876c9d3a MT |
459 | ret = -1; |
460 | } else { | |
9012b28a | 461 | /* lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB success\n"); */ |
876c9d3a MT |
462 | ret = 0; |
463 | } | |
464 | ||
465 | rx_ret: | |
466 | return ret; | |
467 | } | |
468 | ||
469 | static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv) | |
470 | { | |
471 | return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload); | |
472 | } | |
473 | ||
474 | static inline int if_usb_submit_rx_urb(wlan_private * priv) | |
475 | { | |
476 | return __if_usb_submit_rx_urb(priv, &if_usb_receive); | |
477 | } | |
478 | ||
479 | static void if_usb_receive_fwload(struct urb *urb) | |
480 | { | |
481 | struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; | |
482 | wlan_private *priv = rinfo->priv; | |
483 | struct sk_buff *skb = rinfo->skb; | |
484 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; | |
485 | struct fwsyncheader *syncfwheader; | |
486 | struct bootcmdrespStr bootcmdresp; | |
487 | ||
488 | if (urb->status) { | |
9012b28a | 489 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
490 | "URB status is failed during fw load\n"); |
491 | kfree_skb(skb); | |
492 | return; | |
493 | } | |
494 | ||
495 | if (cardp->bootcmdresp == 0) { | |
496 | memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET, | |
497 | sizeof(bootcmdresp)); | |
498 | if (cardp->udev->descriptor.bcdDevice < 0x3106) { | |
499 | kfree_skb(skb); | |
500 | if_usb_submit_rx_urb_fwload(priv); | |
501 | cardp->bootcmdresp = 1; | |
9012b28a | 502 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
503 | "Received valid boot command response\n"); |
504 | return; | |
505 | } | |
506 | if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) { | |
507 | lbs_pr_info( | |
508 | "boot cmd response wrong magic number (0x%x)\n", | |
509 | bootcmdresp.u32magicnumber); | |
510 | } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) { | |
511 | lbs_pr_info( | |
512 | "boot cmd response cmd_tag error (%d)\n", | |
513 | bootcmdresp.u8cmd_tag); | |
514 | } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) { | |
515 | lbs_pr_info( | |
516 | "boot cmd response result error (%d)\n", | |
517 | bootcmdresp.u8result); | |
518 | } else { | |
519 | cardp->bootcmdresp = 1; | |
9012b28a | 520 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
521 | "Received valid boot command response\n"); |
522 | } | |
523 | kfree_skb(skb); | |
524 | if_usb_submit_rx_urb_fwload(priv); | |
525 | return; | |
526 | } | |
527 | ||
528 | syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC); | |
529 | if (!syncfwheader) { | |
9012b28a | 530 | lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n"); |
876c9d3a MT |
531 | kfree_skb(skb); |
532 | return; | |
533 | } | |
534 | ||
535 | memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET, | |
536 | sizeof(struct fwsyncheader)); | |
537 | ||
538 | if (!syncfwheader->cmd) { | |
9012b28a HS |
539 | /* |
540 | lbs_deb_usbd(&cardp->udev->dev, | |
876c9d3a | 541 | "FW received Blk with correct CRC\n"); |
9012b28a | 542 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
543 | "FW received Blk seqnum = %d\n", |
544 | syncfwheader->seqnum); | |
9012b28a | 545 | */ |
876c9d3a MT |
546 | cardp->CRC_OK = 1; |
547 | } else { | |
9012b28a | 548 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
549 | "FW received Blk with CRC error\n"); |
550 | cardp->CRC_OK = 0; | |
551 | } | |
552 | ||
553 | kfree_skb(skb); | |
554 | ||
555 | if (cardp->fwfinalblk) { | |
556 | cardp->fwdnldover = 1; | |
557 | goto exit; | |
558 | } | |
559 | ||
560 | if_prog_firmware(priv); | |
561 | ||
562 | if_usb_submit_rx_urb_fwload(priv); | |
563 | exit: | |
564 | kfree(syncfwheader); | |
565 | ||
566 | return; | |
567 | ||
568 | } | |
569 | ||
570 | #define MRVDRV_MIN_PKT_LEN 30 | |
571 | ||
572 | static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, | |
573 | struct usb_card_rec *cardp, | |
574 | wlan_private *priv) | |
575 | { | |
576 | if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + | |
577 | MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) { | |
9012b28a | 578 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
579 | "Packet length is Invalid\n"); |
580 | kfree_skb(skb); | |
581 | return; | |
582 | } | |
583 | ||
584 | skb_reserve(skb, IPFIELD_ALIGN_OFFSET); | |
585 | skb_put(skb, recvlength); | |
586 | skb_pull(skb, MESSAGE_HEADER_LEN); | |
587 | libertas_process_rxed_packet(priv, skb); | |
588 | priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN); | |
589 | } | |
590 | ||
591 | static inline void process_cmdrequest(int recvlength, u8 *recvbuff, | |
592 | struct sk_buff *skb, | |
593 | struct usb_card_rec *cardp, | |
594 | wlan_private *priv) | |
595 | { | |
596 | u8 *cmdbuf; | |
597 | if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) { | |
9012b28a | 598 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
599 | "The receive buffer is too large\n"); |
600 | kfree_skb(skb); | |
601 | return; | |
602 | } | |
603 | ||
604 | if (!in_interrupt()) | |
605 | BUG(); | |
606 | ||
607 | spin_lock(&priv->adapter->driver_lock); | |
608 | /* take care of cur_cmd = NULL case by reading the | |
609 | * data to clear the interrupt */ | |
610 | if (!priv->adapter->cur_cmd) { | |
611 | cmdbuf = priv->wlan_dev.upld_buf; | |
612 | priv->adapter->hisregcpy &= ~his_cmdupldrdy; | |
613 | } else | |
614 | cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; | |
615 | ||
616 | cardp->usb_int_cause |= his_cmdupldrdy; | |
617 | priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN); | |
618 | memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN, | |
619 | priv->wlan_dev.upld_len); | |
620 | ||
621 | kfree_skb(skb); | |
622 | libertas_interrupt(priv->wlan_dev.netdev); | |
623 | spin_unlock(&priv->adapter->driver_lock); | |
624 | ||
9012b28a | 625 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
626 | "Wake up main thread to handle cmd response\n"); |
627 | ||
628 | return; | |
629 | } | |
630 | ||
631 | /** | |
632 | * @brief This function reads of the packet into the upload buff, | |
633 | * wake up the main thread and initialise the Rx callack. | |
634 | * | |
635 | * @param urb pointer to struct urb | |
636 | * @return N/A | |
637 | */ | |
638 | static void if_usb_receive(struct urb *urb) | |
639 | { | |
640 | struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; | |
641 | wlan_private *priv = rinfo->priv; | |
642 | struct sk_buff *skb = rinfo->skb; | |
643 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; | |
644 | ||
645 | int recvlength = urb->actual_length; | |
646 | u8 *recvbuff = NULL; | |
647 | u32 recvtype; | |
648 | ||
9012b28a | 649 | lbs_deb_enter(LBS_DEB_USB); |
876c9d3a MT |
650 | |
651 | if (recvlength) { | |
652 | if (urb->status) { | |
9012b28a | 653 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
654 | "URB status is failed\n"); |
655 | kfree_skb(skb); | |
656 | goto setup_for_next; | |
657 | } | |
658 | ||
659 | recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; | |
660 | memcpy(&recvtype, recvbuff, sizeof(u32)); | |
9012b28a | 661 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a | 662 | "Recv length = 0x%x\n", recvlength); |
9012b28a | 663 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
664 | "Receive type = 0x%X\n", recvtype); |
665 | recvtype = le32_to_cpu(recvtype); | |
9012b28a | 666 | lbs_deb_usbd(&cardp->udev->dev, |
876c9d3a MT |
667 | "Receive type after = 0x%X\n", recvtype); |
668 | } else if (urb->status) | |
669 | goto rx_exit; | |
670 | ||
671 | ||
672 | switch (recvtype) { | |
673 | case CMD_TYPE_DATA: | |
674 | process_cmdtypedata(recvlength, skb, cardp, priv); | |
675 | break; | |
676 | ||
677 | case CMD_TYPE_REQUEST: | |
678 | process_cmdrequest(recvlength, recvbuff, skb, cardp, priv); | |
679 | break; | |
680 | ||
681 | case CMD_TYPE_INDICATION: | |
682 | /* Event cause handling */ | |
683 | spin_lock(&priv->adapter->driver_lock); | |
684 | cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN); | |
9012b28a | 685 | lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n", |
876c9d3a MT |
686 | cardp->usb_event_cause); |
687 | if (cardp->usb_event_cause & 0xffff0000) { | |
688 | libertas_send_tx_feedback(priv); | |
12a4d265 | 689 | spin_unlock(&priv->adapter->driver_lock); |
876c9d3a MT |
690 | break; |
691 | } | |
692 | cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3; | |
693 | cardp->usb_int_cause |= his_cardevent; | |
694 | kfree_skb(skb); | |
695 | libertas_interrupt(priv->wlan_dev.netdev); | |
696 | spin_unlock(&priv->adapter->driver_lock); | |
697 | goto rx_exit; | |
698 | default: | |
699 | kfree_skb(skb); | |
700 | break; | |
701 | } | |
702 | ||
703 | setup_for_next: | |
704 | if_usb_submit_rx_urb(priv); | |
705 | rx_exit: | |
9012b28a | 706 | lbs_deb_leave(LBS_DEB_USB); |
876c9d3a MT |
707 | } |
708 | ||
709 | /** | |
710 | * @brief This function downloads data to FW | |
711 | * @param priv pointer to wlan_private structure | |
712 | * @param type type of data | |
713 | * @param buf pointer to data buffer | |
714 | * @param len number of bytes | |
715 | * @return 0 or -1 | |
716 | */ | |
208fdd2f | 717 | static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb) |
876c9d3a MT |
718 | { |
719 | int ret = -1; | |
720 | u32 tmp; | |
721 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; | |
722 | ||
9012b28a HS |
723 | lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type); |
724 | lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb); | |
876c9d3a MT |
725 | |
726 | if (type == MVMS_CMD) { | |
727 | tmp = cpu_to_le32(CMD_TYPE_REQUEST); | |
728 | priv->wlan_dev.dnld_sent = DNLD_CMD_SENT; | |
729 | memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, | |
730 | MESSAGE_HEADER_LEN); | |
731 | ||
732 | } else { | |
733 | tmp = cpu_to_le32(CMD_TYPE_DATA); | |
734 | priv->wlan_dev.dnld_sent = DNLD_DATA_SENT; | |
735 | memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, | |
736 | MESSAGE_HEADER_LEN); | |
737 | } | |
738 | ||
739 | memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); | |
740 | ||
741 | ret = | |
742 | usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN); | |
743 | ||
744 | return ret; | |
745 | } | |
746 | ||
747 | /* called with adapter->driver_lock held */ | |
208fdd2f | 748 | static int if_usb_get_int_status(wlan_private * priv, u8 * ireg) |
876c9d3a MT |
749 | { |
750 | struct usb_card_rec *cardp = priv->wlan_dev.card; | |
751 | ||
752 | *ireg = cardp->usb_int_cause; | |
753 | cardp->usb_int_cause = 0; | |
754 | ||
9012b28a | 755 | lbs_deb_usbd(&cardp->udev->dev,"Int cause is 0x%X\n", *ireg); |
876c9d3a MT |
756 | |
757 | return 0; | |
758 | } | |
759 | ||
208fdd2f | 760 | static int if_usb_read_event_cause(wlan_private * priv) |
876c9d3a MT |
761 | { |
762 | struct usb_card_rec *cardp = priv->wlan_dev.card; | |
763 | priv->adapter->eventcause = cardp->usb_event_cause; | |
764 | /* Re-submit rx urb here to avoid event lost issue */ | |
765 | if_usb_submit_rx_urb(priv); | |
766 | return 0; | |
767 | } | |
768 | ||
3874d0fe | 769 | static int reset_device(wlan_private *priv) |
876c9d3a MT |
770 | { |
771 | int ret; | |
772 | ||
3874d0fe | 773 | lbs_deb_enter(LBS_DEB_USB); |
876c9d3a MT |
774 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset, |
775 | cmd_act_halt, 0, 0, NULL); | |
776 | msleep_interruptible(10); | |
777 | ||
3874d0fe | 778 | lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); |
876c9d3a MT |
779 | return ret; |
780 | } | |
781 | ||
208fdd2f | 782 | static int if_usb_unregister_dev(wlan_private * priv) |
876c9d3a MT |
783 | { |
784 | int ret = 0; | |
785 | ||
786 | /* Need to send a Reset command to device before USB resources freed | |
787 | * and wlan_remove_card() called, then device can handle FW download | |
788 | * again. | |
789 | */ | |
790 | if (priv) | |
791 | reset_device(priv); | |
792 | ||
793 | return ret; | |
794 | } | |
795 | ||
796 | ||
797 | /** | |
798 | * @brief This function register usb device and initialize parameter | |
799 | * @param priv pointer to wlan_private | |
800 | * @return 0 or -1 | |
801 | */ | |
208fdd2f | 802 | static int if_usb_register_dev(wlan_private * priv) |
876c9d3a | 803 | { |
876c9d3a | 804 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; |
9012b28a HS |
805 | |
806 | lbs_deb_enter(LBS_DEB_USB); | |
876c9d3a MT |
807 | |
808 | cardp->priv = priv; | |
809 | cardp->eth_dev = priv->wlan_dev.netdev; | |
810 | priv->hotplug_device = &(cardp->udev->dev); | |
811 | ||
812 | SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev)); | |
51d84f50 | 813 | SET_NETDEV_DEV(priv->mesh_dev, &(cardp->udev->dev)); |
876c9d3a | 814 | |
9012b28a | 815 | lbs_deb_usbd(&cardp->udev->dev, "udev pointer is at %p\n", |
876c9d3a MT |
816 | cardp->udev); |
817 | ||
9012b28a | 818 | lbs_deb_leave(LBS_DEB_USB); |
876c9d3a MT |
819 | return 0; |
820 | } | |
821 | ||
822 | ||
823 | ||
208fdd2f | 824 | static int if_usb_prog_firmware(wlan_private * priv) |
876c9d3a MT |
825 | { |
826 | struct usb_card_rec *cardp = priv->wlan_dev.card; | |
827 | int i = 0; | |
828 | static int reset_count = 10; | |
9012b28a | 829 | int ret = 0; |
876c9d3a | 830 | |
9012b28a | 831 | lbs_deb_enter(LBS_DEB_USB); |
876c9d3a MT |
832 | |
833 | cardp->rinfo.priv = priv; | |
834 | ||
835 | restart: | |
836 | if (if_usb_submit_rx_urb_fwload(priv) < 0) { | |
9012b28a HS |
837 | lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); |
838 | ret = -1; | |
839 | goto done; | |
876c9d3a MT |
840 | } |
841 | ||
876c9d3a MT |
842 | cardp->bootcmdresp = 0; |
843 | do { | |
844 | int j = 0; | |
845 | i++; | |
846 | /* Issue Boot command = 1, Boot from Download-FW */ | |
847 | if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB); | |
848 | /* wait for command response */ | |
849 | do { | |
850 | j++; | |
851 | msleep_interruptible(100); | |
852 | } while (cardp->bootcmdresp == 0 && j < 10); | |
853 | } while (cardp->bootcmdresp == 0 && i < 5); | |
854 | ||
855 | if (cardp->bootcmdresp == 0) { | |
856 | if (--reset_count >= 0) { | |
857 | libertas_do_reset(priv); | |
858 | goto restart; | |
859 | } | |
860 | return -1; | |
861 | } | |
876c9d3a MT |
862 | |
863 | i = 0; | |
864 | priv->adapter->fw_ready = 0; | |
865 | ||
866 | cardp->totalbytes = 0; | |
867 | cardp->fwlastblksent = 0; | |
868 | cardp->CRC_OK = 1; | |
869 | cardp->fwdnldover = 0; | |
870 | cardp->fwseqnum = -1; | |
871 | cardp->totalbytes = 0; | |
872 | cardp->fwfinalblk = 0; | |
873 | ||
874 | if_prog_firmware(priv); | |
875 | ||
876 | do { | |
9012b28a | 877 | lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); |
876c9d3a MT |
878 | i++; |
879 | msleep_interruptible(100); | |
880 | if (priv->adapter->surpriseremoved || i >= 20) | |
881 | break; | |
882 | } while (!cardp->fwdnldover); | |
883 | ||
884 | if (!cardp->fwdnldover) { | |
885 | lbs_pr_info("failed to load fw, resetting device!\n"); | |
886 | if (--reset_count >= 0) { | |
887 | libertas_do_reset(priv); | |
888 | goto restart; | |
889 | } | |
890 | ||
891 | lbs_pr_info("FW download failure, time = %d ms\n", i * 100); | |
9012b28a HS |
892 | ret = -1; |
893 | goto done; | |
876c9d3a MT |
894 | } |
895 | ||
896 | if_usb_submit_rx_urb(priv); | |
897 | ||
898 | /* Delay 200 ms to waiting for the FW ready */ | |
899 | msleep_interruptible(200); | |
900 | ||
901 | priv->adapter->fw_ready = 1; | |
902 | ||
9012b28a HS |
903 | done: |
904 | lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); | |
905 | return ret; | |
876c9d3a MT |
906 | } |
907 | ||
876c9d3a MT |
908 | #ifdef CONFIG_PM |
909 | static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) | |
910 | { | |
911 | struct usb_card_rec *cardp = usb_get_intfdata(intf); | |
912 | wlan_private *priv = cardp->priv; | |
913 | ||
9012b28a | 914 | lbs_deb_enter(LBS_DEB_USB); |
876c9d3a MT |
915 | |
916 | if (priv->adapter->psstate != PS_STATE_FULL_POWER) | |
917 | return -1; | |
918 | ||
919 | netif_device_detach(cardp->eth_dev); | |
51d84f50 | 920 | netif_device_detach(priv->mesh_dev); |
876c9d3a MT |
921 | |
922 | /* Unlink tx & rx urb */ | |
923 | usb_kill_urb(cardp->tx_urb); | |
924 | usb_kill_urb(cardp->rx_urb); | |
925 | ||
926 | cardp->rx_urb_recall = 1; | |
927 | ||
9012b28a | 928 | lbs_deb_leave(LBS_DEB_USB); |
876c9d3a MT |
929 | return 0; |
930 | } | |
931 | ||
932 | static int if_usb_resume(struct usb_interface *intf) | |
933 | { | |
934 | struct usb_card_rec *cardp = usb_get_intfdata(intf); | |
51d84f50 | 935 | wlan_private *priv = cardp->priv; |
876c9d3a | 936 | |
9012b28a | 937 | lbs_deb_enter(LBS_DEB_USB); |
876c9d3a MT |
938 | |
939 | cardp->rx_urb_recall = 0; | |
940 | ||
941 | if_usb_submit_rx_urb(cardp->priv); | |
942 | ||
943 | netif_device_attach(cardp->eth_dev); | |
51d84f50 | 944 | netif_device_attach(priv->mesh_dev); |
876c9d3a | 945 | |
9012b28a | 946 | lbs_deb_leave(LBS_DEB_USB); |
876c9d3a MT |
947 | return 0; |
948 | } | |
949 | #else | |
950 | #define if_usb_suspend NULL | |
951 | #define if_usb_resume NULL | |
952 | #endif | |
953 | ||
954 | static struct usb_driver if_usb_driver = { | |
955 | /* driver name */ | |
956 | .name = usbdriver_name, | |
957 | /* probe function name */ | |
958 | .probe = if_usb_probe, | |
959 | /* disconnect function name */ | |
960 | .disconnect = if_usb_disconnect, | |
961 | /* device signature table */ | |
962 | .id_table = if_usb_table, | |
963 | .suspend = if_usb_suspend, | |
964 | .resume = if_usb_resume, | |
965 | }; | |
966 | ||
967 | /** | |
968 | * @brief This function registers driver. | |
969 | * @param add pointer to add_card callback function | |
970 | * @param remove pointer to remove card callback function | |
971 | * @param arg pointer to call back function parameter | |
972 | * @return dummy success variable | |
973 | */ | |
208fdd2f | 974 | int if_usb_register(void) |
876c9d3a MT |
975 | { |
976 | /* | |
977 | * API registers the Marvell USB driver | |
978 | * to the USB system | |
979 | */ | |
980 | usb_register(&if_usb_driver); | |
981 | ||
982 | /* Return success to wlan layer */ | |
983 | return 0; | |
984 | } | |
985 | ||
986 | /** | |
987 | * @brief This function removes usb driver. | |
988 | * @return N/A | |
989 | */ | |
208fdd2f | 990 | void if_usb_unregister(void) |
876c9d3a | 991 | { |
3874d0fe HS |
992 | int i; |
993 | ||
994 | for (i = 0; i<libertas_found; i++) { | |
995 | wlan_private *priv = libertas_devs[i]->priv; | |
996 | reset_device(priv); | |
997 | } | |
998 | ||
876c9d3a MT |
999 | /* API unregisters the driver from USB subsystem */ |
1000 | usb_deregister(&if_usb_driver); | |
876c9d3a | 1001 | } |