New feature for units that can be powered or charged from USB (Recorder fm/v2, Ondios): USB power mode, based on patch #1110332 by Pieter Bos. This way you can save battery power or even charge the battery (fm/v2) while using your unit near a PC. Hold MODE (Ondio) or F1 (fm/v2) while plugging USB to enter that mode. A tiny USB plug icon will be displayed is the status bar (overridden by the regular power plug icon in case of fm/v2 when the charger is connected).


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6836 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/main.c b/apps/main.c
index 568a7ef..9b9bae5 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -230,6 +230,10 @@
                 usb_screen();
                 mounted = true; /* mounting done @ end of USB mode */
             }
+#ifdef HAVE_USB_POWER
+        if (usb_powered())      /* avoid deadlock */
+            break;
+#endif
     }
 
     if (!mounted)
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index c77050e..a10f2e1 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -58,6 +58,7 @@
 const unsigned char bitmap_icons_7x8[][7] =
 {
     {0x08,0x1c,0x3e,0x3e,0x3e,0x14,0x14}, /* Power plug */
+    {0x1c,0x14,0x3e,0x2a,0x22,0x1c,0x08}, /* USB plug */
     {0x00,0x1c,0x1c,0x3e,0x7f,0x00,0x00}, /* Speaker */
     {0x01,0x1e,0x1c,0x3e,0x7f,0x20,0x40}, /* Speaker mute */
     {0x00,0x7f,0x7f,0x3e,0x1c,0x08,0x00}, /* Play */
@@ -239,7 +240,7 @@
 /*
  * Print battery icon to status bar
  */
-void statusbar_icon_battery(int percent, bool charging)
+void statusbar_icon_battery(int percent)
 {
     int i;
     int fill;
@@ -292,11 +293,6 @@
                    STATUSBAR_Y_POS, "?");
         lcd_setfont(FONT_UI);
     }
-    
-    /* draw power plug if charging */
-    if (charging)
-        lcd_bitmap(bitmap_icons_7x8[Icon_Plug], ICON_PLUG_X_POS,
-                   STATUSBAR_Y_POS, ICON_PLUG_WIDTH, STATUSBAR_HEIGHT, false);
 }
 
 /*
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index 77a310d..b2900a1 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -43,6 +43,7 @@
 
 enum icons_7x8 {
     Icon_Plug,
+    Icon_USBPlug,
     Icon_Speaker,
     Icon_Mute,
     Icon_Play,
@@ -97,7 +98,7 @@
 #define TIME_X_END            STATUSBAR_WIDTH-1
 
 extern void statusbar_wipe(void);
-extern void statusbar_icon_battery(int percent, bool charging);
+extern void statusbar_icon_battery(int percent);
 extern bool statusbar_icon_volume(int percent);
 extern void statusbar_icon_play_state(int state);
 extern void statusbar_icon_play_mode(int mode);
diff --git a/apps/status.c b/apps/status.c
index 8d3d174..2218768 100644
--- a/apps/status.c
+++ b/apps/status.c
@@ -40,13 +40,15 @@
 #if CONFIG_KEYPAD == IRIVER_H100_PAD
 #include "button.h"
 #endif
+#include "usb.h"
 
 static enum playmode ff_mode;
 
 static long switch_tick;
-static int  battery_charge_step = 0;
-static bool plug_state;
 static bool battery_state = true;
+#ifdef HAVE_CHARGING
+static int  battery_charge_step = 0;
+#endif
 
 struct status_info {
     int battlevel;
@@ -63,6 +65,10 @@
 #if CONFIG_LED == LED_VIRTUAL
 	bool led; /* disk LED simulation in the status bar */
 #endif
+#ifdef HAVE_USB_POWER
+    bool usb_power;
+#endif
+
 };
 
 void status_init(void)
@@ -170,6 +176,9 @@
 #if CONFIG_LED == LED_VIRTUAL
     info.led = led_read(HZ/2); /* delay should match polling interval */
 #endif
