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
This commit is contained in:
Frank Gevaerts 2012-01-04 21:55:09 +00:00
parent fd5524ff92
commit 4fcffcbdf3
10 changed files with 86 additions and 133 deletions

View file

@ -787,7 +787,7 @@ Lyre prototype 1 */
/* Priority in bootloader is wanted */
#define HAVE_PRIORITY_SCHEDULING
#define USB_STATUS_BY_EVENT
#define USB_DETECT_BY_CORE
#define USB_DETECT_BY_REQUEST
#if defined(HAVE_USBSTACK) && CONFIG_USBOTG == USBOTG_ARC
#define INCLUDE_TIMEOUT_API
#define USB_DRIVER_CLOSE
@ -815,17 +815,17 @@ Lyre prototype 1 */
#ifdef HAVE_USBSTACK
#if CONFIG_USBOTG == USBOTG_ARC
#define USB_STATUS_BY_EVENT
#define USB_DETECT_BY_CORE
#define USB_DETECT_BY_REQUEST
#define INCLUDE_TIMEOUT_API
#elif CONFIG_USBOTG == USBOTG_AS3525
#define USB_STATUS_BY_EVENT
#define USB_DETECT_BY_CORE
#define USB_DETECT_BY_REQUEST
#elif CONFIG_USBOTG == USBOTG_S3C6400X /* FIXME */ && CONFIG_CPU == AS3525v2
#define USB_STATUS_BY_EVENT
#define USB_DETECT_BY_CORE
#define USB_DETECT_BY_REQUEST
#elif CONFIG_USBOTG == USBOTG_RK27XX
#define USB_STATUS_BY_EVENT
#define USB_DETECT_BY_CORE
#define USB_DETECT_BY_REQUEST
#endif /* CONFIG_USB == */
#endif /* HAVE_USBSTACK */

View file

@ -39,9 +39,6 @@ enum
USB_EXTRACTED = 0, /* Event+State */
USB_INSERTED, /* Event+State */
USB_POWERED, /* State - transitional indicator if no power */
#ifdef USB_DETECT_BY_CORE
USB_HOSTED, /* Event - host presence was detected */
#endif
#if (CONFIG_STORAGE & STORAGE_MMC)
USB_REENABLE, /* Event */
#endif

View file

@ -24,7 +24,6 @@
#include "kernel.h"
void usb_drv_startup(void);
void usb_drv_usb_detect_event(void); /* Target implemented */
void usb_drv_int_enable(bool enable); /* Target implemented */
void usb_drv_init(void);
void usb_drv_exit(void);

View file

@ -58,22 +58,6 @@ void usb_remove_int(void)
#endif
}
void usb_drv_usb_detect_event(void)
{
#if (CONFIG_CPU != AS3525v2 || defined(USE_ROCKBOX_USB)) \
&& defined (USB_STATUS_BY_EVENT)
/* Rebooting on USB plug can crash these players in a state where
* hardware power off (pressing the power button) doesn't work anymore
* TODO: Implement USB in rockbox for these players */
int oldstatus = disable_irq_save(); /* May come via USB thread */
if (usb_status == USB_INSERTED)
usb_status_event(USB_HOSTED);
restore_irq(oldstatus);
#endif
}
int usb_detect(void)
{
return usb_status;

View file

@ -40,11 +40,6 @@ void usb_remove_int(void)
usb_status_event(USB_EXTRACTED);
}
void usb_drv_usb_detect_event()
{
usb_status_event(USB_HOSTED);
}
void usb_attach(void)
{
usb_drv_attach();

View file

@ -145,13 +145,6 @@ void usb_drv_int_enable(bool enable)
}
}
/* Called during the setup packet request by the host */
void usb_drv_usb_detect_event(void)
{
if (usb_drv_powered())
usb_status_event(USB_HOSTED);
}
/* Called when reading the MBR */
void usb_fix_mbr(unsigned char *mbr)
{

View file

@ -224,15 +224,6 @@ void usb_insert_int(void)
USB_GPIO_INT_CLR = USB_GPIO_MASK;
timeout_register(&usb_oneshot, usb_timeout_event, HZ/5, val);
}
/* USB_DETECT_BY_CORE: Called when device descriptor is requested */
void usb_drv_usb_detect_event(void)
{
/* Filter for invalid bus reset when unplugging by checking the pin state. */
if(usb_plugged()) {
usb_status_event(USB_HOSTED);
}
}
#endif /* USB_STATUS_BY_EVENT */
#ifdef HAVE_BOOTLOADER_USB_MODE

View file

@ -30,11 +30,6 @@
int usb_status = USB_EXTRACTED;
void usb_drv_usb_detect_event()
{
usb_status_event(USB_INSERTED);
}
void usb_init_device(void)
{
}

View file

@ -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())
{
usb_state = USB_SCREENDUMP;
break;
}
#endif
usb_state = USB_POWERED;
usb_stack_enable(true);
#ifdef USB_DETECT_BY_CORE
/* Wait for USB core to detect the host */
#ifndef USB_DETECT_BY_REQUEST
usb_set_host_present(true);
#endif
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);
break;
}
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);
/* Leave the state as USB_POWERED until the expected number of
ACKS are received. */
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

View file

@ -559,11 +559,6 @@ static void request_handler_device_get_descriptor(struct usb_ctrlrequest* req)
case USB_DT_DEVICE:
ptr = &device_descriptor;
size = sizeof(struct usb_device_descriptor);
#ifdef USB_DETECT_BY_CORE
/* Something requested a device descriptor; consider this a legit
connection */
usb_drv_usb_detect_event();
#endif
break;
case USB_DT_OTHER_SPEED_CONFIG: