diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 631f027..7ad69dc 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -401,361 +401,6 @@ static bool dbg_buffering_thread(void)
 #endif /* CONFIG_CODEC */
 #endif /* HAVE_LCD_BITMAP */
 
-
-#if (CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE))
-/* Tool function to read the flash manufacturer and type, if available.
-   Only chips which could be reprogrammed in system will return values.
-   (The mode switch addresses vary between flash manufacturers, hence addr1/2) */
-   /* In IRAM to avoid problems when running directly from Flash */
-static bool dbg_flash_id(unsigned* p_manufacturer, unsigned* p_device,
-                         unsigned addr1, unsigned addr2)
-                         ICODE_ATTR __attribute__((noinline));
-static bool dbg_flash_id(unsigned* p_manufacturer, unsigned* p_device,
-                         unsigned addr1, unsigned addr2)
-
-{
-    unsigned not_manu, not_id; /* read values before switching to ID mode */
-    unsigned manu, id; /* read values when in ID mode */
-
-#if CONFIG_CPU == SH7034
-    volatile unsigned char* flash = (unsigned char*)0x2000000; /* flash mapping */
-#elif defined(CPU_COLDFIRE)
-    volatile unsigned short* flash = (unsigned short*)0; /* flash mapping */
-#endif
-    int old_level; /* saved interrupt level */
-
-    not_manu = flash[0]; /* read the normal content */
-    not_id   = flash[1]; /* should be 'A' (0x41) and 'R' (0x52) from the "ARCH" marker */
-
-    /* disable interrupts, prevent any stray flash access */
-    old_level = disable_irq_save();
-
-    flash[addr1] = 0xAA; /* enter command mode */
-    flash[addr2] = 0x55;
-    flash[addr1] = 0x90; /* ID command */
-    /* Atmel wants 20ms pause here */
-    /* sleep(HZ/50); no sleeping possible while interrupts are disabled */
-
-    manu = flash[0]; /* read the IDs */
-    id   = flash[1];
-
-    flash[0] = 0xF0; /* reset flash (back to normal read mode) */
-    /* Atmel wants 20ms pause here */
-    /* sleep(HZ/50); no sleeping possible while interrupts are disabled */
-
-    restore_irq(old_level); /* enable interrupts again */
-
-    /* I assume success if the obtained values are different from
-        the normal flash content. This is not perfectly bulletproof, they
-        could theoretically be the same by chance, causing us to fail. */
-    if (not_manu != manu || not_id != id) /* a value has changed */
-    {
-        *p_manufacturer = manu; /* return the results */
-        *p_device = id;
-        return true; /* success */
-    }
-    return false; /* fail */
-}
-#endif /* (CONFIG_CPU == SH7034 || CPU_COLDFIRE) */
-
-#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
-#ifdef CPU_PP
-static int perfcheck(void)
-{
-    int result;
-
-    asm (
-        "mrs     r2, CPSR            \n"
-        "orr     r0, r2, #0xc0       \n" /* disable IRQ and FIQ */
-        "msr     CPSR_c, r0          \n"
-        "mov     %[res], #0          \n"
-        "ldr     r0, [%[timr]]       \n"
-        "add     r0, r0, %[tmo]      \n"
-    "1:                              \n"
-        "add     %[res], %[res], #1  \n"
-        "ldr     r1, [%[timr]]       \n"
-        "cmp     r1, r0              \n"
-        "bmi     1b                  \n"
-        "msr     CPSR_c, r2          \n" /* reset IRQ and FIQ state */
-        :
-        [res]"=&r"(result)
-        :
-        [timr]"r"(&USEC_TIMER),
-        [tmo]"r"(
-#if CONFIG_CPU == PP5002
-        16000
-#else /* PP5020/5022/5024 */
-        10226
-#endif
-        )
-        :
-        "r0", "r1", "r2"
-    );
-    return result;
-}
-#endif
-
-#ifdef HAVE_LCD_BITMAP
-static bool dbg_hw_info(void)
-{
-#if CONFIG_CPU == SH7034
-    int bitmask = HW_MASK;
-    int rom_version = ROM_VERSION;
-    unsigned manu, id; /* flash IDs */
-    bool got_id; /* flag if we managed to get the flash IDs */
-    unsigned rom_crc = 0xffffffff; /* CRC32 of the boot ROM */
-    bool has_bootrom; /* flag for boot ROM present */
-    int oldmode;  /* saved memory guard mode */
-
-    oldmode = system_memory_guard(MEMGUARD_NONE);  /* disable memory guard */
-
-    /* get flash ROM type */
-    got_id = dbg_flash_id(&manu, &id, 0x5555, 0x2AAA); /* try SST, Atmel, NexFlash */
-    if (!got_id)
-        got_id = dbg_flash_id(&manu, &id, 0x555, 0x2AA); /* try AMD, Macronix */
-
-    /* check if the boot ROM area is a flash mirror */
-    has_bootrom = (memcmp((char*)0, (char*)0x02000000, 64*1024) != 0);
-    if (has_bootrom)  /* if ROM and Flash different */
-    {
-        /* calculate CRC16 checksum of boot ROM */
-        rom_crc = crc_32((unsigned char*)0x0000, 64*1024, 0xffffffff);
-    }
-
-    system_memory_guard(oldmode);  /* re-enable memory guard */
-
-    lcd_setfont(FONT_SYSFIXED);
-    lcd_clear_display();
-
-    lcd_puts(0, 0, "[Hardware info]");
-
-    lcd_putsf(0, 1, "ROM: %d.%02d", rom_version/100, rom_version%100);
-
-    lcd_putsf(0, 2, "Mask: 0x%04x", bitmask);
-
-    if (got_id)
-        lcd_putsf(0, 3, "Flash: M=%02x D=%02x", manu, id);
-    else
-        lcd_puts(0, 3, "Flash: M=?? D=??"); /* unknown, sorry */
-
-    if (has_bootrom)
-    {
-        if (rom_crc == 0x56DBA4EE) /* known Version 1 */
-            lcd_puts(0, 4, "Boot ROM: V1");
-        else
-            lcd_putsf(0, 4, "ROMcrc: 0x%08x", rom_crc);
-    }
-    else
-    {
-        lcd_puts(0, 4, "Boot ROM: none");
-    }
-
-    lcd_update();
-
-    while (!(action_userabort(TIMEOUT_BLOCK)));
-
-#elif CONFIG_CPU == MCF5249 || CONFIG_CPU == MCF5250
-    unsigned manu, id; /* flash IDs */
-    int got_id; /* flag if we managed to get the flash IDs */
-    int oldmode;  /* saved memory guard mode */
-    int line = 0;
-
-    oldmode = system_memory_guard(MEMGUARD_NONE);  /* disable memory guard */
-
-    /* get flash ROM type */
-    got_id = dbg_flash_id(&manu, &id, 0x5555, 0x2AAA); /* try SST, Atmel, NexFlash */
-    if (!got_id)
-        got_id = dbg_flash_id(&manu, &id, 0x555, 0x2AA); /* try AMD, Macronix */
-
-    system_memory_guard(oldmode);  /* re-enable memory guard */
-
-    lcd_setfont(FONT_SYSFIXED);
-    lcd_clear_display();
-
-    lcd_puts(0, line++, "[Hardware info]");
-
-    if (got_id)
-        lcd_putsf(0, line++, "Flash: M=%04x D=%04x", manu, id);
-    else
-        lcd_puts(0, line++, "Flash: M=???? D=????"); /* unknown, sorry */
-
-#ifdef IAUDIO_X5
-    {
-        struct ds2411_id id;
-
-        lcd_puts(0, ++line, "Serial Number:");
-
-        got_id = ds2411_read_id(&id);
-
-        if (got_id == DS2411_OK)
-        {
-            lcd_putsf(0, ++line, "  FC=%02x", (unsigned)id.family_code);
-            lcd_putsf(0, ++line, "  ID=%02X %02X %02X %02X %02X %02X",
-                (unsigned)id.uid[0], (unsigned)id.uid[1], (unsigned)id.uid[2],
-                (unsigned)id.uid[3], (unsigned)id.uid[4], (unsigned)id.uid[5]);
-            lcd_putsf(0, ++line, "  CRC=%02X", (unsigned)id.crc);
-        }
-        else
-        {
-            lcd_putsf(0, ++line, "READ ERR=%d", got_id);
-        }
-    }
-#endif
-
-    lcd_update();
-
-    while (!(action_userabort(TIMEOUT_BLOCK)));
-
-#elif defined(CPU_PP502x)
-    int line = 0;
-    char pp_version[] = { (PP_VER2 >> 24) & 0xff, (PP_VER2 >> 16) & 0xff,
-                          (PP_VER2 >> 8) & 0xff, (PP_VER2) & 0xff,
-                          (PP_VER1 >> 24) & 0xff, (PP_VER1 >> 16) & 0xff,
-                          (PP_VER1 >> 8) & 0xff, (PP_VER1) & 0xff, '\0' };
-
-    lcd_setfont(FONT_SYSFIXED);
-    lcd_clear_display();
-
-    lcd_puts(0, line++, "[Hardware info]");
-
-#ifdef IPOD_ARCH
-    lcd_putsf(0, line++, "HW rev: 0x%08lx", IPOD_HW_REVISION);
-#endif
-
-#ifdef IPOD_COLOR
-    extern int lcd_type; /* Defined in lcd-colornano.c */
-
-    lcd_putsf(0, line++, "LCD type: %d", lcd_type);
-#endif
-
-    lcd_putsf(0, line++, "PP version: %s", pp_version);
-
-    lcd_putsf(0, line++, "Est. clock (kHz): %d", perfcheck());
-
-    lcd_update();
-
-    while (!(action_userabort(TIMEOUT_BLOCK)));
-
-#elif CONFIG_CPU == PP5002
-    int line = 0;
-    char pp_version[] = { (PP_VER4 >> 8) & 0xff, PP_VER4 & 0xff,
-                          (PP_VER3 >> 8) & 0xff, PP_VER3 & 0xff,
-                          (PP_VER2 >> 8) & 0xff, PP_VER2 & 0xff,
-                          (PP_VER1 >> 8) & 0xff, PP_VER1 & 0xff, '\0' };
-
-
-    lcd_setfont(FONT_SYSFIXED);
-    lcd_clear_display();
-
-    lcd_puts(0, line++, "[Hardware info]");
-
-#ifdef IPOD_ARCH
-    lcd_putsf(0, line++, "HW rev: 0x%08lx", IPOD_HW_REVISION);
-#endif
-
-    lcd_putsf(0, line++, "PP version: %s", pp_version);
-
-    lcd_putsf(0, line++, "Est. clock (kHz): %d", perfcheck());
-
-    lcd_update();
-
-    while (!(action_userabort(TIMEOUT_BLOCK)));
-    
-#else
-    /* Define this function in your target tree */
-    return __dbg_hw_info();
-#endif /* CONFIG_CPU */
-    lcd_setfont(FONT_UI);
-    return false;
-}
-#else /* !HAVE_LCD_BITMAP */
-static bool dbg_hw_info(void)
-{
-    int button;
-    int currval = 0;
-    int rom_version = ROM_VERSION;
-    unsigned manu, id; /* flash IDs */
-    bool got_id; /* flag if we managed to get the flash IDs */
-    unsigned rom_crc = 0xffffffff; /* CRC32 of the boot ROM */
-    bool has_bootrom; /* flag for boot ROM present */
-    int oldmode;  /* saved memory guard mode */
-
-    oldmode = system_memory_guard(MEMGUARD_NONE);  /* disable memory guard */
-
-    /* get flash ROM type */
-    got_id = dbg_flash_id(&manu, &id, 0x5555, 0x2AAA); /* try SST, Atmel, NexFlash */
-    if (!got_id)
-        got_id = dbg_flash_id(&manu, &id, 0x555, 0x2AA); /* try AMD, Macronix */
-
-    /* check if the boot ROM area is a flash mirror */
-    has_bootrom = (memcmp((char*)0, (char*)0x02000000, 64*1024) != 0);
-    if (has_bootrom)  /* if ROM and Flash different */
-    {
-        /* calculate CRC16 checksum of boot ROM */
-        rom_crc = crc_32((unsigned char*)0x0000, 64*1024, 0xffffffff);
-    }
-
-    system_memory_guard(oldmode);  /* re-enable memory guard */
-
-    lcd_clear_display();
-
-    lcd_puts(0, 0, "[HW Info]");
-    while(1)
-    {
-        switch(currval)
-        {
-            case 0:
-                lcd_putsf(0, 1, "ROM: %d.%02d",
-                         rom_version/100, rom_version%100);
-                break;
-            case 1:
-                if (got_id)
-                    lcd_putsf(0, 1, "Flash:%02x,%02x", manu, id);
-                else
-                    lcd_puts(0, 1, "Flash:??,??"); /* unknown, sorry */
-                break;
-            case 2:
-                if (has_bootrom)
-                {
-                    if (rom_crc == 0x56DBA4EE) /* known Version 1 */
-                        lcd_puts(0, 1, "BootROM: V1");
-                    else if (rom_crc == 0x358099E8)
-                        lcd_puts(0, 1, "BootROM: V2");
-                        /* alternative boot ROM found in one single player so far */
-                    else
-                        lcd_putsf(0, 1, "R: %08x", rom_crc);
-                }
-                else
-                    lcd_puts(0, 1, "BootROM: no");
-        }
-
-        lcd_update();
-
-        button = get_action(CONTEXT_SETTINGS,TIMEOUT_BLOCK);
-
-        switch(button)
-        {
-            case ACTION_STD_CANCEL:
-                return false;
-
-            case ACTION_SETTINGS_DEC:
-                currval--;
-                if(currval < 0)
-                    currval = 2;
-                break;
-
-            case ACTION_SETTINGS_INC:
-                currval++;
-                if(currval > 2)
-                    currval = 0;
-                break;
-        }
-    }
-    return false;
-}
-#endif /* !HAVE_LCD_BITMAP */
-#endif /* PLATFORM_NATIVE */
-
 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
 static const char* dbg_partitions_getname(int selected_item, void *data,
                                           char *buffer, size_t buffer_len)