+#ifdef HAVE_USB_POWER
+    info.usb_power = usb_powered();
+#endif
 
     /* only redraw if forced to, or info has changed */
     if (force_redraw ||
@@ -183,10 +192,10 @@
     /* players always "redraw" */
     {
 #endif
-        
+
+#ifdef HAVE_CHARGING
         if (info.inserted) {
             battery_state = true;
-            plug_state = true;
 #if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200
             /* zero battery run time if charging */
             if (charge_state > 0) {
@@ -212,8 +221,9 @@
                 }
             }
         }
-        else {
-            plug_state=false;
+        else
+#endif /* HAVE_CHARGING */
+        {
             if (info.battery_safe)
                 battery_state = true;
             else {
@@ -228,8 +238,18 @@
 
 #ifdef HAVE_LCD_BITMAP
         if (battery_state)
-            statusbar_icon_battery(info.battlevel, plug_state);
-            
+            statusbar_icon_battery(info.battlevel);
+
+        /* draw power plug if charging */
+        if (info.inserted)
+            lcd_bitmap(bitmap_icons_7x8[Icon_Plug], ICON_PLUG_X_POS,
+                       STATUSBAR_Y_POS, ICON_PLUG_WIDTH, STATUSBAR_HEIGHT, false);
+#ifdef HAVE_USB_POWER
+        else if (info.usb_power)
+            lcd_bitmap(bitmap_icons_7x8[Icon_USBPlug], ICON_PLUG_X_POS,
+                       STATUSBAR_Y_POS, ICON_PLUG_WIDTH, STATUSBAR_HEIGHT, false);
+#endif
+
         info.redraw_volume = statusbar_icon_volume(info.volume);
         statusbar_icon_play_state(current_playmode() + Icon_Play);
         switch (info.repeat) {
diff --git a/docs/CREDITS b/docs/CREDITS
index de98748..93a2533 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -119,3 +119,4 @@
 Pedro Baltazar Vasconcelos
 Ray Lambert
 Dave Wiard
+Pieter Bos
diff --git a/firmware/export/config-fmrecorder.h b/firmware/export/config-fmrecorder.h
index 914ef60..a3f2597 100644
--- a/firmware/export/config-fmrecorder.h
+++ b/firmware/export/config-fmrecorder.h
@@ -76,6 +76,9 @@
 /* Define this for LCD backlight available */
 #define CONFIG_BACKLIGHT BL_RTC /* on I2C controlled RTC port */
 
+/* define this if the unit can be powered or charged via USB */
+#define HAVE_USB_POWER
+
 #define CONFIG_LCD LCD_SSD1815
 
 #define BOOTFILE_EXT ".ajz"
diff --git a/firmware/export/config-ondiofm.h b/firmware/export/config-ondiofm.h
index b052832..9436b86 100644
--- a/firmware/export/config-ondiofm.h
+++ b/firmware/export/config-ondiofm.h
@@ -90,6 +90,9 @@
 
 #define CONFIG_LCD LCD_SSD1815
 
+/* define this if the unit can be powered or charged via USB */
+#define HAVE_USB_POWER
+
 #define BOOTFILE_EXT ".ajz"
 #define BOOTFILE "ajbrec" BOOTFILE_EXT
 
diff --git a/firmware/export/config-ondiosp.h b/firmware/export/config-ondiosp.h
index 6c800b3..fd79d19 100644
--- a/firmware/export/config-ondiosp.h
+++ b/firmware/export/config-ondiosp.h
@@ -78,6 +78,9 @@
 
 #define CONFIG_LCD LCD_SSD1815
 
+/* define this if the unit can be powered or charged via USB */
+#define HAVE_USB_POWER
+
 #define BOOTFILE_EXT ".ajz"
 #define BOOTFILE "ajbrec" BOOTFILE_EXT
 
diff --git a/firmware/export/config-recorderv2.h b/firmware/export/config-recorderv2.h
index 450222d..c75f0e6 100644
--- a/firmware/export/config-recorderv2.h
+++ b/firmware/export/config-recorderv2.h
@@ -76,6 +76,9 @@
 /* Define this for LCD backlight available */
 #define CONFIG_BACKLIGHT BL_RTC /* on I2C controlled RTC port */
 
+/* define this if the unit can be powered or charged via USB */
+#define HAVE_USB_POWER
+
 #define CONFIG_LCD LCD_SSD1815
 
 #define BOOTFILE_EXT ".ajz"
diff --git a/firmware/export/usb.h b/firmware/export/usb.h
index fc96c67..e8602e7 100644
--- a/firmware/export/usb.h
+++ b/firmware/export/usb.h
@@ -28,5 +28,8 @@
 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 */
+#ifdef HAVE_USB_POWER
+bool usb_powered(void);
+#endif
 
 #endif
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index bb2e675..3eab413 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -437,7 +437,12 @@
     current = CURRENT_NORMAL;
 #endif /* MEM == 8 */
 
-    if(usb_inserted()) {
+    if(usb_inserted()
+#ifdef HAVE_USB_POWER
+       || usb_powered()
+#endif
+    )
+    {
         current = CURRENT_USB;
     }
 
diff --git a/firmware/usb.c b/firmware/usb.c
index a514f8f..866ca53 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -47,18 +47,21 @@
 
 #if !defined(SIMULATOR) && !defined(USB_NONE)
 
-/* Messages from usb_tick */
+/* 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
 
-/* Thread states */
-#define EXTRACTING      1
-#define EXTRACTED       2
-#define INSERTED        3
-#define INSERTING       4
+#if CONFIG_KEYPAD == RECORDER_PAD
+#define USBPOWER_BUTTON BUTTON_F1
+#elif CONFIG_KEYPAD == ONDIO_PAD
+#define USBPOWER_BUTTON BUTTON_MENU
+#endif
+#endif /* HAVE_USB_POWER */
 
 /* The ADC tick reads one channel per tick, and we want to check 3 successive
    readings on the USB voltage channel. This doesn't apply to the Player, but
@@ -221,8 +224,15 @@
                     screen_dump();
                 }
                 else
-                {
 #endif
+#ifdef HAVE_USB_POWER
+                if(button_status() == USBPOWER_BUTTON)
+                {
+                    usb_state = USB_POWERED;
+                }
+                else
+#endif
+                {
                     /* Tell all threads that they have to back off the ATA.
                        We subtract one for our own thread. */
                     num_acks_to_expect =
@@ -230,11 +240,9 @@
                     waiting_for_ack = true;
                     DEBUGF("USB inserted. Waiting for ack from %d threads...\n",
                            num_acks_to_expect);
-#ifdef HAVE_LCD_BITMAP
                 }
-#endif
                 break;
-       
+
             case SYS_USB_CONNECTED_ACK:
                 if(waiting_for_ack)
                 {
@@ -259,33 +267,37 @@
 
             case USB_EXTRACTED:
 #ifdef HAVE_LCD_BITMAP
-                if(!do_screendump_instead_of_usb)
+                if(do_screendump_instead_of_usb)
+                    break;
+#endif
+#ifdef HAVE_USB_POWER
+                if(usb_state == USB_POWERED)
                 {
-#endif
-                    if(usb_state == USB_INSERTED)
-                    {
-                        /* Only disable the USB mode if we really have enabled it
-                           some threads might not have acknowledged the
-                           insertion */
-                        usb_slave_mode(false);
-                    }
-
                     usb_state = USB_EXTRACTED;
-                    
-                    /* Tell all threads that we are back in business */
-                    num_acks_to_expect =
-                        queue_broadcast(SYS_USB_DISCONNECTED, NULL) - 1;
-                    waiting_for_ack = true;
-                    DEBUGF("USB extracted. Waiting for ack from %d threads...\n",
-                           num_acks_to_expect);
-#ifdef HAVE_LCD_CHARCELLS
-                    lcd_icon(ICON_USB, false);
-#endif
-#ifdef HAVE_LCD_BITMAP
+                    break;
                 }
 #endif
+                if(usb_state == USB_INSERTED)
+                {
+                    /* Only disable the USB mode if we really have enabled it
+                       some threads might not have acknowledged the
+                       insertion */
+                    usb_slave_mode(false);
+                }
+
+                usb_state = USB_EXTRACTED;
+
+                /* Tell all threads that we are back in business */
+                num_acks_to_expect =
+                    queue_broadcast(SYS_USB_DISCONNECTED, NULL) - 1;
+                waiting_for_ack = true;
+                DEBUGF("USB extracted. Waiting for ack from %d threads...\n",
+                       num_acks_to_expect);
+#ifdef HAVE_LCD_CHARCELLS
+                lcd_icon(ICON_USB, false);
+#endif
                 break;
-        
+
             case SYS_USB_DISCONNECTED_ACK:
                 if(waiting_for_ack)
                 {
@@ -475,6 +487,13 @@
     return usb_state == USB_INSERTED;
 }
 
+#ifdef HAVE_USB_POWER
+bool usb_powered(void)
+{
+    return usb_state == USB_POWERED;
+}
+#endif
+
 #else
 
 #ifdef USB_NONE