diff --git a/firmware/export/usb_core.h b/firmware/export/usb_core.h index be3e4789d9..2027cca5e8 100644 --- a/firmware/export/usb_core.h +++ b/firmware/export/usb_core.h @@ -50,6 +50,7 @@ void usb_core_exit(void); void usb_core_control_request(struct usb_ctrlrequest* req); void usb_core_transfer_complete(int endpoint, bool in); void usb_core_bus_reset(void); +bool usb_core_data_connection(void); #endif diff --git a/firmware/target/arm/usb-fw-pp502x.c b/firmware/target/arm/usb-fw-pp502x.c index cff3089ae0..768368d575 100644 --- a/firmware/target/arm/usb-fw-pp502x.c +++ b/firmware/target/arm/usb-fw-pp502x.c @@ -56,34 +56,118 @@ void usb_init_device(void) void usb_enable(bool on) { - if (on) - usb_core_init(); + if (on) { + /* 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 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 */ + } + } else usb_core_exit(); } +bool usb_pin_detect(void) +{ +#if defined(IPOD_ARCH) + /* GPIO L bit 4 is usb detect */ + if (GPIOL_INPUT_VAL & 0x10) + return true; + +#elif defined(SANSA_C200) + /* GPIO H bit 1 is usb detect */ + if (GPIOH_INPUT_VAL & 0x02) + return true; + +#elif defined(SANSA_E200) + /* GPIO B bit 4 is usb detect */ + if (GPIOB_INPUT_VAL & 0x10) + return true; + +#elif defined(IRIVER_H10) || defined(IRIVER_H10_5GB) + /* GPIO L bit 2 is usb detect */ + if (GPIOL_INPUT_VAL & 0x4) + return true; +#endif + return false; +} + +/* 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 defined(IPOD_COLOR) || defined(IPOD_4G) \ || defined(IPOD_MINI) || defined(IPOD_MINI2G) /* GPIO C bit 1 is firewire detect */ if (!(GPIOC_INPUT_VAL & 0x02)) - return USB_INSERTED; -#elif defined(SANSA_C200) - /* GPIO H bit 1 is usb detect */ - if (GPIOH_INPUT_VAL & 0x02) - return USB_INSERTED; -#elif defined(SANSA_E200) - /* GPIO B bit 4 is usb detect */ - if (GPIOB_INPUT_VAL & 0x10) - return USB_INSERTED; -#elif defined(IRIVER_H10) || defined(IRIVER_H10_5GB) - /* GPIO L bit 2 is usb detect */ - if (GPIOL_INPUT_VAL & 0x4) + /* no charger detection needed for firewire */ return USB_INSERTED; #endif - if (usb_drv_powered()) - return USB_INSERTED; - return USB_EXTRACTED; + 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; + return status; + } + + /* 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 50 ticks (500ms) before deciding there is no computer + attached. */ + countdown = 50; + + return status; } diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 7f610ff83a..8e71c77ed7 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -292,6 +292,7 @@ static const struct { static int usb_address = 0; static bool initialized = false; +static bool data_connection = false; static struct event_queue usbcore_queue; #ifdef USB_STORAGE @@ -305,6 +306,9 @@ static void ack_control(struct usb_ctrlrequest* req); void usb_core_init(void) { + if (initialized) + return; + queue_init(&usbcore_queue, false); usb_drv_init(); #ifdef USB_STORAGE @@ -331,10 +335,16 @@ void usb_core_exit(void) #ifdef USB_STORAGE remove_thread(usbcore_thread); #endif + data_connection = false; } logf("usb_core_exit() finished"); } +bool usb_core_data_connection(void) +{ + return data_connection; +} + #ifdef USB_STORAGE void usb_core_thread(void) { @@ -352,6 +362,7 @@ void usb_core_thread(void) void usb_core_control_request(struct usb_ctrlrequest* req) { /* note: interrupt context */ + data_connection = true; #ifdef USB_BENCHMARK if ((req->bRequestType & 0x60) == USB_TYPE_VENDOR) { @@ -499,6 +510,7 @@ void usb_core_control_request(struct usb_ctrlrequest* req) void usb_core_bus_reset(void) { usb_address = 0; + data_connection = false; } /* called by usb_drv_transfer_completed() */