diff --git a/firmware/target/arm/as3525/debug-as3525.c b/firmware/target/arm/as3525/debug-as3525.c
index 513295e..d18f2d7 100644
--- a/firmware/target/arm/as3525/debug-as3525.c
+++ b/firmware/target/arm/as3525/debug-as3525.c
@@ -248,7 +248,7 @@ static int calc_freq(int clk)
         }
 }
 
-bool __dbg_hw_info(void)
+bool dbg_hw_info(void)
 {
     int line;
 #if CONFIG_CPU == AS3525
diff --git a/firmware/target/arm/as3525/debug-target.h b/firmware/target/arm/as3525/debug-target.h
index a9e4355..1359e6a 100644
--- a/firmware/target/arm/as3525/debug-target.h
+++ b/firmware/target/arm/as3525/debug-target.h
@@ -24,6 +24,6 @@
 #include <stdbool.h>
 
 #define DEBUG_CANCEL BUTTON_LEFT
-bool __dbg_hw_info(void);
+bool dbg_hw_info(void);
 bool dbg_ports(void);
 #endif
diff --git a/firmware/target/arm/at91sam/lyre_proto1/debug-lyre_proto1.c b/firmware/target/arm/at91sam/lyre_proto1/debug-lyre_proto1.c
index 54a262a..5277afc 100644
--- a/firmware/target/arm/at91sam/lyre_proto1/debug-lyre_proto1.c
+++ b/firmware/target/arm/at91sam/lyre_proto1/debug-lyre_proto1.c
@@ -23,12 +23,12 @@
 #include <stdbool.h>
 #include "debug-target.h"
 
-bool __dbg_ports(void)
+bool dbg_ports(void)
 {
     return false;
 }
 
-bool __dbg_hw_info(void)
+bool dbg_hw_info(void)
 {
     return false;
 }
diff --git a/firmware/target/arm/at91sam/lyre_proto1/debug-target.h b/firmware/target/arm/at91sam/lyre_proto1/debug-target.h
index 140feaf..59dd58c 100644
--- a/firmware/target/arm/at91sam/lyre_proto1/debug-target.h
+++ b/firmware/target/arm/at91sam/lyre_proto1/debug-target.h
@@ -21,6 +21,6 @@
 
 #include <stdbool.h>
 
-bool __dbg_ports(void);
-bool __dbg_hw_info(void);
+bool dbg_ports(void);
+bool dbg_hw_info(void);
 
diff --git a/firmware/target/arm/debug-pp.c b/firmware/target/arm/debug-pp.c
index 3b9250c..080e0ed 100644
--- a/firmware/target/arm/debug-pp.c
+++ b/firmware/target/arm/debug-pp.c
@@ -28,8 +28,43 @@
 #include "powermgmt.h"
 #include "adc.h"
 #include "iap.h"
+#include "hwcompat.h"
 #include "debug-target.h"
 
+static int perfcheck(void)
+{
+    int result;
+
+    asm (
+        "mrs     r2, CPSR            \n"
+        "orr     r0, r2, #0xc0       \n" /* disable IRQ and FIQ */
+        "msr     CPSR_c, r0          \n"
+        "mov     %[res], #0          \n"
+        "ldr     r0, [%[timr]]       \n"
+        "add     r0, r0, %[tmo]      \n"
+    "1:                              \n"
+        "add     %[res], %[res], #1  \n"
+        "ldr     r1, [%[timr]]       \n"
+        "cmp     r1, r0              \n"
+        "bmi     1b                  \n"
+        "msr     CPSR_c, r2          \n" /* reset IRQ and FIQ state */
+        :
+        [res]"=&r"(result)
+        :
+        [timr]"r"(&USEC_TIMER),
+        [tmo]"r"(
+#if CONFIG_CPU == PP5002
+        16000
+#else /* PP5020/5022/5024 */
+        10226
+#endif
+        )
+        :
+        "r0", "r1", "r2"
+    );
+    return result;
+}
+
 bool dbg_ports(void)
 {
     int line;
@@ -152,3 +187,46 @@ bool dbg_ports(void)
     }
     return false;
 }
