From c0e5ac42ef93abd5720ae28e47701ed3996d8af8 Mon Sep 17 00:00:00 2001 From: gevaerts Date: Wed, 27 Feb 2008 19:08:30 +0000 Subject: [PATCH] move the usb_core thread functionality to the main usb thread fix button-detection so screenshots and charge-only mode work without enabling UMS firewire detection is now handled separately from usb detection increase the usb thread priority while an UMS connection is active git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16435 a1c6a512-1295-4272-9138-f99709370657 --- apps/main.c | 2 + firmware/export/usb.h | 35 ++++++++-- firmware/export/usb_core.h | 30 ++------- firmware/target/arm/usb-fw-pp502x.c | 123 ++++++++-------------------------- firmware/usb.c | 124 ++++++++++++++++++++++++++++++++-- firmware/usbstack/usb_core.c | 128 ++++++++++++------------------------ 6 files changed, 223 insertions(+), 219 deletions(-) diff --git a/apps/main.c b/apps/main.c index 92e7149fe..3b2d516bd 100644 --- a/apps/main.c +++ b/apps/main.c @@ -457,7 +457,9 @@ static void init(void) #endif { usb_screen(); +#ifndef HAVE_USBSTACK mounted = true; /* mounting done @ end of USB mode */ +#endif } #ifdef HAVE_USB_POWER if (usb_powered()) /* avoid deadlock */ diff --git a/firmware/export/usb.h b/firmware/export/usb.h index ebeb93ad2..4bfbfd4b7 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h @@ -23,15 +23,17 @@ #include "button.h" /* Messages from usb_tick and thread states */ -#define USB_INSERTED 1 -#define USB_EXTRACTED 2 -#ifdef HAVE_MMC -#define USB_REENABLE 3 -#endif +enum { + USB_INSERTED, + USB_EXTRACTED, + USB_REENABLE, + USB_POWERED, + USB_TRANSFER_COMPLETION, + USB_REQUEST_REBOOT +}; -#ifdef HAVE_USB_POWER -#define USB_POWERED 4 +#ifdef HAVE_USB_POWER #if CONFIG_KEYPAD == RECORDER_PAD #define USBPOWER_BUTTON BUTTON_F1 #define USBPOWER_BTN_IGNORE BUTTON_ON @@ -70,6 +72,16 @@ enum { USB_DRIVER_COUNT }; #endif +#ifdef HAVE_USBSTACK +struct usb_transfer_completion_event_data +{ + unsigned char endpoint; + bool in; + int status; + int length; + void* data; +}; +#endif void usb_init(void); @@ -87,5 +99,14 @@ bool usb_charging_enable(bool on); bool usb_charging_enabled(void); #endif #endif +#ifdef HAVE_USBSTACK +void usb_signal_transfer_completion(struct usb_transfer_completion_event_data* event_data); +bool usb_driver_enabled(int driver); +#endif + +#if defined(IPOD_COLOR) || defined(IPOD_4G) \ + || defined(IPOD_MINI) || defined(IPOD_MINI2G) +bool firewire_detect(void); +#endif #endif diff --git a/firmware/export/usb_core.h b/firmware/export/usb_core.h index 73cf5c012..6af3545b3 100644 --- a/firmware/export/usb_core.h +++ b/firmware/export/usb_core.h @@ -20,34 +20,23 @@ #define USB_CORE_H #ifndef BOOTLOADER -#define USB_THREAD -#ifdef USE_ROCKBOX_USB //#define USB_SERIAL //#define USB_BENCHMARK #define USB_STORAGE - -#else #define USB_CHARGING_ONLY - -#endif /* USE_ROCKBOX_USB */ -#else +#else /* BOOTLOADER */ #define USB_CHARGING_ONLY #endif /* BOOTLOADER */ #include "usb_ch9.h" +#include "usb.h" #if defined(CPU_PP) #define USB_IRAM_ORIGIN ((unsigned char *)0x4000c000) #define USB_IRAM_SIZE ((size_t)0xc000) #endif - -enum { - USB_CORE_QUIT, - USB_CORE_TRANSFER_COMPLETION -}; - /* endpoints */ enum { EP_CONTROL = 0, @@ -66,16 +55,6 @@ enum { NUM_ENDPOINTS }; - -/* queue events */ -#define USB_TRANSFER_COMPLETE 1 - -struct queue_msg { - int endpoint; - int length; - void* data; -}; - extern int usb_max_pkt_size; void usb_core_init(void); @@ -83,7 +62,8 @@ void usb_core_exit(void); void usb_core_control_request(struct usb_ctrlrequest* req); void usb_core_transfer_complete(int endpoint, bool in, int status, int length); void usb_core_bus_reset(void); -bool usb_core_data_connection(void); - +bool usb_core_exclusive_connection(void); +void usb_core_enable_protocol(int driver,bool enabled); +void usb_core_handle_transfer_completion(struct usb_transfer_completion_event_data* event); #endif diff --git a/firmware/target/arm/usb-fw-pp502x.c b/firmware/target/arm/usb-fw-pp502x.c index bc0c339e4..e0558a190 100644 --- a/firmware/target/arm/usb-fw-pp502x.c +++ b/firmware/target/arm/usb-fw-pp502x.c @@ -70,33 +70,25 @@ void usb_init_device(void) void usb_enable(bool on) { if (on) { - usb_core_init(); -#if !defined(USE_ROCKBOX_USB) - /* until we have native mass-storage mode, we want to reboot on - usb host connect */ -#if defined(IRIVER_H10) || defined (IRIVER_H10_5GB) - if (button_status()==BUTTON_RIGHT) -#endif /* defined(IRIVER_H10) || defined (IRIVER_H10_5GB) */ - { -#ifndef HAVE_FLASH_STORAGE - ata_sleepnow(); /* Immediately spindown the disk. */ - sleep(HZ*2); -#endif - -#ifdef IPOD_ARCH /* The following code is based on ipodlinux */ + /* if USB is detected, re-enable the USB-devices, otherwise make sure it's disabled */ + DEV_EN |= DEV_USB0; + DEV_RS &=~DEV_USB0; + DEV_EN |= DEV_USB1; + DEV_RS &=~DEV_USB1; #if CONFIG_CPU == PP5020 - memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21); -#elif CONFIG_CPU == PP5022 - memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21); -#endif /* CONFIG_CPU */ -#endif /* IPOD_ARCH */ - - system_reboot(); /* Reboot */ - } -#endif /* USE_ROCKBOX_USB */ + DEV_INIT2 |= INIT_USB; +#endif + usb_core_init(); } - else + else { usb_core_exit(); + /* Disable USB devices */ + DEV_EN &=~ DEV_USB0; + DEV_EN &=~ DEV_USB1; +#if CONFIG_CPU == PP5020 + DEV_INIT2 &=~ INIT_USB; +#endif + } } static bool usb_pin_detect(void) @@ -136,80 +128,23 @@ static bool usb_pin_detect(void) /* detect host or charger (INSERTED or POWERED) */ int usb_detect(void) { - static int countdown = 0; - static int status = USB_EXTRACTED; - static bool prev_usbstatus1 = false; - bool usbstatus1, usbstatus2; + if(usb_pin_detect()) { + return USB_INSERTED; + } + else { + return USB_EXTRACTED; + } +} #if defined(IPOD_COLOR) || defined(IPOD_4G) \ || defined(IPOD_MINI) || defined(IPOD_MINI2G) +bool firewire_detect(void) +{ /* GPIO C bit 1 is firewire detect */ if (!(GPIOC_INPUT_VAL & 0x02)) /* no charger detection needed for firewire */ - return USB_INSERTED; -#endif - - if (countdown > 0) - { - countdown--; - - usbstatus2 = usb_core_data_connection(); - if ((countdown == 0) || usbstatus2) - { - /* We now know that we have been connected to either a charger - or a computer */ - countdown = 0; - status = usbstatus2 ? USB_INSERTED : USB_POWERED; - } - return status; - } - - usbstatus1 = usb_pin_detect(); - - if (usbstatus1 == prev_usbstatus1) - { - /* Nothing has changed, so just return previous status */ - return status; - } - prev_usbstatus1 = usbstatus1; - - if (!usbstatus1) - { /* We have just been disconnected */ - status = USB_EXTRACTED; - - /* Disable USB devices */ - DEV_EN &=~ DEV_USB0; - DEV_EN &=~ DEV_USB1; -#if CONFIG_CPU == PP5020 - DEV_INIT2 &=~ INIT_USB; -#endif - - return status; - } else { - /* if USB is detected, re-enable the USB-devices, otherwise make sure it's disabled */ - DEV_EN |= DEV_USB0; - DEV_RS &=~DEV_USB0; - DEV_EN |= DEV_USB1; - DEV_RS &=~DEV_USB1; -#if CONFIG_CPU == PP5020 - DEV_INIT2 |= INIT_USB; -#endif - } - - /* Run the USB stack to request full bus power */ - usb_core_init(); - - if((button_status() & ~USBPOWER_BTN_IGNORE) == USBPOWER_BUTTON) - { - /* The user wants to charge, so it doesn't matter what we are - connected to. */ - status = USB_POWERED; - return status; - } - - /* Wait up to 100 ticks (1s) before deciding there is no computer - attached. */ - countdown = 100; - - return status; + return true; + else + return false; } +#endif diff --git a/firmware/usb.c b/firmware/usb.c index 75ee4759c..3ba7480f8 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -37,6 +37,9 @@ #include "sprintf.h" #include "string.h" #include "usb-target.h" +#ifdef HAVE_USBSTACK +#include "usb_core.h" +#endif #ifdef IRIVER_H300_SERIES #include "pcf50606.h" /* for pcf50606_usb_charging_... */ #endif @@ -65,13 +68,23 @@ static int usb_mmc_countdown = 0; #ifndef BOOTLOADER static long usb_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)]; static const char usb_thread_name[] = "usb"; +static struct thread_entry *usb_thread_entry; #endif static struct event_queue usb_queue; static int last_usb_status; static bool usb_monitor_enabled; +#if defined(IPOD_COLOR) || defined(IPOD_4G) \ + || defined(IPOD_MINI) || defined(IPOD_MINI2G) +static int firewire_countdown; +static bool last_firewire_status; +#endif + + + #ifndef BOOTLOADER +#ifndef HAVE_USBSTACK static void usb_slave_mode(bool on) { int rc; @@ -88,10 +101,8 @@ static void usb_slave_mode(bool on) { DEBUGF("Leaving USB slave mode\n"); -#ifndef HAVE_USBSTACK /* Let the ISDx00 settle */ sleep(HZ*1); -#endif usb_enable(false); @@ -116,6 +127,30 @@ static void usb_slave_mode(bool on) } } +#endif + +static void try_reboot(void) +{ +#if defined(IRIVER_H10) || defined (IRIVER_H10_5GB) + if (button_status()==BUTTON_RIGHT) +#endif /* defined(IRIVER_H10) || defined (IRIVER_H10_5GB) */ + { +#ifndef HAVE_FLASH_STORAGE + ata_sleepnow(); /* Immediately spindown the disk. */ + sleep(HZ*2); +#endif + +#ifdef IPOD_ARCH /* The following code is based on ipodlinux */ +#if CONFIG_CPU == PP5020 + memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21); +#elif CONFIG_CPU == PP5022 + memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21); +#endif /* CONFIG_CPU */ +#endif /* IPOD_ARCH */ + + system_reboot(); /* Reboot */ + } +} static void usb_thread(void) { @@ -130,6 +165,11 @@ static void usb_thread(void) queue_wait(&usb_queue, &ev); switch(ev.id) { +#ifdef HAVE_USBSTACK + case USB_TRANSFER_COMPLETION: + usb_core_handle_transfer_completion((struct usb_transfer_completion_event_data*)ev.data); + break; +#endif #ifdef HAVE_USB_POWER case USB_POWERED: usb_state = USB_POWERED; @@ -147,6 +187,12 @@ static void usb_thread(void) if((button_status() & ~USBPOWER_BTN_IGNORE) == USBPOWER_BUTTON) { usb_state = USB_POWERED; +#ifdef HAVE_USBSTACK + usb_core_enable_protocol(USB_DRIVER_MASS_STORAGE,false); + usb_core_enable_protocol(USB_DRIVER_SERIAL,false);/* TODO: add debug setting */ + usb_core_enable_protocol(USB_DRIVER_CHARGING_ONLY,true); + usb_enable(true); +#endif } else #endif @@ -168,9 +214,26 @@ static void usb_thread(void) if(num_acks_to_expect == 0) { DEBUGF("All threads have acknowledged the connect.\n"); +#ifdef HAVE_USBSTACK +#ifdef HAVE_PRIORITY_SCHEDULING + thread_set_priority(usb_thread_entry,PRIORITY_REALTIME); +#endif +#ifdef USE_ROCKBOX_USB + usb_core_enable_protocol(USB_DRIVER_MASS_STORAGE,true); + usb_core_enable_protocol(USB_DRIVER_SERIAL,false);/* TODO: add debug setting */ + usb_core_enable_protocol(USB_DRIVER_CHARGING_ONLY,false); + usb_enable(true); +#else /* USE_ROCKBOX_USB */ + /* until we have native mass-storage mode, we want to reboot on + usb host connect */ + try_reboot(); +#endif /* USE_ROCKBOX_USB */ + +#else usb_slave_mode(true); - usb_state = USB_INSERTED; cpu_idle_mode(true); +#endif + usb_state = USB_INSERTED; } else { @@ -181,6 +244,12 @@ static void usb_thread(void) break; case USB_EXTRACTED: +#ifdef HAVE_USBSTACK + usb_enable(false); +#ifdef HAVE_PRIORITY_SCHEDULING + thread_set_priority(usb_thread_entry,PRIORITY_SYSTEM); +#endif +#endif #ifdef HAVE_LCD_BITMAP if(do_screendump_instead_of_usb) break; @@ -192,6 +261,7 @@ static void usb_thread(void) break; } #endif +#ifndef HAVE_USBSTACK if(usb_state == USB_INSERTED) { /* Only disable the USB mode if we really have enabled it @@ -200,6 +270,7 @@ static void usb_thread(void) usb_slave_mode(false); cpu_idle_mode(false); } +#endif usb_state = USB_EXTRACTED; @@ -243,11 +314,21 @@ static void usb_thread(void) usb_enable(true); /* reenable only if still inserted */ break; #endif + case USB_REQUEST_REBOOT: + if((button_status() & ~USBPOWER_BTN_IGNORE) != USBPOWER_BUTTON) + try_reboot(); + break; } } } #endif +#ifdef HAVE_USBSTACK +void usb_signal_transfer_completion(struct usb_transfer_completion_event_data* event_data) +{ + queue_post(&usb_queue, USB_TRANSFER_COMPLETION, (intptr_t)event_data); +} +#endif #ifndef BOOTLOADER static void usb_tick(void) @@ -256,6 +337,29 @@ static void usb_tick(void) if(usb_monitor_enabled) { +#if defined(IPOD_COLOR) || defined(IPOD_4G) \ + || defined(IPOD_MINI) || defined(IPOD_MINI2G) + int current_firewire_status = firewire_detect(); + if(current_firewire_status != last_firewire_status) + { + last_firewire_status = current_firewire_status; + firewire_countdown = NUM_POLL_READINGS; + } + else + { + /* Count down until it gets negative */ + if(firewire_countdown >= 0) + firewire_countdown--; + + /* Report to the thread if we have had 3 identical status + readings in a row */ + if(firewire_countdown == 0) + { + queue_post(&usb_queue, USB_REQUEST_REBOOT, 0); + } + } +#endif + current_status = usb_detect(); /* Only report when the status has changed */ @@ -300,18 +404,24 @@ void usb_init(void) usb_monitor_enabled = false; countdown = -1; +#if defined(IPOD_COLOR) || defined(IPOD_4G) \ + || defined(IPOD_MINI) || defined(IPOD_MINI2G) + firewire_countdown = -1; + last_firewire_status = false; +#endif + usb_init_device(); usb_enable(false); /* We assume that the USB cable is extracted */ - last_usb_status = false; + last_usb_status = USB_EXTRACTED; #ifndef BOOTLOADER queue_init(&usb_queue, true); - create_thread(usb_thread, usb_stack, sizeof(usb_stack), 0, - usb_thread_name IF_PRIO(, PRIORITY_SYSTEM) - IF_COP(, CPU)); + usb_thread_entry = create_thread(usb_thread, usb_stack, + sizeof(usb_stack), 0, usb_thread_name + IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU)); tick_add_task(usb_tick); #endif diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 38797bc35..b389b4706 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -28,8 +28,6 @@ #include "usb_drv.h" #include "usb_core.h" -#define USB_THREAD - #if defined(USB_STORAGE) #include "usb_storage.h" #endif @@ -289,28 +287,14 @@ static struct usb_string_descriptor* usb_strings[] = static int usb_address = 0; static bool initialized = false; -static bool data_connection = false; -static struct event_queue usbcore_queue; static enum { DEFAULT, ADDRESS, CONFIGURED } usb_state; -#ifdef USB_THREAD -static const char usbcore_thread_name[] = "usb_core"; -static struct thread_entry* usbcore_thread; -static long usbcore_stack[DEFAULT_STACK_SIZE]; -static void usb_core_thread(void); -#endif - -#ifdef USE_ROCKBOX_USB +static bool usb_core_storage_enabled = false; +static bool usb_core_serial_enabled = false; static bool usb_core_charging_enabled = false; -static bool usb_core_storage_enabled = true; -static bool usb_core_serial_enabled = true; #if defined(USB_BENCHMARK) static bool usb_core_benchmark_enabled = false; #endif -#else -static bool usb_core_charging_enabled = true; -#endif - static void usb_core_control_request_handler(struct usb_ctrlrequest* req); static int ack_control(struct usb_ctrlrequest* req); @@ -318,16 +302,7 @@ static int ack_control(struct usb_ctrlrequest* req); static unsigned char *response_data; static unsigned char __response_data[CACHEALIGN_UP(256)] CACHEALIGN_ATTR; -struct usb_core_event -{ - unsigned char endpoint; - bool in; - int status; - int length; - void* data; -}; - -static struct usb_core_event events[NUM_ENDPOINTS]; +static struct usb_transfer_completion_event_data events[NUM_ENDPOINTS]; #ifdef IPOD_ARCH static void set_serial_descriptor(void) @@ -408,8 +383,11 @@ void usb_core_init(void) response_data = (void*)UNCACHED_ADDR(&__response_data); - queue_init(&usbcore_queue, false); usb_drv_init(); + + /* class driver init functions should be safe to call even if the driver + * won't be used. This simplifies other logic (i.e. we don't need to know + * yet which drivers will be enabled */ #ifdef USB_STORAGE usb_storage_init(); #endif @@ -418,14 +396,6 @@ void usb_core_init(void) usb_serial_init(); #endif -#ifdef USB_THREAD - usbcore_thread = - create_thread(usb_core_thread, usbcore_stack, sizeof(usbcore_stack), 0, - usbcore_thread_name - IF_PRIO(, PRIORITY_SYSTEM) - IF_COP(, CPU)); -#endif - #ifdef USB_BENCHMARK usb_benchmark_init(); #endif @@ -438,71 +408,57 @@ void usb_core_exit(void) { if (initialized) { usb_drv_exit(); -#ifdef USB_THREAD - queue_post(&usbcore_queue, USB_CORE_QUIT, 0); - thread_wait(usbcore_thread); -#endif - queue_delete(&usbcore_queue); } - data_connection = false; initialized = false; logf("usb_core_exit() finished"); } -bool usb_core_data_connection(void) -{ - return data_connection; -} - -#ifdef USB_THREAD -void usb_core_thread(void) +void usb_core_handle_transfer_completion(struct usb_transfer_completion_event_data* event) { - while (1) { - struct queue_event ev; - - queue_wait(&usbcore_queue, &ev); - if (ev.id == USB_CORE_QUIT) { - cancel_cpu_boost(); - return; - } - - if (ev.id == USB_CORE_TRANSFER_COMPLETION) { - struct usb_core_event* event = (struct usb_core_event*)ev.data; - switch(event->endpoint) { - case EP_CONTROL: - logf("ctrl handled %ld",current_tick); - usb_core_control_request_handler((struct usb_ctrlrequest*)event->data); - break; + switch(event->endpoint) { + case EP_CONTROL: + logf("ctrl handled %ld",current_tick); + usb_core_control_request_handler((struct usb_ctrlrequest*)event->data); + break; #ifdef USB_STORAGE - case EP_MASS_STORAGE: - usb_storage_transfer_complete(event->in,event->status,event->length); - break; + case EP_MASS_STORAGE: + usb_storage_transfer_complete(event->in,event->status,event->length); + break; #endif #ifdef USB_SERIAL - case EP_SERIAL: - usb_serial_transfer_complete(event->in,event->status,event->length); - break; + case EP_SERIAL: + usb_serial_transfer_complete(event->in,event->status,event->length); + break; #endif #ifdef USB_BENCHMARK - case EP_BENCHMARK: - usb_benchmark_transfer_complete(event->in); - break; + case EP_BENCHMARK: + usb_benchmark_transfer_complete(event->in); + break; #endif #ifdef USB_CHARGING_ONLY - case EP_CHARGING_ONLY: - break; + case EP_CHARGING_ONLY: + break; #endif - } - } } } -#endif -static void usb_core_control_request_handler(struct usb_ctrlrequest* req) +void usb_core_enable_protocol(int driver,bool enabled) { - /* note: interrupt context */ - data_connection = true; + switch(driver) { + case USB_DRIVER_MASS_STORAGE: + usb_core_storage_enabled = enabled; + break; + case USB_DRIVER_SERIAL: + usb_core_serial_enabled = enabled; + break; + case USB_DRIVER_CHARGING_ONLY: + usb_core_charging_enabled = enabled; + break; + } +} +static void usb_core_control_request_handler(struct usb_ctrlrequest* req) +{ if(usb_state == DEFAULT) { set_serial_descriptor(); } @@ -766,13 +722,13 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req) } break; } + logf("control handled"); } /* called by usb_drv_int() */ void usb_core_bus_reset(void) { usb_address = 0; - data_connection = false; usb_state = DEFAULT; } @@ -795,7 +751,7 @@ void usb_core_transfer_complete(int endpoint, bool in, int status,int length) events[endpoint].status=status; events[endpoint].length=length; /* All other endoints. Let the thread deal with it */ - queue_post(&usbcore_queue, USB_CORE_TRANSFER_COMPLETION, (intptr_t)&events[endpoint]); + usb_signal_transfer_completion(&events[endpoint]); break; } } @@ -809,7 +765,7 @@ void usb_core_control_request(struct usb_ctrlrequest* req) events[0].status=0; events[0].length=0; logf("ctrl received %ld",current_tick); - queue_post(&usbcore_queue, USB_CORE_TRANSFER_COMPLETION,(intptr_t)&events[0]); + usb_signal_transfer_completion(&events[0]); } static int ack_control(struct usb_ctrlrequest* req) -- 2.11.4.GIT