summaryrefslogtreecommitdiffstats
path: root/firmware/usb.c
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2012-01-04 21:55:09 +0000
committerFrank Gevaerts <frank@gevaerts.be>2012-01-04 21:55:09 +0000
commit4fcffcbdf34fc7a619c0626f8478cf06cdf1a043 (patch)
treead3a951e3ec9566b315807af8ab4045529c8878c /firmware/usb.c
parentfd5524ff92b49d9fb14d3feaca4d26d86a05b2b2 (diff)
downloadrockbox-4fcffcbdf34fc7a619c0626f8478cf06cdf1a043.tar.gz
rockbox-4fcffcbdf34fc7a619c0626f8478cf06cdf1a043.tar.bz2
rockbox-4fcffcbdf34fc7a619c0626f8478cf06cdf1a043.zip
Reorganise USB initialisation to not depend on a specific enumeration sequence, by Bartosz Fabianowski, with minor tweaks by Michael Sevakis (FS#12497)
FreeBSD apparently sends a SET_ADDRESS first, which confused our code. This patch fixes that, and also simplifies the connection handling a bit. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31582 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/usb.c')
-rw-r--r--firmware/usb.c158
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;
/* We assume that the USB cable is extracted */
static int usb_state = USB_EXTRACTED;
-
+static bool usb_host_present = false;
+static int usb_num_acks_to_expect = 0;
+static long usb_last_broadcast_tick = 0;
#if (CONFIG_STORAGE & STORAGE_MMC) && defined(USB_FULL_INIT) && !defined(HAVE_USBSTACK)
static int usb_mmc_countdown = 0;
#endif
@@ -109,21 +111,20 @@ static void try_reboot(void)
#endif /* USB_FIRWIRE_HANDLING || (HAVE_USBSTACK && !USE_ROCKBOX_USB) */
/* Screen dump */
+#ifdef HAVE_LCD_BITMAP
static inline bool usb_do_screendump(void)
{
-#ifdef HAVE_LCD_BITMAP
if(do_screendump_instead_of_usb)
{
- usb_state = USB_SCREENDUMP;
screen_dump();
#ifdef HAVE_REMOTE_LCD
remote_screen_dump();
#endif /* HAVE_REMOTE_LCD */
return true;
}
-#endif /* HAVE_LCD_BITMAP */
return false;
}
+#endif /* HAVE_LCD_BITMAP */
/* Power (charging-only) button */
static inline bool usb_power_button(void)
@@ -356,13 +357,69 @@ static inline void usb_slave_mode(bool on)
}
#endif /* HAVE_USBSTACK */
+static void usb_set_host_present(bool present)
+{
+ if(usb_host_present == present)
+ return;
+
+ usb_host_present = present;
+
+ if(!usb_host_present)
+ {
+ usb_configure_drivers(USB_EXTRACTED);
+ return;
+ }
+
+ if(usb_power_button())
+ {
+ /* Only charging is desired */
+ usb_configure_drivers(USB_POWERED);
+ return;
+ }
+
+ if(!usb_configure_drivers(USB_INSERTED))
+ return; /* Exclusive storage access not required */
+
+ /* Tell all threads that they have to back off the storage.
+ We subtract one for our own thread. Expect an ACK for every
+ listener for each broadcast they received. If it has been too
+ long, the user might have entered a screen that didn't ACK
+ when inserting the cable, such as a debugging screen. In that
+ case, reset the count or else USB would be locked out until
+ rebooting because it most likely won't ever come. Simply
+ resetting to the most recent broadcast count is racy. */
+ if(TIME_AFTER(current_tick, usb_last_broadcast_tick + HZ*5))
+ {
+ usb_num_acks_to_expect = 0;
+ usb_last_broadcast_tick = current_tick;
+ }
+
+ usb_num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
+ DEBUGF("usb: waiting for %d acks...\n", num_acks_to_expect);
+}
+
+static bool usb_handle_connected_ack(void)
+{
+ if(usb_num_acks_to_expect > 0 && --usb_num_acks_to_expect == 0)
+ {
+ DEBUGF("usb: all threads have acknowledged the connect.\n");
+ if(usb_host_present)
+ {
+ usb_slave_mode(true);
+ return true;
+ }
+ }
+ else
+ {
+ DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect);
+ }
+
+ return false;
+}
/*--- General driver code ---*/
static void NORETURN_ATTR usb_thread(void)
{
- int num_acks_to_expect = 0;
- long last_broadcast_tick = current_tick;
- bool host_detected = false;
struct queue_event ev;
while(1)
@@ -378,6 +435,10 @@ static void NORETURN_ATTR usb_thread(void)
if(usb_state <= USB_EXTRACTED)
break;
+#ifdef USB_DETECT_BY_REQUEST
+ usb_set_host_present(true);
+#endif
+
usb_core_handle_transfer_completion(
(struct usb_transfer_completion_event_data*)ev.data);
break;
@@ -387,72 +448,26 @@ static void NORETURN_ATTR usb_thread(void)
if(usb_state != USB_EXTRACTED)
break;
+#ifdef HAVE_LCD_BITMAP
if(usb_do_screendump())
- break;
-
- usb_state = USB_POWERED;
- usb_stack_enable(true);
-
-#ifdef USB_DETECT_BY_CORE
- /* Wait for USB core to detect the host */
- break;
-
- case USB_HOSTED:
- if(usb_state != USB_POWERED)
- break;
-#endif /* USB_DETECT_BY_CORE */
-
- if(host_detected)
- break;
-
- host_detected = true;
-
- if(usb_power_button())
{
- /* Only charging is desired */
- usb_configure_drivers(USB_POWERED);
+ usb_state = USB_SCREENDUMP;
break;
}
+#endif
- if(!usb_configure_drivers(USB_INSERTED))
- break; /* Exclusive storage access not required */
-
- /* Tell all threads that they have to back off the storage.
- We subtract one for our own thread. Expect an ACK for every
- listener for each broadcast they received. If it has been too
- long, the user might have entered a screen that didn't ACK
- when inserting the cable, such as a debugging screen. In that
- case, reset the count or else USB would be locked out until
- rebooting because it most likely won't ever come. Simply
- resetting to the most recent broadcast count is racy. */
- if(TIME_AFTER(current_tick, last_broadcast_tick + HZ*5))
- {
- num_acks_to_expect = 0;
- last_broadcast_tick = current_tick;
- }
-
- num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
- DEBUGF("usb: waiting for %d acks...\n", num_acks_to_expect);
+ usb_state = USB_POWERED;
+ usb_stack_enable(true);
- /* Leave the state as USB_POWERED until the expected number of
- ACKS are received. */
+#ifndef USB_DETECT_BY_REQUEST
+ usb_set_host_present(true);
+#endif
break;
- /* USB_INSERTED: or USB_HOSTED: */
+ /* USB_INSERTED */
case SYS_USB_CONNECTED_ACK:
- if(num_acks_to_expect > 0 && --num_acks_to_expect == 0)
- {
- DEBUGF("usb: all threads have acknowledged the connect.\n");
- if(host_detected)
- {
- usb_slave_mode(true);
- usb_state = USB_INSERTED;
- }
- }
- else
- {
- DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect);
- }
+ if(usb_handle_connected_ack())
+ usb_state = USB_INSERTED;
break;
/* SYS_USB_CONNECTED_ACK */
@@ -470,13 +485,7 @@ static void NORETURN_ATTR usb_thread(void)
usb_state = USB_EXTRACTED;
- if(host_detected)
- {
- /* Ok to broadcast disconnect now */
- usb_configure_drivers(USB_EXTRACTED);
- host_detected = false;
- }
-
+ usb_set_host_present(false);
break;
/* USB_EXTRACTED: */
@@ -530,8 +539,7 @@ void usb_status_event(int current_status)
{
/* Caller isn't expected to filter for changes in status.
* current_status:
- * all: USB_INSERTED, USB_EXTRACTED
- * USB_DETECT_BY_CORE: USB_HOSTED (from core)
+ * USB_INSERTED, USB_EXTRACTED
*/
if(usb_monitor_enabled)
{
@@ -552,10 +560,6 @@ void usb_start_monitoring(void)
/* An event may have been missed because it was sent before monitoring
* was enabled due to the connector already having been inserted before
* before or during boot. */
-#ifdef USB_DETECT_BY_CORE
- /* Filter the status - USB_HOSTED may happen later */
- status = (status == USB_INSERTED) ? : USB_EXTRACTED;
-#endif
usb_status_event(status);
#ifdef USB_FIREWIRE_HANDLING