+
+bool dbg_hw_info(void)
+{
+    int line = 0;
+#if defined(CPU_PP502x)
+    char pp_version[] = { (PP_VER2 >> 24) & 0xff, (PP_VER2 >> 16) & 0xff,
+                          (PP_VER2 >> 8) & 0xff, (PP_VER2) & 0xff,
+                          (PP_VER1 >> 24) & 0xff, (PP_VER1 >> 16) & 0xff,
+                          (PP_VER1 >> 8) & 0xff, (PP_VER1) & 0xff, '\0' };
+#elif CONFIG_CPU == PP5002
+    char pp_version[] = { (PP_VER4 >> 8) & 0xff, PP_VER4 & 0xff,
+                          (PP_VER3 >> 8) & 0xff, PP_VER3 & 0xff,
+                          (PP_VER2 >> 8) & 0xff, PP_VER2 & 0xff,
+                          (PP_VER1 >> 8) & 0xff, PP_VER1 & 0xff, '\0' };
+#endif
+
+    lcd_setfont(FONT_SYSFIXED);
+    lcd_clear_display();
+
+    lcd_puts(0, line++, "[Hardware info]");
+
+#ifdef IPOD_ARCH
+    lcd_putsf(0, line++, "HW rev: 0x%08lx", IPOD_HW_REVISION);
+#endif
+
+#ifdef IPOD_COLOR
+    extern int lcd_type; /* Defined in lcd-colornano.c */
+
+    lcd_putsf(0, line++, "LCD type: %d", lcd_type);
+#endif
+
+    lcd_putsf(0, line++, "PP version: %s", pp_version);
+
+    lcd_putsf(0, line++, "Est. clock (kHz): %d", perfcheck());
+
+    lcd_update();
+
+    /* wait for exit */
+    while (button_get_w_tmo(HZ/10) != (DEBUG_CANCEL|BUTTON_REL));
+
+    lcd_setfont(FONT_UI);
+    return false;
+}
diff --git a/firmware/target/arm/debug-target.h b/firmware/target/arm/debug-target.h
index 4408acf..28f9532 100644
--- a/firmware/target/arm/debug-target.h
+++ b/firmware/target/arm/debug-target.h
@@ -47,3 +47,4 @@
 #   define DEBUG_CANCEL  BUTTON_CANCEL
 #endif
 bool dbg_ports(void);
