FS #7691 - improved USB detection on PP devices.  This patch modifies the target-tree function usb_detect() on all targets from bool to int, returning USB_INSERTED or USB_EXTRACTED instead of true or false.  This was done to enable the PP usb_detect() to check for USB_POWER (either a connection to a USB wall charger, or the user holding "charge mode" button) and return that as a third value.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14600 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/main.c b/apps/main.c
index 3d41940..86f651f 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -444,7 +444,7 @@
 #endif
     
     usb_start_monitoring();
-    while (usb_detect())
+    while (usb_detect() == USB_INSERTED)
     {   
 #ifdef HAVE_EEPROM_SETTINGS
         firmware_settings.disk_clean = false;
diff --git a/bootloader/gigabeat.c b/bootloader/gigabeat.c
index e482c70..704548b 100644
--- a/bootloader/gigabeat.c
+++ b/bootloader/gigabeat.c
@@ -66,7 +66,7 @@
     usb_init();
 
     /* Enter USB mode without USB thread */
-    if(usb_detect())
+    if(usb_detect() == USB_INSERTED)
     {
         const char msg[] = "Bootloader USB mode";
         reset_screen();
@@ -78,7 +78,7 @@
         sleep(HZ/20);
         usb_enable(true);
 
-        while (usb_detect())
+        while (usb_detect() == USB_INSERTED)
             sleep(HZ);
 
         usb_enable(false);
diff --git a/bootloader/iriver_h300.c b/bootloader/iriver_h300.c
index dce178f..a3a15bd 100644
--- a/bootloader/iriver_h300.c
+++ b/bootloader/iriver_h300.c
@@ -169,7 +169,7 @@
 
     /* Turn off if we believe the start was accidental */
     if(!(rtc_alarm || on_button || rc_on_button ||
-         usb_detect() || charger_inserted())) {
+         (usb_detect() == USB_INSERTED) || charger_inserted())) {
         __reset_cookie();
         power_off();
     }
@@ -222,7 +222,8 @@
     {
         hold_status = true;
     }
-    if (hold_status && !rtc_alarm && !usb_detect() && !charger_inserted())
+    if (hold_status && !rtc_alarm && (usb_detect() != USB_INSERTED) && 
+        !charger_inserted())
     {
         if (detect_original_firmware())
         {
@@ -282,7 +283,7 @@
                 break;
             }
 
-            if(usb_detect())
+            if(usb_detect() == USB_INSERTED)
                 request_start = true;
         }
         if(!request_start)
@@ -297,7 +298,7 @@
     usb_init();
 
     /* A hack to enter USB mode without using the USB thread */
-    if(usb_detect())
+    if(usb_detect() == USB_INSERTED)
     {
         const char msg[] = "Bootloader USB mode";
         int w, h;
@@ -314,7 +315,7 @@
         sleep(HZ/20);
         usb_enable(true);
         cpu_idle_mode(true);
-        while (usb_detect())
+        while (usb_detect() == USB_INSERTED)
         {
             /* Print the battery status. */
             line = 0;
diff --git a/bootloader/main-pp.c b/bootloader/main-pp.c
index 0d377fd..8b85139 100644
--- a/bootloader/main-pp.c
+++ b/bootloader/main-pp.c
@@ -464,7 +464,7 @@
     {
         usb_retry++;
         sleep(HZ/4);
-        usb = usb_detect();
+        usb = (usb_detect() == USB_INSERTED);
     }
     if (usb)
         btn |= BOOTLOADER_BOOT_OF;
diff --git a/bootloader/main.c b/bootloader/main.c
index 0306eea..e60799f 100644
--- a/bootloader/main.c
+++ b/bootloader/main.c
@@ -388,7 +388,7 @@
     power_init();
 
     /* Turn off if neither ON button is pressed */
-    if(!(on_button || rc_on_button || usb_detect()))
+    if(!(on_button || rc_on_button || (usb_detect() == USB_INSERTED)))
     {
         __reset_cookie();
         power_off();
@@ -439,7 +439,7 @@
     }
     
 # ifdef EEPROM_SETTINGS
-    if (!hold_status && !usb_detect() && !recovery_mode)
+    if (!hold_status && (usb_detect() != USB_INSERTED) && !recovery_mode)
         try_flashboot();
 # endif
 
@@ -467,7 +467,7 @@
 
     /* Don't start if the Hold button is active on the device you
        are starting with */
-    if (!usb_detect() && (hold_status
+    if ((usb_detect() != USB_INSERTED) && (hold_status
 #ifdef HAVE_EEPROM_SETTINGS
                           || recovery_mode
 #endif
@@ -494,7 +494,7 @@
     usb_init();
 
     /* A hack to enter USB mode without using the USB thread */
-    if(usb_detect())
+    if(usb_detect() == USB_INSERTED)
     {
         const char msg[] = "Bootloader USB mode";
         int w, h;
@@ -520,7 +520,7 @@
         sleep(HZ/20);
         usb_enable(true);
         cpu_idle_mode(true);
-        while (usb_detect())
+        while (usb_detect() == USB_INSERTED)
         {
             /* Print the battery status. */
             line = 0;
diff --git a/firmware/export/usb.h b/firmware/export/usb.h
index 622db355..82b9d36 100644
--- a/firmware/export/usb.h
+++ b/firmware/export/usb.h
@@ -20,6 +20,41 @@
 #define _USB_H_
 
 #include "kernel.h"
+#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
+
+#ifdef HAVE_USB_POWER
+#define USB_POWERED     4
+
+#if CONFIG_KEYPAD == RECORDER_PAD
+#define USBPOWER_BUTTON BUTTON_F1
+#define USBPOWER_BTN_IGNORE BUTTON_ON
+#elif CONFIG_KEYPAD == ONDIO_PAD
+#define USBPOWER_BUTTON BUTTON_MENU
+#define USBPOWER_BTN_IGNORE BUTTON_OFF
+#elif (CONFIG_KEYPAD == IPOD_4G_PAD)
+#define USBPOWER_BUTTON BUTTON_MENU
+#define USBPOWER_BTN_IGNORE BUTTON_PLAY
+#elif CONFIG_KEYPAD == IRIVER_H300_PAD
+#define USBPOWER_BUTTON BUTTON_REC
+#define USBPOWER_BTN_IGNORE BUTTON_ON
+#elif CONFIG_KEYPAD == GIGABEAT_PAD
+#define USBPOWER_BUTTON BUTTON_MENU
+#define USBPOWER_BTN_IGNORE BUTTON_POWER
+#elif CONFIG_KEYPAD == IRIVER_H10_PAD
+#define USBPOWER_BUTTON BUTTON_NONE
+#define USBPOWER_BTN_IGNORE BUTTON_POWER
+#elif CONFIG_KEYPAD == SANSA_E200_PAD
+#define USBPOWER_BUTTON BUTTON_SELECT
+#define USBPOWER_BTN_IGNORE BUTTON_POWER
+#endif
+#endif /* HAVE_USB_POWER */
 
 void usb_init(void);
 void usb_enable(bool on);
@@ -28,7 +63,7 @@
 void usb_wait_for_disconnect(struct event_queue *q);
 int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks);
 bool usb_inserted(void); /* return the official value, what's been reported to the threads */
-bool usb_detect(void); /* return the raw hardware value */
+int usb_detect(void); /* return the raw hardware value - nothing/pc/charger */
 #ifdef HAVE_USB_POWER
 bool usb_powered(void);
 #ifdef CONFIG_CHARGING
diff --git a/firmware/target/arm/pnx0101/iriver-ifp7xx/usb-ifp7xx.c b/firmware/target/arm/pnx0101/iriver-ifp7xx/usb-ifp7xx.c
index a22a227..3761c84 100644
--- a/firmware/target/arm/pnx0101/iriver-ifp7xx/usb-ifp7xx.c
+++ b/firmware/target/arm/pnx0101/iriver-ifp7xx/usb-ifp7xx.c
@@ -37,10 +37,10 @@
 {
 }
 
-bool usb_detect(void)
+int usb_detect(void)
 {
     /* TODO: Implement USB_ISP1582 */
-    return false;
+    return USB_EXTRACTED;
 }
 
 void usb_enable(bool on)
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c
index 566d25e..217a7d3 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/usb-meg-fx.c
@@ -21,6 +21,7 @@
 #include "system.h"
 #include "kernel.h"
 #include "ata.h"
+#include "usb.h"
 
 #define USB_RST_ASSERT   GPBDAT &= ~(1 << 4)
 #define USB_RST_DEASSERT GPBDAT |=  (1 << 4)
@@ -35,9 +36,12 @@
 #define USB_CRADLE_BUS_DISABLE GPHDAT &= ~(1 << 8)
 
 /* The usb detect is one pin to the cpu active low */
-inline bool usb_detect(void)
+int usb_detect(void)
 {
-    return USB_UNIT_IS_PRESENT | USB_CRADLE_IS_PRESENT;
+   if (USB_UNIT_IS_PRESENT | USB_CRADLE_IS_PRESENT)
+       return USB_INSERTED;
+   else
+       return USB_EXTRACTED;
 }
 
 void usb_init_device(void)
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h
index baeb539..65690dc 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/usb-target.h
@@ -20,7 +20,6 @@
 #define USB_TARGET_H
 
 bool usb_init_device(void);
-bool usb_detect(void);
 void usb_enable(bool on);
 
 #endif
diff --git a/firmware/target/arm/usb-fw-pp5002.c b/firmware/target/arm/usb-fw-pp5002.c
index e64d4f8..2a216c4 100644
--- a/firmware/target/arm/usb-fw-pp5002.c
+++ b/firmware/target/arm/usb-fw-pp5002.c
@@ -56,15 +56,15 @@
     }
 }
 
-bool usb_detect(void)
+int usb_detect(void)
 {
 #if defined(IPOD_1G2G) || defined(IPOD_3G)
     /* GPIO C bit 7 is firewire detect */
     if (!(GPIOC_INPUT_VAL & 0x80))
-        return true;
+        return USB_INSERTED;
 #endif
 
     /* TODO: add USB detection for iPod 3rd gen */
 
-    return false;
+    return USB_EXTRACTED;
 }
diff --git a/firmware/target/arm/usb-fw-pp502x.c b/firmware/target/arm/usb-fw-pp502x.c
index 76bd728..ad2a105 100644
--- a/firmware/target/arm/usb-fw-pp502x.c
+++ b/firmware/target/arm/usb-fw-pp502x.c
@@ -92,7 +92,7 @@
 void usb_enable(bool on)
 {
 #ifdef HAVE_USBSTACK
-	(void)on;
+    (void)on;
 #else	
     /* This device specific code will eventually give way to proper USB
        handling, which should be the same for all PP502x targets. */
@@ -124,18 +124,42 @@
 #endif /* !HAVE_USBSTACK */
 }
 
-bool usb_detect(void)
+int usb_detect(void)
 {
+    static int countdown = 0;
+    static int status = USB_EXTRACTED;
     static bool prev_usbstatus1 = false;
-    bool usbstatus1,usbstatus2;
+    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 true;
+        return USB_INSERTED;
 #endif
 
+    if (countdown > 0)
+    {
+        countdown--;
+
+        usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false;
+        if ((countdown == 0) || usbstatus2)
+        {
+            countdown = 0;
+            status = usbstatus2 ? USB_INSERTED : USB_POWERED;
+            dr_controller_stop();
+
+#ifdef HAVE_USBSTACK
+            /* TODO: Move this call - it shouldn't be done in this function */
+            if (status == USB_INSERTED)
+            {
+                usb_stack_start();
+            }
+#endif
+        }
+        return status;
+    }
+
     /* UDC_ID should have the bit format:
         [31:24] = 0x0
         [23:16] = 0x22 (Revision number)
@@ -144,29 +168,51 @@
         [7:6]   = 0x0 (Reserved)
         [5:0]   = 0x05 (ID) */
     if (UDC_ID != 0x22FA05) {
-        return false;
+        /* This should never occur - do we even need to test? */
+        return USB_EXTRACTED;
     }
 
     usbstatus1 = (UDC_OTGSC & 0x800) ? true : false;
-#ifdef HAVE_USBSTACK
-    if ((usbstatus1 == true) && (prev_usbstatus1 == false)) {
-        usb_stack_start();
-    } else if ((usbstatus1 == false) && (prev_usbstatus1 == true)) {
-        usb_stack_stop();
-    }
-#else
-    if ((usbstatus1 == true) && (prev_usbstatus1 == false)) {
-        dr_controller_run();
-    } else if ((usbstatus1 == false) && (prev_usbstatus1 == true)) {
-        dr_controller_stop();
-    }
-#endif
-    prev_usbstatus1 = usbstatus1;
-    usbstatus2 = (UDC_PORTSC1 & PORTSCX_CURRENT_CONNECT_STATUS) ? true : false;
 
-    if (usbstatus1 && usbstatus2) {
-        return true;
-    } else {
-        return false;
+    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;
+#ifdef HAVE_USBSTACK
+        /* TODO: Move this call - it shouldn't be done in this function */
+        usb_stack_stop();
+#endif
+        return status;
+    }
+
+    /* We now know that we have just been connected to either a charger
+       or a computer */
+
+    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;
+    }
+
+    /* Run the USB controller for long enough to detect if we're connected
+       to a computer, then stop it again. */
+
+    dr_controller_run();
+
+    /* Wait for 50 ticks (500ms) before deciding there is no computer
+       attached.  The required value varied a lot between different users
+       when this feature was being tested. */
+
+    countdown = 50;
+
+    return status;
 }
diff --git a/firmware/target/coldfire/iaudio/usb-iaudio.c b/firmware/target/coldfire/iaudio/usb-iaudio.c
index 3bd1a7a..21d6961 100644
--- a/firmware/target/coldfire/iaudio/usb-iaudio.c
+++ b/firmware/target/coldfire/iaudio/usb-iaudio.c
@@ -20,6 +20,7 @@
 #include <stdbool.h>
 #include "cpu.h"
 #include "system.h"
+#include "usb.h"
 
 void usb_init_device(void)
 {
@@ -30,9 +31,9 @@
     or_l(0x00800000, &GPIO1_FUNCTION);  /* USB detect */
 }
 
-bool usb_detect(void)
+int usb_detect(void)
 {
-    return (GPIO1_READ & 0x00800000)?true:false;
+    return (GPIO1_READ & 0x00800000) ? USB_INSERTED : USB_EXTRACTED;
 }
 
 void usb_enable(bool on)
diff --git a/firmware/target/coldfire/iriver/h100/usb-h100.c b/firmware/target/coldfire/iriver/h100/usb-h100.c
index 3b00e96..5a2f7f5 100644
--- a/firmware/target/coldfire/iriver/h100/usb-h100.c
+++ b/firmware/target/coldfire/iriver/h100/usb-h100.c
@@ -21,6 +21,7 @@
 #include "cpu.h"
 #include "system.h"
 #include "kernel.h"
+#include "usb.h"
 
 void usb_init_device(void)
 {
@@ -30,9 +31,9 @@
     or_l(0x01000040, &GPIO_FUNCTION);
 }
 
-bool usb_detect(void)
+int usb_detect(void)
 {
-    return (GPIO1_READ & 0x80)?true:false;
+    return (GPIO1_READ & 0x80) ? USB_INSERTED : USB_EXTRACTED;
 }
 
 void usb_enable(bool on)
diff --git a/firmware/target/coldfire/iriver/h300/usb-h300.c b/firmware/target/coldfire/iriver/h300/usb-h300.c
index d08cc24..d50b7bc 100644
--- a/firmware/target/coldfire/iriver/h300/usb-h300.c
+++ b/firmware/target/coldfire/iriver/h300/usb-h300.c
@@ -21,6 +21,7 @@
 #include "cpu.h"
 #include "system.h"
 #include "kernel.h"
+#include "usb.h"
 
 void usb_init_device(void)
 {
@@ -35,9 +36,9 @@
     or_l(0x03000000, &GPIO_FUNCTION);
 }
 
-bool usb_detect(void)
+int usb_detect(void)
 {
-    return (GPIO1_READ & 0x80)?true:false;
+    return (GPIO1_READ & 0x80) ? USB_INSERTED : USB_EXTRACTED;
 }
 
 void usb_enable(bool on)
diff --git a/firmware/target/sh/archos/fm_v2/usb-fm_v2.c b/firmware/target/sh/archos/fm_v2/usb-fm_v2.c
index 3dcc355..9c641b9 100644
--- a/firmware/target/sh/archos/fm_v2/usb-fm_v2.c
+++ b/firmware/target/sh/archos/fm_v2/usb-fm_v2.c
@@ -22,10 +22,11 @@
 #include "cpu.h"
 #include "hwcompat.h"
 #include "system.h"
+#include "usb.h"
 
-bool usb_detect(void)
+int usb_detect(void)
 {
-    return (adc_read(ADC_USB_POWER) <= 512) ? true : false;
+    return (adc_read(ADC_USB_POWER) <= 512) ? USB_INSERTED : USB_EXTRACTED;
 }
 
 void usb_enable(bool on)
diff --git a/firmware/target/sh/archos/ondio/usb-ondio.c b/firmware/target/sh/archos/ondio/usb-ondio.c
index c856f3a..b370fec 100644
--- a/firmware/target/sh/archos/ondio/usb-ondio.c
+++ b/firmware/target/sh/archos/ondio/usb-ondio.c
@@ -23,10 +23,11 @@
 #include "cpu.h"
 #include "hwcompat.h"
 #include "system.h"
+#include "usb.h"
 
-bool usb_detect(void)
+int usb_detect(void)
 {
-    return (adc_read(ADC_USB_POWER) <= 512) ? true : false;
+    return (adc_read(ADC_USB_POWER) <= 512) ? USB_INSERTED : USB_EXTRACTED;
 }
 
 void usb_enable(bool on)
diff --git a/firmware/target/sh/archos/player/usb-player.c b/firmware/target/sh/archos/player/usb-player.c
index c10e222..e86003f 100644
--- a/firmware/target/sh/archos/player/usb-player.c
+++ b/firmware/target/sh/archos/player/usb-player.c
@@ -20,10 +20,11 @@
 #include <stdbool.h>
 #include "cpu.h"
 #include "system.h"
+#include "usb.h"
 
-bool usb_detect(void)
+int usb_detect(void)
 {
-    return (PADR & 0x8000) ? false : true;
+    return (PADR & 0x8000) ? USB_INSERTED : USB_EXTRACTED;
 }
 
 void usb_enable(bool on)
diff --git a/firmware/target/sh/archos/recorder/usb-recorder.c b/firmware/target/sh/archos/recorder/usb-recorder.c
index 7ed2370..dfa8462 100644
--- a/firmware/target/sh/archos/recorder/usb-recorder.c
+++ b/firmware/target/sh/archos/recorder/usb-recorder.c
@@ -22,10 +22,11 @@
 #include "cpu.h"
 #include "hwcompat.h"
 #include "system.h"
+#include "usb.h"
 
-bool usb_detect(void)
+int usb_detect(void)
 {
-    return (adc_read(ADC_USB_POWER) > 500) ? true : false;
+    return (adc_read(ADC_USB_POWER) > 500) ? USB_INSERTED : USB_EXTRACTED;
 }
 
 void usb_enable(bool on)
diff --git a/firmware/usb.c b/firmware/usb.c
index 9e9cb77..876a5e4 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -51,39 +51,6 @@
 
 #if !defined(SIMULATOR) && !defined(USB_NONE)
 
-/* Messages from usb_tick and thread states */
-#define USB_INSERTED    1
-#define USB_EXTRACTED   2 
-#ifdef HAVE_MMC
-#define USB_REENABLE    3
-#endif
-#ifdef HAVE_USB_POWER
-#define USB_POWERED     4
-
-#if CONFIG_KEYPAD == RECORDER_PAD
-#define USBPOWER_BUTTON BUTTON_F1
-#define USBPOWER_BTN_IGNORE BUTTON_ON
-#elif CONFIG_KEYPAD == ONDIO_PAD
-#define USBPOWER_BUTTON BUTTON_MENU
-#define USBPOWER_BTN_IGNORE BUTTON_OFF
-#elif (CONFIG_KEYPAD == IPOD_4G_PAD)
-#define USBPOWER_BUTTON BUTTON_MENU
-#define USBPOWER_BTN_IGNORE BUTTON_PLAY
-#elif CONFIG_KEYPAD == IRIVER_H300_PAD
-#define USBPOWER_BUTTON BUTTON_REC
-#define USBPOWER_BTN_IGNORE BUTTON_ON
-#elif CONFIG_KEYPAD == GIGABEAT_PAD
-#define USBPOWER_BUTTON BUTTON_MENU
-#define USBPOWER_BTN_IGNORE BUTTON_POWER
-#elif CONFIG_KEYPAD == IRIVER_H10_PAD
-#define USBPOWER_BUTTON BUTTON_NONE
-#define USBPOWER_BTN_IGNORE BUTTON_POWER
-#elif CONFIG_KEYPAD == SANSA_E200_PAD
-#define USBPOWER_BUTTON BUTTON_SELECT
-#define USBPOWER_BTN_IGNORE BUTTON_POWER
-#endif
-#endif /* HAVE_USB_POWER */
-
 #define NUM_POLL_READINGS (HZ/5)
 static int countdown;
 
@@ -100,7 +67,7 @@
 static const char usb_thread_name[] = "usb";
 #endif
 static struct event_queue usb_queue;
-static bool last_usb_status;
+static int last_usb_status;
 static bool usb_monitor_enabled;
 
 
@@ -161,6 +128,11 @@
         queue_wait(&usb_queue, &ev);
         switch(ev.id)
         {
+#ifdef HAVE_USB_POWER
+            case USB_POWERED:
+                usb_state = USB_POWERED;
+                break;
+#endif
             case USB_INSERTED:
 #ifdef HAVE_LCD_BITMAP
                 if(do_screendump_instead_of_usb)
@@ -278,7 +250,7 @@
 #ifndef BOOTLOADER
 static void usb_tick(void)
 {
-    bool current_status;
+    int current_status;
 
     if(usb_monitor_enabled)
     {
@@ -300,10 +272,7 @@
                readings in a row */
             if(countdown == 0)
             {
-                if(current_status)
-                    queue_post(&usb_queue, USB_INSERTED, 0);
-                else
-                    queue_post(&usb_queue, USB_EXTRACTED, 0);
+                queue_post(&usb_queue, current_status, 0);
             }
         }
     }
@@ -463,9 +432,9 @@
 {
 }
 
-bool usb_detect(void)
+int usb_detect(void)
 {
-    return false;
+    return USB_EXTRACTED;
 }
 
 void usb_wait_for_disconnect(struct event_queue *q)