diff options
author | Dan Williams <dcbw@redhat.com> | 2007-08-20 11:43:25 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:50:34 -0400 |
commit | 954ee164f4f4598afc172c0ec3865d0352e55a0b (patch) | |
tree | 51aae73210d22c0a91282a52b5198cfa1ad068b4 /drivers/net/wireless/libertas/if_usb.c | |
parent | b1b1907dceadddc7d7317f8ae85a5efec44125d8 (diff) |
[PATCH] libertas: reorganize and simplify init sequence
This patch moves all firmware load responsibility into the interface-specific
code and gets rid of the firmware pointer in the generic card structure. It
also removes 3 fairly unecessary callbacks: hw_register_dev, hw_unregister_dev,
and hw_prog_firmware. It also makes the init sequence from interface
probe functions more logical, as there are paired add/remove and start/stop
calls into generic libertas code.
Because the USB driver code uses the same TX URB callback for both firmware
upload (where the generic libertas structure isn't initialized yet) and for
normal operation (where it is), some bits of USB code have to deal with
'priv' being NULL. All USB firmware upload bits have been changed to not
require 'priv' at all, but simply the USB card structure.
Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/if_usb.c')
-rw-r--r-- | drivers/net/wireless/libertas/if_usb.c | 365 |
1 files changed, 162 insertions, 203 deletions
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 364eae374b93..105a00a7025d 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c | |||
@@ -45,14 +45,14 @@ MODULE_DEVICE_TABLE(usb, if_usb_table); | |||
45 | 45 | ||
46 | static void if_usb_receive(struct urb *urb); | 46 | static void if_usb_receive(struct urb *urb); |
47 | static void if_usb_receive_fwload(struct urb *urb); | 47 | static void if_usb_receive_fwload(struct urb *urb); |
48 | static int if_usb_register_dev(wlan_private * priv); | 48 | static int if_usb_prog_firmware(struct usb_card_rec *cardp); |
49 | static int if_usb_unregister_dev(wlan_private *); | ||
50 | static int if_usb_prog_firmware(wlan_private *); | ||
51 | static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); | 49 | static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); |
52 | static int if_usb_get_int_status(wlan_private * priv, u8 *); | 50 | static int if_usb_get_int_status(wlan_private * priv, u8 *); |
53 | static int if_usb_read_event_cause(wlan_private *); | 51 | static int if_usb_read_event_cause(wlan_private *); |
54 | static int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); | 52 | static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb); |
55 | static void if_usb_free(struct usb_card_rec *cardp); | 53 | static void if_usb_free(struct usb_card_rec *cardp); |
54 | static int if_usb_submit_rx_urb(struct usb_card_rec *cardp); | ||
55 | static int if_usb_reset_device(struct usb_card_rec *cardp); | ||
56 | 56 | ||
57 | /** | 57 | /** |
58 | * @brief call back function to handle the status of the URB | 58 | * @brief call back function to handle the status of the URB |
@@ -61,29 +61,40 @@ static void if_usb_free(struct usb_card_rec *cardp); | |||
61 | */ | 61 | */ |
62 | static void if_usb_write_bulk_callback(struct urb *urb) | 62 | static void if_usb_write_bulk_callback(struct urb *urb) |
63 | { | 63 | { |
64 | wlan_private *priv = (wlan_private *) (urb->context); | 64 | struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context; |
65 | wlan_adapter *adapter = priv->adapter; | ||
66 | struct net_device *dev = priv->dev; | ||
67 | 65 | ||
68 | /* handle the transmission complete validations */ | 66 | /* handle the transmission complete validations */ |
69 | 67 | ||
70 | if (urb->status != 0) { | 68 | if (urb->status == 0) { |
71 | /* print the failure status number for debug */ | 69 | wlan_private *priv = cardp->priv; |
72 | lbs_pr_info("URB in failure status: %d\n", urb->status); | 70 | |
73 | } else { | ||
74 | /* | 71 | /* |
75 | lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n"); | 72 | lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n"); |
76 | lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n", | 73 | lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n", |
77 | urb->actual_length); | 74 | urb->actual_length); |
78 | */ | 75 | */ |
79 | priv->dnld_sent = DNLD_RES_RECEIVED; | 76 | |
80 | /* Wake main thread if commands are pending */ | 77 | /* Used for both firmware TX and regular TX. priv isn't |
81 | if (!adapter->cur_cmd) | 78 | * valid at firmware load time. |
82 | wake_up_interruptible(&priv->waitq); | 79 | */ |
83 | if ((adapter->connect_status == LIBERTAS_CONNECTED)) { | 80 | if (priv) { |
84 | netif_wake_queue(dev); | 81 | wlan_adapter *adapter = priv->adapter; |
85 | netif_wake_queue(priv->mesh_dev); | 82 | struct net_device *dev = priv->dev; |
83 | |||
84 | priv->dnld_sent = DNLD_RES_RECEIVED; | ||
85 | |||
86 | /* Wake main thread if commands are pending */ | ||
87 | if (!adapter->cur_cmd) | ||
88 | wake_up_interruptible(&priv->waitq); | ||
89 | |||
90 | if ((adapter->connect_status == LIBERTAS_CONNECTED)) { | ||
91 | netif_wake_queue(dev); | ||
92 | netif_wake_queue(priv->mesh_dev); | ||
93 | } | ||
86 | } | 94 | } |
95 | } else { | ||
96 | /* print the failure status number for debug */ | ||
97 | lbs_pr_info("URB in failure status: %d\n", urb->status); | ||
87 | } | 98 | } |
88 | 99 | ||
89 | return; | 100 | return; |
@@ -205,24 +216,35 @@ static int if_usb_probe(struct usb_interface *intf, | |||
205 | } | 216 | } |
206 | } | 217 | } |
207 | 218 | ||
219 | /* Upload firmware */ | ||
220 | cardp->rinfo.cardp = cardp; | ||
221 | if (if_usb_prog_firmware(cardp)) { | ||
222 | lbs_deb_usbd(&udev->dev, "FW upload failed"); | ||
223 | goto err_prog_firmware; | ||
224 | } | ||
225 | |||
208 | if (!(priv = libertas_add_card(cardp, &udev->dev))) | 226 | if (!(priv = libertas_add_card(cardp, &udev->dev))) |
209 | goto dealloc; | 227 | goto err_prog_firmware; |
210 | 228 | ||
211 | udev->dev.driver_data = priv; | 229 | cardp->priv = priv; |
212 | 230 | ||
213 | if (libertas_add_mesh(priv, &udev->dev)) | 231 | if (libertas_add_mesh(priv, &udev->dev)) |
214 | goto err_add_mesh; | 232 | goto err_add_mesh; |
215 | 233 | ||
216 | priv->hw_register_dev = if_usb_register_dev; | 234 | cardp->eth_dev = priv->dev; |
217 | priv->hw_unregister_dev = if_usb_unregister_dev; | 235 | |
218 | priv->hw_prog_firmware = if_usb_prog_firmware; | ||
219 | priv->hw_host_to_card = if_usb_host_to_card; | 236 | priv->hw_host_to_card = if_usb_host_to_card; |
220 | priv->hw_get_int_status = if_usb_get_int_status; | 237 | priv->hw_get_int_status = if_usb_get_int_status; |
221 | priv->hw_read_event_cause = if_usb_read_event_cause; | 238 | priv->hw_read_event_cause = if_usb_read_event_cause; |
222 | priv->boot2_version = udev->descriptor.bcdDevice; | 239 | priv->boot2_version = udev->descriptor.bcdDevice; |
223 | 240 | ||
224 | if (libertas_activate_card(priv)) | 241 | /* Delay 200 ms to waiting for the FW ready */ |
225 | goto err_activate_card; | 242 | if_usb_submit_rx_urb(cardp); |
243 | msleep_interruptible(200); | ||
244 | priv->adapter->fw_ready = 1; | ||
245 | |||
246 | if (libertas_start_card(priv)) | ||
247 | goto err_start_card; | ||
226 | 248 | ||
227 | list_add_tail(&cardp->list, &usb_devices); | 249 | list_add_tail(&cardp->list, &usb_devices); |
228 | 250 | ||
@@ -231,11 +253,12 @@ static int if_usb_probe(struct usb_interface *intf, | |||
231 | 253 | ||
232 | return 0; | 254 | return 0; |
233 | 255 | ||
234 | err_activate_card: | 256 | err_start_card: |
235 | libertas_remove_mesh(priv); | 257 | libertas_remove_mesh(priv); |
236 | err_add_mesh: | 258 | err_add_mesh: |
237 | free_netdev(priv->dev); | 259 | libertas_remove_card(priv); |
238 | kfree(priv->adapter); | 260 | err_prog_firmware: |
261 | if_usb_reset_device(cardp); | ||
239 | dealloc: | 262 | dealloc: |
240 | if_usb_free(cardp); | 263 | if_usb_free(cardp); |
241 | 264 | ||
@@ -252,21 +275,22 @@ static void if_usb_disconnect(struct usb_interface *intf) | |||
252 | { | 275 | { |
253 | struct usb_card_rec *cardp = usb_get_intfdata(intf); | 276 | struct usb_card_rec *cardp = usb_get_intfdata(intf); |
254 | wlan_private *priv = (wlan_private *) cardp->priv; | 277 | wlan_private *priv = (wlan_private *) cardp->priv; |
255 | wlan_adapter *adapter = NULL; | ||
256 | 278 | ||
257 | adapter = priv->adapter; | 279 | lbs_deb_enter(LBS_DEB_MAIN); |
258 | 280 | ||
259 | /* | 281 | /* Update Surprise removed to TRUE */ |
260 | * Update Surprise removed to TRUE | 282 | cardp->surprise_removed = 1; |
261 | */ | ||
262 | adapter->surpriseremoved = 1; | ||
263 | 283 | ||
264 | list_del(&cardp->list); | 284 | list_del(&cardp->list); |
265 | 285 | ||
266 | /* card is removed and we can call wlan_remove_card */ | 286 | if (priv) { |
267 | lbs_deb_usbd(&cardp->udev->dev, "call remove card\n"); | 287 | wlan_adapter *adapter = priv->adapter; |
268 | libertas_remove_mesh(priv); | 288 | |
269 | libertas_remove_card(priv); | 289 | adapter->surpriseremoved = 1; |
290 | libertas_stop_card(priv); | ||
291 | libertas_remove_mesh(priv); | ||
292 | libertas_remove_card(priv); | ||
293 | } | ||
270 | 294 | ||
271 | /* Unlink and free urb */ | 295 | /* Unlink and free urb */ |
272 | if_usb_free(cardp); | 296 | if_usb_free(cardp); |
@@ -274,7 +298,7 @@ static void if_usb_disconnect(struct usb_interface *intf) | |||
274 | usb_set_intfdata(intf, NULL); | 298 | usb_set_intfdata(intf, NULL); |
275 | usb_put_dev(interface_to_usbdev(intf)); | 299 | usb_put_dev(interface_to_usbdev(intf)); |
276 | 300 | ||
277 | return; | 301 | lbs_deb_leave(LBS_DEB_MAIN); |
278 | } | 302 | } |
279 | 303 | ||
280 | /** | 304 | /** |
@@ -282,12 +306,11 @@ static void if_usb_disconnect(struct usb_interface *intf) | |||
282 | * @param priv pointer to wlan_private | 306 | * @param priv pointer to wlan_private |
283 | * @return 0 | 307 | * @return 0 |
284 | */ | 308 | */ |
285 | static int if_prog_firmware(wlan_private * priv) | 309 | static int if_prog_firmware(struct usb_card_rec *cardp) |
286 | { | 310 | { |
287 | struct usb_card_rec *cardp = priv->card; | ||
288 | struct FWData *fwdata; | 311 | struct FWData *fwdata; |
289 | struct fwheader *fwheader; | 312 | struct fwheader *fwheader; |
290 | u8 *firmware = priv->firmware->data; | 313 | u8 *firmware = cardp->fw->data; |
291 | 314 | ||
292 | fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); | 315 | fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); |
293 | 316 | ||
@@ -335,7 +358,7 @@ static int if_prog_firmware(wlan_private * priv) | |||
335 | cardp->totalbytes); | 358 | cardp->totalbytes); |
336 | */ | 359 | */ |
337 | memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); | 360 | memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); |
338 | usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); | 361 | usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); |
339 | 362 | ||
340 | } else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) { | 363 | } else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) { |
341 | /* | 364 | /* |
@@ -345,7 +368,7 @@ static int if_prog_firmware(wlan_private * priv) | |||
345 | "Donwloading FW JUMP BLOCK\n"); | 368 | "Donwloading FW JUMP BLOCK\n"); |
346 | */ | 369 | */ |
347 | memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); | 370 | memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); |
348 | usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); | 371 | usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); |
349 | cardp->fwfinalblk = 1; | 372 | cardp->fwfinalblk = 1; |
350 | } | 373 | } |
351 | 374 | ||
@@ -360,10 +383,10 @@ static int if_prog_firmware(wlan_private * priv) | |||
360 | return 0; | 383 | return 0; |
361 | } | 384 | } |
362 | 385 | ||
363 | static int if_usb_reset_device(wlan_private *priv) | 386 | static int if_usb_reset_device(struct usb_card_rec *cardp) |
364 | { | 387 | { |
365 | int ret; | 388 | int ret; |
366 | struct usb_card_rec *cardp = priv->card; | 389 | wlan_private * priv = cardp->priv; |
367 | 390 | ||
368 | lbs_deb_enter(LBS_DEB_USB); | 391 | lbs_deb_enter(LBS_DEB_USB); |
369 | 392 | ||
@@ -371,7 +394,7 @@ static int if_usb_reset_device(wlan_private *priv) | |||
371 | * command to the firmware. | 394 | * command to the firmware. |
372 | */ | 395 | */ |
373 | ret = usb_reset_device(cardp->udev); | 396 | ret = usb_reset_device(cardp->udev); |
374 | if (!ret) { | 397 | if (!ret && priv) { |
375 | msleep(10); | 398 | msleep(10); |
376 | ret = libertas_reset_device(priv); | 399 | ret = libertas_reset_device(priv); |
377 | msleep(10); | 400 | msleep(10); |
@@ -389,14 +412,12 @@ static int if_usb_reset_device(wlan_private *priv) | |||
389 | * @param nb data length | 412 | * @param nb data length |
390 | * @return 0 or -1 | 413 | * @return 0 or -1 |
391 | */ | 414 | */ |
392 | static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) | 415 | static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb) |
393 | { | 416 | { |
394 | /* pointer to card structure */ | ||
395 | struct usb_card_rec *cardp = priv->card; | ||
396 | int ret = -1; | 417 | int ret = -1; |
397 | 418 | ||
398 | /* check if device is removed */ | 419 | /* check if device is removed */ |
399 | if (priv->adapter->surpriseremoved) { | 420 | if (cardp->surprise_removed) { |
400 | lbs_deb_usbd(&cardp->udev->dev, "Device removed\n"); | 421 | lbs_deb_usbd(&cardp->udev->dev, "Device removed\n"); |
401 | goto tx_ret; | 422 | goto tx_ret; |
402 | } | 423 | } |
@@ -404,7 +425,7 @@ static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) | |||
404 | usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, | 425 | usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, |
405 | usb_sndbulkpipe(cardp->udev, | 426 | usb_sndbulkpipe(cardp->udev, |
406 | cardp->bulk_out_endpointAddr), | 427 | cardp->bulk_out_endpointAddr), |
407 | payload, nb, if_usb_write_bulk_callback, priv); | 428 | payload, nb, if_usb_write_bulk_callback, cardp); |
408 | 429 | ||
409 | cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; | 430 | cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; |
410 | 431 | ||
@@ -421,11 +442,9 @@ tx_ret: | |||
421 | return ret; | 442 | return ret; |
422 | } | 443 | } |
423 | 444 | ||
424 | static int __if_usb_submit_rx_urb(wlan_private * priv, | 445 | static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp, |
425 | void (*callbackfn) | 446 | void (*callbackfn)(struct urb *urb)) |
426 | (struct urb *urb)) | ||
427 | { | 447 | { |
428 | struct usb_card_rec *cardp = priv->card; | ||
429 | struct sk_buff *skb; | 448 | struct sk_buff *skb; |
430 | struct read_cb_info *rinfo = &cardp->rinfo; | 449 | struct read_cb_info *rinfo = &cardp->rinfo; |
431 | int ret = -1; | 450 | int ret = -1; |
@@ -461,22 +480,21 @@ rx_ret: | |||
461 | return ret; | 480 | return ret; |
462 | } | 481 | } |
463 | 482 | ||
464 | static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv) | 483 | static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp) |
465 | { | 484 | { |
466 | return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload); | 485 | return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload); |
467 | } | 486 | } |
468 | 487 | ||
469 | static inline int if_usb_submit_rx_urb(wlan_private * priv) | 488 | static int if_usb_submit_rx_urb(struct usb_card_rec *cardp) |
470 | { | 489 | { |
471 | return __if_usb_submit_rx_urb(priv, &if_usb_receive); | 490 | return __if_usb_submit_rx_urb(cardp, &if_usb_receive); |
472 | } | 491 | } |
473 | 492 | ||
474 | static void if_usb_receive_fwload(struct urb *urb) | 493 | static void if_usb_receive_fwload(struct urb *urb) |
475 | { | 494 | { |
476 | struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; | 495 | struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; |
477 | wlan_private *priv = rinfo->priv; | ||
478 | struct sk_buff *skb = rinfo->skb; | 496 | struct sk_buff *skb = rinfo->skb; |
479 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; | 497 | struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp; |
480 | struct fwsyncheader *syncfwheader; | 498 | struct fwsyncheader *syncfwheader; |
481 | struct bootcmdrespStr bootcmdresp; | 499 | struct bootcmdrespStr bootcmdresp; |
482 | 500 | ||
@@ -492,7 +510,7 @@ static void if_usb_receive_fwload(struct urb *urb) | |||
492 | sizeof(bootcmdresp)); | 510 | sizeof(bootcmdresp)); |
493 | if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { | 511 | if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { |
494 | kfree_skb(skb); | 512 | kfree_skb(skb); |
495 | if_usb_submit_rx_urb_fwload(priv); | 513 | if_usb_submit_rx_urb_fwload(cardp); |
496 | cardp->bootcmdresp = 1; | 514 | cardp->bootcmdresp = 1; |
497 | lbs_deb_usbd(&cardp->udev->dev, | 515 | lbs_deb_usbd(&cardp->udev->dev, |
498 | "Received valid boot command response\n"); | 516 | "Received valid boot command response\n"); |
@@ -516,7 +534,7 @@ static void if_usb_receive_fwload(struct urb *urb) | |||
516 | "Received valid boot command response\n"); | 534 | "Received valid boot command response\n"); |
517 | } | 535 | } |
518 | kfree_skb(skb); | 536 | kfree_skb(skb); |
519 | if_usb_submit_rx_urb_fwload(priv); | 537 | if_usb_submit_rx_urb_fwload(cardp); |
520 | return; | 538 | return; |
521 | } | 539 | } |
522 | 540 | ||
@@ -552,9 +570,9 @@ static void if_usb_receive_fwload(struct urb *urb) | |||
552 | goto exit; | 570 | goto exit; |
553 | } | 571 | } |
554 | 572 | ||
555 | if_prog_firmware(priv); | 573 | if_prog_firmware(cardp); |
556 | 574 | ||
557 | if_usb_submit_rx_urb_fwload(priv); | 575 | if_usb_submit_rx_urb_fwload(cardp); |
558 | exit: | 576 | exit: |
559 | kfree(syncfwheader); | 577 | kfree(syncfwheader); |
560 | 578 | ||
@@ -633,9 +651,9 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff, | |||
633 | static void if_usb_receive(struct urb *urb) | 651 | static void if_usb_receive(struct urb *urb) |
634 | { | 652 | { |
635 | struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; | 653 | struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; |
636 | wlan_private *priv = rinfo->priv; | ||
637 | struct sk_buff *skb = rinfo->skb; | 654 | struct sk_buff *skb = rinfo->skb; |
638 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; | 655 | struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp; |
656 | wlan_private * priv = cardp->priv; | ||
639 | 657 | ||
640 | int recvlength = urb->actual_length; | 658 | int recvlength = urb->actual_length; |
641 | u8 *recvbuff = NULL; | 659 | u8 *recvbuff = NULL; |
@@ -696,7 +714,7 @@ static void if_usb_receive(struct urb *urb) | |||
696 | } | 714 | } |
697 | 715 | ||
698 | setup_for_next: | 716 | setup_for_next: |
699 | if_usb_submit_rx_urb(priv); | 717 | if_usb_submit_rx_urb(cardp); |
700 | rx_exit: | 718 | rx_exit: |
701 | lbs_deb_leave(LBS_DEB_USB); | 719 | lbs_deb_leave(LBS_DEB_USB); |
702 | } | 720 | } |
@@ -731,7 +749,7 @@ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 n | |||
731 | 749 | ||
732 | memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); | 750 | memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); |
733 | 751 | ||
734 | return usb_tx_block(priv, cardp->bulk_out_buffer, | 752 | return usb_tx_block(cardp, cardp->bulk_out_buffer, |
735 | nb + MESSAGE_HEADER_LEN); | 753 | nb + MESSAGE_HEADER_LEN); |
736 | } | 754 | } |
737 | 755 | ||
@@ -751,46 +769,10 @@ static int if_usb_get_int_status(wlan_private * priv, u8 * ireg) | |||
751 | static int if_usb_read_event_cause(wlan_private * priv) | 769 | static int if_usb_read_event_cause(wlan_private * priv) |
752 | { | 770 | { |
753 | struct usb_card_rec *cardp = priv->card; | 771 | struct usb_card_rec *cardp = priv->card; |
772 | |||
754 | priv->adapter->eventcause = cardp->usb_event_cause; | 773 | priv->adapter->eventcause = cardp->usb_event_cause; |
755 | /* Re-submit rx urb here to avoid event lost issue */ | 774 | /* Re-submit rx urb here to avoid event lost issue */ |
756 | if_usb_submit_rx_urb(priv); | 775 | if_usb_submit_rx_urb(cardp); |
757 | return 0; | ||
758 | } | ||
759 | |||
760 | static int if_usb_unregister_dev(wlan_private * priv) | ||
761 | { | ||
762 | int ret = 0; | ||
763 | |||
764 | /* Need to send a Reset command to device before USB resources freed | ||
765 | * and wlan_remove_card() called, then device can handle FW download | ||
766 | * again. | ||
767 | */ | ||
768 | if (priv) | ||
769 | libertas_reset_device(priv); | ||
770 | |||
771 | return ret; | ||
772 | } | ||
773 | |||
774 | |||
775 | /** | ||
776 | * @brief This function register usb device and initialize parameter | ||
777 | * @param priv pointer to wlan_private | ||
778 | * @return 0 or -1 | ||
779 | */ | ||
780 | static int if_usb_register_dev(wlan_private * priv) | ||
781 | { | ||
782 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; | ||
783 | |||
784 | lbs_deb_enter(LBS_DEB_USB); | ||
785 | |||
786 | cardp->priv = priv; | ||
787 | cardp->eth_dev = priv->dev; | ||
788 | priv->hotplug_device = &(cardp->udev->dev); | ||
789 | |||
790 | lbs_deb_usbd(&cardp->udev->dev, "udev pointer is at %p\n", | ||
791 | cardp->udev); | ||
792 | |||
793 | lbs_deb_leave(LBS_DEB_USB); | ||
794 | return 0; | 776 | return 0; |
795 | } | 777 | } |
796 | 778 | ||
@@ -800,10 +782,9 @@ static int if_usb_register_dev(wlan_private * priv) | |||
800 | * 2:Boot from FW in EEPROM | 782 | * 2:Boot from FW in EEPROM |
801 | * @return 0 | 783 | * @return 0 |
802 | */ | 784 | */ |
803 | static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) | 785 | static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue) |
804 | { | 786 | { |
805 | struct usb_card_rec *cardp = priv->card; | 787 | struct bootcmdstr sbootcmd; |
806 | struct bootcmdstr sbootcmd; | ||
807 | int i; | 788 | int i; |
808 | 789 | ||
809 | /* Prepare command */ | 790 | /* Prepare command */ |
@@ -814,28 +795,83 @@ static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) | |||
814 | memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); | 795 | memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); |
815 | 796 | ||
816 | /* Issue command */ | 797 | /* Issue command */ |
817 | usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); | 798 | usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); |
818 | 799 | ||
819 | return 0; | 800 | return 0; |
820 | } | 801 | } |
821 | 802 | ||
822 | 803 | ||
823 | static int if_usb_do_prog_firmware(wlan_private * priv) | 804 | /** |
805 | * @brief This function checks the validity of Boot2/FW image. | ||
806 | * | ||
807 | * @param data pointer to image | ||
808 | * len image length | ||
809 | * @return 0 or -1 | ||
810 | */ | ||
811 | static int check_fwfile_format(u8 *data, u32 totlen) | ||
812 | { | ||
813 | u32 bincmd, exit; | ||
814 | u32 blksize, offset, len; | ||
815 | int ret; | ||
816 | |||
817 | ret = 1; | ||
818 | exit = len = 0; | ||
819 | |||
820 | do { | ||
821 | struct fwheader *fwh = (void *)data; | ||
822 | |||
823 | bincmd = le32_to_cpu(fwh->dnldcmd); | ||
824 | blksize = le32_to_cpu(fwh->datalength); | ||
825 | switch (bincmd) { | ||
826 | case FW_HAS_DATA_TO_RECV: | ||
827 | offset = sizeof(struct fwheader) + blksize; | ||
828 | data += offset; | ||
829 | len += offset; | ||
830 | if (len >= totlen) | ||
831 | exit = 1; | ||
832 | break; | ||
833 | case FW_HAS_LAST_BLOCK: | ||
834 | exit = 1; | ||
835 | ret = 0; | ||
836 | break; | ||
837 | default: | ||
838 | exit = 1; | ||
839 | break; | ||
840 | } | ||
841 | } while (!exit); | ||
842 | |||
843 | if (ret) | ||
844 | lbs_pr_err("firmware file format check FAIL\n"); | ||
845 | else | ||
846 | lbs_deb_fw("firmware file format check PASS\n"); | ||
847 | |||
848 | return ret; | ||
849 | } | ||
850 | |||
851 | |||
852 | static int if_usb_prog_firmware(struct usb_card_rec *cardp) | ||
824 | { | 853 | { |
825 | struct usb_card_rec *cardp = priv->card; | ||
826 | int i = 0; | 854 | int i = 0; |
827 | static int reset_count = 10; | 855 | static int reset_count = 10; |
828 | int ret = 0; | 856 | int ret = 0; |
829 | 857 | ||
830 | lbs_deb_enter(LBS_DEB_USB); | 858 | lbs_deb_enter(LBS_DEB_USB); |
831 | 859 | ||
832 | cardp->rinfo.priv = priv; | 860 | if ((ret = request_firmware(&cardp->fw, libertas_fw_name, |
861 | &cardp->udev->dev)) < 0) { | ||
862 | lbs_pr_err("request_firmware() failed with %#x\n", ret); | ||
863 | lbs_pr_err("firmware %s not found\n", libertas_fw_name); | ||
864 | goto done; | ||
865 | } | ||
866 | |||
867 | if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) | ||
868 | goto release_fw; | ||
833 | 869 | ||
834 | restart: | 870 | restart: |
835 | if (if_usb_submit_rx_urb_fwload(priv) < 0) { | 871 | if (if_usb_submit_rx_urb_fwload(cardp) < 0) { |
836 | lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); | 872 | lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); |
837 | ret = -1; | 873 | ret = -1; |
838 | goto done; | 874 | goto release_fw; |
839 | } | 875 | } |
840 | 876 | ||
841 | cardp->bootcmdresp = 0; | 877 | cardp->bootcmdresp = 0; |
@@ -843,7 +879,7 @@ restart: | |||
843 | int j = 0; | 879 | int j = 0; |
844 | i++; | 880 | i++; |
845 | /* Issue Boot command = 1, Boot from Download-FW */ | 881 | /* Issue Boot command = 1, Boot from Download-FW */ |
846 | if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB); | 882 | if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); |
847 | /* wait for command response */ | 883 | /* wait for command response */ |
848 | do { | 884 | do { |
849 | j++; | 885 | j++; |
@@ -853,14 +889,13 @@ restart: | |||
853 | 889 | ||
854 | if (cardp->bootcmdresp == 0) { | 890 | if (cardp->bootcmdresp == 0) { |
855 | if (--reset_count >= 0) { | 891 | if (--reset_count >= 0) { |
856 | if_usb_reset_device(priv); | 892 | if_usb_reset_device(cardp); |
857 | goto restart; | 893 | goto restart; |
858 | } | 894 | } |
859 | return -1; | 895 | return -1; |
860 | } | 896 | } |
861 | 897 | ||
862 | i = 0; | 898 | i = 0; |
863 | priv->adapter->fw_ready = 0; | ||
864 | 899 | ||
865 | cardp->totalbytes = 0; | 900 | cardp->totalbytes = 0; |
866 | cardp->fwlastblksent = 0; | 901 | cardp->fwlastblksent = 0; |
@@ -870,113 +905,37 @@ restart: | |||
870 | cardp->totalbytes = 0; | 905 | cardp->totalbytes = 0; |
871 | cardp->fwfinalblk = 0; | 906 | cardp->fwfinalblk = 0; |
872 | 907 | ||
873 | if_prog_firmware(priv); | 908 | if_prog_firmware(cardp); |
874 | 909 | ||
875 | do { | 910 | do { |
876 | lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); | 911 | lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); |
877 | i++; | 912 | i++; |
878 | msleep_interruptible(100); | 913 | msleep_interruptible(100); |
879 | if (priv->adapter->surpriseremoved || i >= 20) | 914 | if (cardp->surprise_removed || i >= 20) |
880 | break; | 915 | break; |
881 | } while (!cardp->fwdnldover); | 916 | } while (!cardp->fwdnldover); |
882 | 917 | ||
883 | if (!cardp->fwdnldover) { | 918 | if (!cardp->fwdnldover) { |
884 | lbs_pr_info("failed to load fw, resetting device!\n"); | 919 | lbs_pr_info("failed to load fw, resetting device!\n"); |
885 | if (--reset_count >= 0) { | 920 | if (--reset_count >= 0) { |
886 | if_usb_reset_device(priv); | 921 | if_usb_reset_device(cardp); |
887 | goto restart; | 922 | goto restart; |
888 | } | 923 | } |
889 | 924 | ||
890 | lbs_pr_info("FW download failure, time = %d ms\n", i * 100); | 925 | lbs_pr_info("FW download failure, time = %d ms\n", i * 100); |
891 | ret = -1; | 926 | ret = -1; |
892 | goto done; | 927 | goto release_fw; |
893 | } | 928 | } |
894 | 929 | ||
895 | if_usb_submit_rx_urb(priv); | 930 | release_fw: |
896 | 931 | release_firmware(cardp->fw); | |
897 | /* Delay 200 ms to waiting for the FW ready */ | 932 | cardp->fw = NULL; |
898 | msleep_interruptible(200); | ||
899 | |||
900 | priv->adapter->fw_ready = 1; | ||
901 | 933 | ||
902 | done: | 934 | done: |
903 | lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); | 935 | lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); |
904 | return ret; | 936 | return ret; |
905 | } | 937 | } |
906 | 938 | ||
907 | /** | ||
908 | * @brief This function checks the validity of Boot2/FW image. | ||
909 | * | ||
910 | * @param data pointer to image | ||
911 | * len image length | ||
912 | * @return 0 or -1 | ||
913 | */ | ||
914 | static int check_fwfile_format(u8 *data, u32 totlen) | ||
915 | { | ||
916 | u32 bincmd, exit; | ||
917 | u32 blksize, offset, len; | ||
918 | int ret; | ||
919 | |||
920 | ret = 1; | ||
921 | exit = len = 0; | ||
922 | |||
923 | do { | ||
924 | struct fwheader *fwh = (void *)data; | ||
925 | |||
926 | bincmd = le32_to_cpu(fwh->dnldcmd); | ||
927 | blksize = le32_to_cpu(fwh->datalength); | ||
928 | switch (bincmd) { | ||
929 | case FW_HAS_DATA_TO_RECV: | ||
930 | offset = sizeof(struct fwheader) + blksize; | ||
931 | data += offset; | ||
932 | len += offset; | ||
933 | if (len >= totlen) | ||
934 | exit = 1; | ||
935 | break; | ||
936 | case FW_HAS_LAST_BLOCK: | ||
937 | exit = 1; | ||
938 | ret = 0; | ||
939 | break; | ||
940 | default: | ||
941 | exit = 1; | ||
942 | break; | ||
943 | } | ||
944 | } while (!exit); | ||
945 | |||
946 | if (ret) | ||
947 | lbs_pr_err("firmware file format check FAIL\n"); | ||
948 | else | ||
949 | lbs_deb_fw("firmware file format check PASS\n"); | ||
950 | |||
951 | return ret; | ||
952 | } | ||
953 | |||
954 | |||
955 | static int if_usb_prog_firmware(wlan_private *priv) | ||
956 | { | ||
957 | int ret = -1; | ||
958 | |||
959 | lbs_deb_enter(LBS_DEB_FW); | ||
960 | |||
961 | if ((ret = request_firmware(&priv->firmware, libertas_fw_name, | ||
962 | priv->hotplug_device)) < 0) { | ||
963 | lbs_pr_err("request_firmware() failed with %#x\n", ret); | ||
964 | lbs_pr_err("firmware %s not found\n", libertas_fw_name); | ||
965 | goto done; | ||
966 | } | ||
967 | |||
968 | if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) { | ||
969 | release_firmware(priv->firmware); | ||
970 | goto done; | ||
971 | } | ||
972 | |||
973 | ret = if_usb_do_prog_firmware(priv); | ||
974 | |||
975 | release_firmware(priv->firmware); | ||
976 | done: | ||
977 | return ret; | ||
978 | } | ||
979 | |||
980 | 939 | ||
981 | #ifdef CONFIG_PM | 940 | #ifdef CONFIG_PM |
982 | static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) | 941 | static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) |