+bool dbg_hw_info(void);
diff --git a/firmware/target/arm/imx31/debug-imx31.c b/firmware/target/arm/imx31/debug-imx31.c
index 1239c7c..9b080ff 100644
--- a/firmware/target/arm/imx31/debug-imx31.c
+++ b/firmware/target/arm/imx31/debug-imx31.c
@@ -30,7 +30,7 @@
 #include "ccm-imx31.h"
 #include "dvfs_dptc-imx31.h"
 
-bool __dbg_hw_info(void)
+bool dbg_hw_info(void)
 {
     int line;
     unsigned int pllref;
diff --git a/firmware/target/arm/imx31/debug-target.h b/firmware/target/arm/imx31/debug-target.h
index 06baee5..da80b27 100644
--- a/firmware/target/arm/imx31/debug-target.h
+++ b/firmware/target/arm/imx31/debug-target.h
@@ -22,7 +22,7 @@
 #define DEBUG_TARGET_H
 
 #define DEBUG_CANCEL  BUTTON_BACK
-bool __dbg_hw_info(void);
+bool dbg_hw_info(void);
 bool dbg_ports(void);
 
 #endif /* DEBUG_TARGET_H */
diff --git a/firmware/target/arm/s3c2440/debug-s3c2440.c b/firmware/target/arm/s3c2440/debug-s3c2440.c
index e552f12..99ab8e4 100644
--- a/firmware/target/arm/s3c2440/debug-s3c2440.c
+++ b/firmware/target/arm/s3c2440/debug-s3c2440.c
@@ -29,7 +29,7 @@
 #include "font.h"
 #include "debug-target.h"
 
-bool __dbg_hw_info(void)
+bool dbg_hw_info(void)
 {
     return false;
 }
diff --git a/firmware/target/arm/s3c2440/debug-target.h b/firmware/target/arm/s3c2440/debug-target.h
index dc274b9..9e83da6 100644
--- a/firmware/target/arm/s3c2440/debug-target.h
+++ b/firmware/target/arm/s3c2440/debug-target.h
@@ -25,6 +25,6 @@
 #define DEBUG_CANCEL  BUTTON_MENU
 #endif
 
-bool __dbg_hw_info(void);
+bool dbg_hw_info(void);
 bool dbg_ports(void);
 
diff --git a/firmware/target/arm/s5l8700/debug-s5l8700.c b/firmware/target/arm/s5l8700/debug-s5l8700.c
index 1f8dbeb..480d0f0 100644
--- a/firmware/target/arm/s5l8700/debug-s5l8700.c
+++ b/firmware/target/arm/s5l8700/debug-s5l8700.c
@@ -41,7 +41,7 @@
 extern int lcd_type;
 extern uint32_t nand_type[4];
 
-bool __dbg_hw_info(void)
+bool dbg_hw_info(void)
 {
     int line;
     int i;
@@ -127,7 +127,7 @@ bool __dbg_hw_info(void)
         }
 
 #else
-        _DEBUG_PRINTF("__dbg_hw_info");
+        _DEBUG_PRINTF("dbg_hw_info");
 #endif
 
         lcd_update(); 
diff --git a/firmware/target/arm/s5l8700/debug-target.h b/firmware/target/arm/s5l8700/debug-target.h
index 351468f..95f2f94 100644
--- a/firmware/target/arm/s5l8700/debug-target.h
+++ b/firmware/target/arm/s5l8700/debug-target.h
@@ -26,7 +26,7 @@
 
 #define DEBUG_CANCEL BUTTON_MENU
 
-bool __dbg_hw_info(void);
+bool dbg_hw_info(void);
 bool dbg_ports(void);
 
 #endif /* _DEBUG_TARGET_H_ */
diff --git a/firmware/target/arm/tcc77x/debug-target.h b/firmware/target/arm/tcc77x/debug-target.h
index 6cf93cc..c985751 100644
--- a/firmware/target/arm/tcc77x/debug-target.h
+++ b/firmware/target/arm/tcc77x/debug-target.h
@@ -19,6 +19,6 @@
  *
  ****************************************************************************/
 
-bool __dbg_hw_info(void);
+bool dbg_hw_info(void);
 bool dbg_ports(void);
 
diff --git a/firmware/target/arm/tcc77x/debug-tcc77x.c b/firmware/target/arm/tcc77x/debug-tcc77x.c
index 88b0722..250afb4 100644
--- a/firmware/target/arm/tcc77x/debug-tcc77x.c
+++ b/firmware/target/arm/tcc77x/debug-tcc77x.c
@@ -36,7 +36,7 @@ bool dbg_ports(void)
     return false;
 }
 
-bool __dbg_hw_info(void)
+bool dbg_hw_info(void)
 {
     int line = 0, i, button, oldline;
     bool done=false;
diff --git a/firmware/target/arm/tcc780x/debug-target.h b/firmware/target/arm/tcc780x/debug-target.h
index 6cf93cc..c985751 100644
--- a/firmware/target/arm/tcc780x/debug-target.h
+++ b/firmware/target/arm/tcc780x/debug-target.h
@@ -19,6 +19,6 @@
  *
  ****************************************************************************/
 
-bool __dbg_hw_info(void);
+bool dbg_hw_info(void);
 bool dbg_ports(void);
 
diff --git a/firmware/target/arm/tcc780x/debug-tcc780x.c b/firmware/target/arm/tcc780x/debug-tcc780x.c
index d527e2b..22de868 100644
--- a/firmware/target/arm/tcc780x/debug-tcc780x.c
+++ b/firmware/target/arm/tcc780x/debug-tcc780x.c
@@ -40,7 +40,7 @@ bool dbg_ports(void)
     return false;
 }
 
-bool __dbg_hw_info(void)
+bool dbg_hw_info(void)
 {
     int line = 0, i, oldline;
 
diff --git a/firmware/target/arm/tms320dm320/debug-dm320.c b/firmware/target/arm/tms320dm320/debug-dm320.c
index 26f34a4..de17d54 100644
--- a/firmware/target/arm/tms320dm320/debug-dm320.c
+++ b/firmware/target/arm/tms320dm320/debug-dm320.c
@@ -121,7 +121,7 @@ bool dbg_ports(void)
     return false;
 }
 
-bool __dbg_hw_info(void)
+bool dbg_hw_info(void)
 {
     int line = 0, oldline;
     int button;
diff --git a/firmware/target/arm/tms320dm320/debug-target.h b/firmware/target/arm/tms320dm320/debug-target.h
index bcf9d68..5fc0c98 100644
--- a/firmware/target/arm/tms320dm320/debug-target.h
+++ b/firmware/target/arm/tms320dm320/debug-target.h
@@ -19,5 +19,5 @@
  *
  ****************************************************************************/
  
-bool __dbg_hw_info(void);
+bool dbg_hw_info(void);
 bool dbg_ports(void);
diff --git a/firmware/target/coldfire/debug-coldfire.c b/firmware/target/coldfire/debug-coldfire.c
index 14221d6..b021cd1 100644
--- a/firmware/target/coldfire/debug-coldfire.c
+++ b/firmware/target/coldfire/debug-coldfire.c
@@ -29,6 +29,58 @@
 #include "adc.h"
 #include "debug-target.h"
 #include "lcd-remote.h"
+#ifdef IAUDIO_X5
+#include "ds2411.h"
+#endif
+
+/* Tool function to read the flash manufacturer and type, if available.
+   Only chips which could be reprogrammed in system will return values.
+   (The mode switch addresses vary between flash manufacturers, hence addr1/2) */
+   /* In IRAM to avoid problems when running directly from Flash */
+static bool dbg_flash_id(unsigned* p_manufacturer, unsigned* p_device,
+                         unsigned addr1, unsigned addr2)
+                         ICODE_ATTR __attribute__((noinline));
+static bool dbg_flash_id(unsigned* p_manufacturer, unsigned* p_device,
+                         unsigned addr1, unsigned addr2)
+
+{
+    unsigned not_manu, not_id; /* read values before switching to ID mode */
+    unsigned manu, id; /* read values when in ID mode */
+
+    volatile unsigned short* flash = (unsigned short*)0; /* flash mapping */
+    int old_level; /* saved interrupt level */
+
+    not_manu = flash[0]; /* read the normal content */
+    not_id   = flash[1]; /* should be 'A' (0x41) and 'R' (0x52) from the "ARCH" marker */
+
+    /* disable interrupts, prevent any stray flash access */
+    old_level = disable_irq_save();
+
+    flash[addr1] = 0xAA; /* enter command mode */
+    flash[addr2] = 0x55;
+    flash[addr1] = 0x90; /* ID command */
+    /* Atmel wants 20ms pause here */
+    /* sleep(HZ/50); no sleeping possible while interrupts are disabled */
+    manu = flash[0]; /* read the IDs */
+    id   = flash[1];
+
+    flash[0] = 0xF0; /* reset flash (back to normal read mode) */
+    /* Atmel wants 20ms pause here */
+    /* sleep(HZ/50); no sleeping possible while interrupts are disabled */
+
+    restore_irq(old_level); /* enable interrupts again */
+
+    /* I assume success if the obtained values are different from
+        the normal flash content. This is not perfectly bulletproof, they
+        could theoretically be the same by chance, causing us to fail. */
+    if (not_manu != manu || not_id != id) /* a value has changed */
+    {
+        *p_manufacturer = manu; /* return the results */
+        *p_device = id;
+        return true; /* success */
+    }
+    return false; /* fail */
+}
 
 bool dbg_ports(void)
 {
@@ -105,3 +157,59 @@ bool dbg_ports(void)
     }
     return false;
 }
+
+bool dbg_hw_info(void)
+{
+    unsigned manu, id; /* flash IDs */
+    int got_id; /* flag if we managed to get the flash IDs */
+    int oldmode;  /* saved memory guard mode */
+    int line = 0;
+
+    oldmode = system_memory_guard(MEMGUARD_NONE);  /* disable memory guard */
+
+    /* get flash ROM type */
+    got_id = dbg_flash_id(&manu, &id, 0x5555, 0x2AAA); /* try SST, Atmel, NexFlash */
+    if (!got_id)
+        got_id = dbg_flash_id(&manu, &id, 0x555, 0x2AA); /* try AMD, Macronix */
+
+    system_memory_guard(oldmode);  /* re-enable memory guard */
+
+    lcd_setfont(FONT_SYSFIXED);
+    lcd_clear_display();
+
+    lcd_puts(0, line++, "[Hardware info]");
+
+    if (got_id)
+        lcd_putsf(0, line++, "Flash: M=%04x D=%04x", manu, id);
+    else
+        lcd_puts(0, line++, "Flash: M=???? D=????"); /* unknown, sorry */
+
+#ifdef IAUDIO_X5
+    {
+        struct ds2411_id id;
+
+        lcd_puts(0, ++line, "Serial Number:");
+
+        got_id = ds2411_read_id(&id);
+
+        if (got_id == DS2411_OK)
+        {
+            lcd_putsf(0, ++line, "  FC=%02x", (unsigned)id.family_code);
+            lcd_putsf(0, ++line, "  ID=%02X %02X %02X %02X %02X %02X",
+                (unsigned)id.uid[0], (unsigned)id.uid[1], (unsigned)id.uid[2],
+                (unsigned)id.uid[3], (unsigned)id.uid[4], (unsigned)id.uid[5]);
+            lcd_putsf(0, ++line, "  CRC=%02X", (unsigned)id.crc);
+        }
+        else
+        {
+            lcd_putsf(0, ++line, "READ ERR=%d", got_id);
+        }
+    }
+#endif
+
+    /* wait for exit */
+    while (button_get_w_tmo(HZ/10) != (DEBUG_CANCEL|BUTTON_REL));
+
+    lcd_setfont(FONT_UI);
+    return false;
+}
diff --git a/firmware/target/coldfire/debug-target.h b/firmware/target/coldfire/debug-target.h
index 76b502e..de19bf1 100644
--- a/firmware/target/coldfire/debug-target.h
+++ b/firmware/target/coldfire/debug-target.h
@@ -32,3 +32,4 @@
 #   define DEBUG_CANCEL  BUTTON_REC
 #endif
 bool dbg_ports(void);
