diff options
Diffstat (limited to 'firmware/usb.c')
-rw-r--r-- | firmware/usb.c | 158 |
1 files changed, 81 insertions, 77 deletions
diff --git a/firmware/usb.c b/firmware/usb.c index 6251677e45..436b840a13 100644 --- a/firmware/usb.c +++ b/firmware/usb.c | |||
@@ -63,7 +63,9 @@ bool do_screendump_instead_of_usb = false; | |||
63 | 63 | ||
64 | /* We assume that the USB cable is extracted */ | 64 | /* We assume that the USB cable is extracted */ |
65 | static int usb_state = USB_EXTRACTED; | 65 | static int usb_state = USB_EXTRACTED; |
66 | 66 | static bool usb_host_present = false; | |
67 | static int usb_num_acks_to_expect = 0; | ||
68 | static long usb_last_broadcast_tick = 0; | ||
67 | #if (CONFIG_STORAGE & STORAGE_MMC) && defined(USB_FULL_INIT) && !defined(HAVE_USBSTACK) | 69 | #if (CONFIG_STORAGE & STORAGE_MMC) && defined(USB_FULL_INIT) && !defined(HAVE_USBSTACK) |
68 | static int usb_mmc_countdown = 0; | 70 | static int usb_mmc_countdown = 0; |
69 | #endif | 71 | #endif |
@@ -109,21 +111,20 @@ static void try_reboot(void) | |||
109 | #endif /* USB_FIRWIRE_HANDLING || (HAVE_USBSTACK && !USE_ROCKBOX_USB) */ | 111 | #endif /* USB_FIRWIRE_HANDLING || (HAVE_USBSTACK && !USE_ROCKBOX_USB) */ |
110 | 112 | ||
111 | /* Screen dump */ | 113 | /* Screen dump */ |
114 | #ifdef HAVE_LCD_BITMAP | ||
112 | static inline bool usb_do_screendump(void) | 115 | static inline bool usb_do_screendump(void) |
113 | { | 116 | { |
114 | #ifdef HAVE_LCD_BITMAP | ||
115 | if(do_screendump_instead_of_usb) | 117 | if(do_screendump_instead_of_usb) |
116 | { | 118 | { |
117 | usb_state = USB_SCREENDUMP; | ||
118 | screen_dump(); | 119 | screen_dump(); |
119 | #ifdef HAVE_REMOTE_LCD | 120 | #ifdef HAVE_REMOTE_LCD |
120 | remote_screen_dump(); | 121 | remote_screen_dump(); |
121 | #endif /* HAVE_REMOTE_LCD */ | 122 | #endif /* HAVE_REMOTE_LCD */ |
122 | return true; | 123 | return true; |
123 | } | 124 | } |
124 | #endif /* HAVE_LCD_BITMAP */ | ||
125 | return false; | 125 | return false; |
126 | } | 126 | } |
127 | #endif /* HAVE_LCD_BITMAP */ | ||
127 | 128 | ||
128 | /* Power (charging-only) button */ | 129 | /* Power (charging-only) button */ |
129 | static inline bool usb_power_button(void) | 130 | static inline bool usb_power_button(void) |
@@ -356,13 +357,69 @@ static inline void usb_slave_mode(bool on) | |||
356 | } | 357 | } |
357 | #endif /* HAVE_USBSTACK */ | 358 | #endif /* HAVE_USBSTACK */ |
358 | 359 | ||
360 | static void usb_set_host_present(bool present) | ||
361 | { | ||
362 | if(usb_host_present == present) | ||
363 | return; | ||
364 | |||
365 | usb_host_present = present; | ||
366 | |||
367 | if(!usb_host_present) | ||
368 | { | ||
369 | usb_configure_drivers(USB_EXTRACTED); | ||
370 | return; | ||
371 | } | ||
372 | |||
373 | if(usb_power_button()) | ||
374 | { | ||
375 | /* Only charging is desired */ | ||
376 | usb_configure_drivers(USB_POWERED); | ||
377 | return; | ||
378 | } | ||
379 | |||
380 | if(!usb_configure_drivers(USB_INSERTED)) | ||
381 | return; /* Exclusive storage access not required */ | ||
382 | |||
383 | /* Tell all threads that they have to back off the storage. | ||
384 | We subtract one for our own thread. Expect an ACK for every | ||
385 | listener for each broadcast they received. If it has been too | ||
386 | long, the user might have entered a screen that didn't ACK | ||
387 | when inserting the cable, such as a debugging screen. In that | ||
388 | case, reset the count or else USB would be locked out until | ||
389 | rebooting because it most likely won't ever come. Simply | ||
390 | resetting to the most recent broadcast count is racy. */ | ||
391 | if(TIME_AFTER(current_tick, usb_last_broadcast_tick + HZ*5)) | ||
392 | { | ||
393 | usb_num_acks_to_expect = 0; | ||
394 | usb_last_broadcast_tick = current_tick; | ||
395 | } | ||
396 | |||
397 | usb_num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1; | ||
398 | DEBUGF("usb: waiting for %d acks...\n", num_acks_to_expect); | ||
399 | } | ||
400 | |||
401 | static bool usb_handle_connected_ack(void) | ||
402 | { | ||
403 | if(usb_num_acks_to_expect > 0 && --usb_num_acks_to_expect == 0) | ||
404 | { | ||
405 | DEBUGF("usb: all threads have acknowledged the connect.\n"); | ||
406 | if(usb_host_present) | ||
407 | { | ||
408 | usb_slave_mode(true); | ||
409 | return true; | ||
410 | } | ||
411 | } | ||
412 | else | ||
413 | { | ||
414 | DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); | ||
415 | } | ||
416 | |||
417 | return false; | ||
418 | } | ||
359 | 419 | ||
360 | /*--- General driver code ---*/ | 420 | /*--- General driver code ---*/ |
361 | static void NORETURN_ATTR usb_thread(void) | 421 | static void NORETURN_ATTR usb_thread(void) |
362 | { | 422 | { |
363 | int num_acks_to_expect = 0; | ||
364 | long last_broadcast_tick = current_tick; | ||
365 | bool host_detected = false; | ||
366 | struct queue_event ev; | 423 | struct queue_event ev; |
367 | 424 | ||
368 | while(1) | 425 | while(1) |
@@ -378,6 +435,10 @@ static void NORETURN_ATTR usb_thread(void) | |||
378 | if(usb_state <= USB_EXTRACTED) | 435 | if(usb_state <= USB_EXTRACTED) |
379 | break; | 436 | break; |
380 | 437 | ||
438 | #ifdef USB_DETECT_BY_REQUEST | ||
439 | usb_set_host_present(true); | ||
440 | #endif | ||
441 | |||
381 | usb_core_handle_transfer_completion( | 442 | usb_core_handle_transfer_completion( |
382 | (struct usb_transfer_completion_event_data*)ev.data); | 443 | (struct usb_transfer_completion_event_data*)ev.data); |
383 | break; | 444 | break; |
@@ -387,72 +448,26 @@ static void NORETURN_ATTR usb_thread(void) | |||
387 | if(usb_state != USB_EXTRACTED) | 448 | if(usb_state != USB_EXTRACTED) |
388 | break; | 449 | break; |
389 | 450 | ||
451 | #ifdef HAVE_LCD_BITMAP | ||
390 | if(usb_do_screendump()) | 452 | if(usb_do_screendump()) |
391 | break; | ||
392 | |||
393 | usb_state = USB_POWERED; | ||
394 | usb_stack_enable(true); | ||
395 | |||
396 | #ifdef USB_DETECT_BY_CORE | ||
397 | /* Wait for USB core to detect the host */ | ||
398 | break; | ||
399 | |||
400 | case USB_HOSTED: | ||
401 | if(usb_state != USB_POWERED) | ||
402 | break; | ||
403 | #endif /* USB_DETECT_BY_CORE */ | ||
404 | |||
405 | if(host_detected) | ||
406 | break; | ||
407 | |||
408 | host_detected = true; | ||
409 | |||
410 | if(usb_power_button()) | ||
411 | { | 453 | { |
412 | /* Only charging is desired */ | 454 | usb_state = USB_SCREENDUMP; |
413 | usb_configure_drivers(USB_POWERED); | ||
414 | break; | 455 | break; |
415 | } | 456 | } |
457 | #endif | ||
416 | 458 | ||
417 | if(!usb_configure_drivers(USB_INSERTED)) | 459 | usb_state = USB_POWERED; |
418 | break; /* Exclusive storage access not required */ | 460 | usb_stack_enable(true); |
419 | |||
420 | /* Tell all threads that they have to back off the storage. | ||
421 | We subtract one for our own thread. Expect an ACK for every | ||
422 | listener for each broadcast they received. If it has been too | ||
423 | long, the user might have entered a screen that didn't ACK | ||
424 | when inserting the cable, such as a debugging screen. In that | ||
425 | case, reset the count or else USB would be locked out until | ||
426 | rebooting because it most likely won't ever come. Simply | ||
427 | resetting to the most recent broadcast count is racy. */ | ||
428 | if(TIME_AFTER(current_tick, last_broadcast_tick + HZ*5)) | ||
429 | { | ||
430 | num_acks_to_expect = 0; | ||
431 | last_broadcast_tick = current_tick; | ||
432 | } | ||
433 | |||
434 | num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1; | ||
435 | DEBUGF("usb: waiting for %d acks...\n", num_acks_to_expect); | ||
436 | 461 | ||
437 | /* Leave the state as USB_POWERED until the expected number of | 462 | #ifndef USB_DETECT_BY_REQUEST |
438 | ACKS are received. */ | 463 | usb_set_host_present(true); |
464 | #endif | ||
439 | break; | 465 | break; |
440 | /* USB_INSERTED: or USB_HOSTED: */ | 466 | /* USB_INSERTED */ |
441 | 467 | ||
442 | case SYS_USB_CONNECTED_ACK: | 468 | case SYS_USB_CONNECTED_ACK: |
443 | if(num_acks_to_expect > 0 && --num_acks_to_expect == 0) | 469 | if(usb_handle_connected_ack()) |
444 | { | 470 | usb_state = USB_INSERTED; |
445 | DEBUGF("usb: all threads have acknowledged the connect.\n"); | ||
446 | if(host_detected) | ||
447 | { | ||
448 | usb_slave_mode(true); | ||
449 | usb_state = USB_INSERTED; | ||
450 | } | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); | ||
455 | } | ||
456 | break; | 471 | break; |
457 | /* SYS_USB_CONNECTED_ACK */ | 472 | /* SYS_USB_CONNECTED_ACK */ |
458 | 473 | ||
@@ -470,13 +485,7 @@ static void NORETURN_ATTR usb_thread(void) | |||
470 | 485 | ||
471 | usb_state = USB_EXTRACTED; | 486 | usb_state = USB_EXTRACTED; |
472 | 487 | ||
473 | if(host_detected) | 488 | usb_set_host_present(false); |
474 | { | ||
475 | /* Ok to broadcast disconnect now */ | ||
476 | usb_configure_drivers(USB_EXTRACTED); | ||
477 | host_detected = false; | ||
478 | } | ||
479 | |||
480 | break; | 489 | break; |
481 | /* USB_EXTRACTED: */ | 490 | /* USB_EXTRACTED: */ |
482 | 491 | ||
@@ -530,8 +539,7 @@ void usb_status_event(int current_status) | |||
530 | { | 539 | { |
531 | /* Caller isn't expected to filter for changes in status. | 540 | /* Caller isn't expected to filter for changes in status. |
532 | * current_status: | 541 | * current_status: |
533 | * all: USB_INSERTED, USB_EXTRACTED | 542 | * USB_INSERTED, USB_EXTRACTED |
534 | * USB_DETECT_BY_CORE: USB_HOSTED (from core) | ||
535 | */ | 543 | */ |
536 | if(usb_monitor_enabled) | 544 | if(usb_monitor_enabled) |
537 | { | 545 | { |
@@ -552,10 +560,6 @@ void usb_start_monitoring(void) | |||
552 | /* An event may have been missed because it was sent before monitoring | 560 | /* An event may have been missed because it was sent before monitoring |
553 | * was enabled due to the connector already having been inserted before | 561 | * was enabled due to the connector already having been inserted before |
554 | * before or during boot. */ | 562 | * before or during boot. */ |
555 | #ifdef USB_DETECT_BY_CORE | ||
556 | /* Filter the status - USB_HOSTED may happen later */ | ||
557 | status = (status == USB_INSERTED) ? : USB_EXTRACTED; | ||
558 | #endif | ||
559 | usb_status_event(status); | 563 | usb_status_event(status); |
560 | 564 | ||
561 | #ifdef USB_FIREWIRE_HANDLING | 565 | #ifdef USB_FIREWIRE_HANDLING |