+bool dbg_hw_info(void);
diff --git a/firmware/target/mips/ingenic_jz47xx/debug-jz4740.c b/firmware/target/mips/ingenic_jz47xx/debug-jz4740.c
index 5bdd4c4..d717056 100644
--- a/firmware/target/mips/ingenic_jz47xx/debug-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/debug-jz4740.c
@@ -134,7 +134,7 @@ bool dbg_ports(void)
     return false;
 }
 
-bool __dbg_hw_info(void)
+bool dbg_hw_info(void)
 {
     int btn = 0;
 #ifdef HAVE_TOUCHSCREEN
diff --git a/firmware/target/mips/ingenic_jz47xx/debug-target.h b/firmware/target/mips/ingenic_jz47xx/debug-target.h
index f82b43d..f51c5bf 100644
--- a/firmware/target/mips/ingenic_jz47xx/debug-target.h
+++ b/firmware/target/mips/ingenic_jz47xx/debug-target.h
@@ -22,7 +22,7 @@
 #ifndef __DEBUG_TARGET_H_
 #define __DEBUG_TARGET_H_
 
-bool __dbg_hw_info(void);
+bool dbg_hw_info(void);
 bool dbg_ports(void);
 
 #endif /* __DEBUG_TARGET_H_ */
diff --git a/firmware/target/sh/debug-sh.c b/firmware/target/sh/debug-sh.c
index 3502cfa..78d0032 100644
--- a/firmware/target/sh/debug-sh.c
+++ b/firmware/target/sh/debug-sh.c
@@ -22,13 +22,65 @@
 #include "config.h"
 #include "system.h"
 #include <stdbool.h>
+#include <string.h>
 #include "font.h"
 #include "lcd.h"
 #include "button.h"
 #include "powermgmt.h"
 #include "adc.h"
+#include "hwcompat.h"    /* ROM_VERSION */
+#include "crc32.h"      
 #include "debug-target.h"
 
+
+/* Tool function to read the flash manufacturer and type, if available.
+   Only chips which could be reprogrammed in system will return values.
+   (The mode switch addresses vary between flash manufacturers, hence addr1/2) */
+   /* In IRAM to avoid problems when running directly from Flash */
+static bool dbg_flash_id(unsigned* p_manufacturer, unsigned* p_device,
+                         unsigned addr1, unsigned addr2)
+                         ICODE_ATTR __attribute__((noinline));
+static bool dbg_flash_id(unsigned* p_manufacturer, unsigned* p_device,
+                         unsigned addr1, unsigned addr2)
+{
+    unsigned not_manu, not_id; /* read values before switching to ID mode */
+    unsigned manu, id; /* read values when in ID mode */
+
+    volatile unsigned char* flash = (unsigned char*)0x2000000; /* flash mapping */
+    int old_level; /* saved interrupt level */
+
+    not_manu = flash[0]; /* read the normal content */
+    not_id   = flash[1]; /* should be 'A' (0x41) and 'R' (0x52) from the "ARCH" marker */
+
+    /* disable interrupts, prevent any stray flash access */
+    old_level = disable_irq_save();
+
+    flash[addr1] = 0xAA; /* enter command mode */
+    flash[addr2] = 0x55;
+    flash[addr1] = 0x90; /* ID command */
+    /* Atmel wants 20ms pause here */
+    /* sleep(HZ/50); no sleeping possible while interrupts are disabled */
+
+    manu = flash[0]; /* read the IDs */
+    id   = flash[1];
+
+    flash[0] = 0xF0; /* reset flash (back to normal read mode) */
+    /* Atmel wants 20ms pause here */
+    /* sleep(HZ/50); no sleeping possible while interrupts are disabled */
+
+    restore_irq(old_level); /* enable interrupts again */
+    /* I assume success if the obtained values are different from
+        the normal flash content. This is not perfectly bulletproof, they
+        could theoretically be the same by chance, causing us to fail. */
+    if (not_manu != manu || not_id != id) /* a value has changed */
+    {
+        *p_manufacturer = manu; /* return the results */
+        *p_device = id;
+        return true; /* success */
+    }
+    return false; /* fail */
+}
+
 bool dbg_ports(void)
 {
     int adc_battery_voltage;
@@ -58,11 +110,11 @@ bool dbg_ports(void)
                  adc_battery_voltage % 1000, adc_battery_level);
 
         lcd_update();
-        if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL))
-        {
-            lcd_setfont(FONT_UI);
-            return false;
-        }
+
+        while (button_get_w_tmo(HZ/10) != (DEBUG_CANCEL|BUTTON_REL));
+
+        lcd_setfont(FONT_UI);
+
 #else /* !HAVE_LCD_BITMAP */
 
        if (currval == 0) {
@@ -101,3 +153,127 @@ bool dbg_ports(void)
     }
     return false;
 }
+
+bool dbg_hw_info(void)
+{
+#ifndef HAVE_LCD_BITMAP
+    int button;
+    int currval = 0;
+#else
+    int bitmask = HW_MASK;
+#endif
+    int rom_version = ROM_VERSION;
+    unsigned manu, id; /* flash IDs */
+    bool got_id; /* flag if we managed to get the flash IDs */
+    unsigned rom_crc = 0xffffffff; /* CRC32 of the boot ROM */
+    bool has_bootrom; /* flag for boot ROM present */
+    int oldmode;  /* saved memory guard mode */
+
+    oldmode = system_memory_guard(MEMGUARD_NONE);  /* disable memory guard */
+
+    /* get flash ROM type */
+    got_id = dbg_flash_id(&manu, &id, 0x5555, 0x2AAA); /* try SST, Atmel, NexFlash */
+    if (!got_id)
+        got_id = dbg_flash_id(&manu, &id, 0x555, 0x2AA); /* try AMD, Macronix */
+
+    /* check if the boot ROM area is a flash mirror */
+    has_bootrom = (memcmp((char*)0, (char*)0x02000000, 64*1024) != 0);
+    if (has_bootrom)  /* if ROM and Flash different */
+    {
+        /* calculate CRC16 checksum of boot ROM */
+        rom_crc = crc_32((unsigned char*)0x0000, 64*1024, 0xffffffff);
+    }
+
+    system_memory_guard(oldmode);  /* re-enable memory guard */
+
+    lcd_clear_display();
+
+#ifdef HAVE_LCD_BITMAP
+    lcd_setfont(FONT_SYSFIXED);
+
+    lcd_puts(0, 0, "[Hardware info]");
+
+    lcd_putsf(0, 1, "ROM: %d.%02d", rom_version/100, rom_version%100);
+
+    lcd_putsf(0, 2, "Mask: 0x%04x", bitmask);
+    if (got_id)
+        lcd_putsf(0, 3, "Flash: M=%02x D=%02x", manu, id);
+    else
+        lcd_puts(0, 3, "Flash: M=?? D=??"); /* unknown, sorry */
+
+    if (has_bootrom)
+    {
+        if (rom_crc == 0x56DBA4EE) /* known Version 1 */
+            lcd_puts(0, 4, "Boot ROM: V1");
+        else
+            lcd_putsf(0, 4, "ROMcrc: 0x%08x", rom_crc);
+    }
+    else
+    {
+        lcd_puts(0, 4, "Boot ROM: none");
+    }
+
+    lcd_update();
+
+    /* wait for exit */
+    while (button_get_w_tmo(HZ/10) != (DEBUG_CANCEL|BUTTON_REL));
+
+    lcd_setfont(FONT_UI);
+
+#else /* !HAVE_LCD_BITMAP */
+    lcd_puts(0, 0, "[HW Info]");
+    while(1)
+    {
+        switch(currval)
+        {
+            case 0:
+                lcd_putsf(0, 1, "ROM: %d.%02d",
+                         rom_version/100, rom_version%100);
+                break;
+            case 1:
+                if (got_id)
+                    lcd_putsf(0, 1, "Flash:%02x,%02x", manu, id);
+                else
+                    lcd_puts(0, 1, "Flash:??,??"); /* unknown, sorry */
+                break;
+            case 2:
+                if (has_bootrom)
+                {
+                    if (rom_crc == 0x56DBA4EE) /* known Version 1 */
+                        lcd_puts(0, 1, "BootROM: V1");
+                    else if (rom_crc == 0x358099E8)
+                        lcd_puts(0, 1, "BootROM: V2");
+                        /* alternative boot ROM found in one single player so far */
+                    else
+                        lcd_putsf(0, 1, "R: %08x", rom_crc);
+                }
+                else
+                    lcd_puts(0, 1, "BootROM: no");
+        }
+
+        lcd_update();
+
+        button = button_get_w_tmo(HZ/10);
+
+        switch(button)
+        {
+            case BUTTON_STOP:
+                return false;
+
+            case BUTTON_LEFT:
+                currval--;
+                if(currval < 0)
+                    currval = 2;
+                break;
+
+            case BUTTON_RIGHT:
+                currval++;
+                if(currval > 2)
+                    currval = 0;
+                break;
+        }
+    }
+#endif
+    return false;
+}
+
diff --git a/firmware/target/sh/debug-target.h b/firmware/target/sh/debug-target.h
index 4e25b81..f738795 100644
--- a/firmware/target/sh/debug-target.h
+++ b/firmware/target/sh/debug-target.h
@@ -25,3 +25,4 @@
 #   define DEBUG_CANCEL  BUTTON_MENU
 #endif
 bool dbg_ports(void);
+bool dbg_hw_info(void);
