Initial commit for the Sony NWZ linux port

SUPPORTED SERIES:
- NWZ-E450
- NWZ-E460
- NWZ-E470
- NWZ-E580
- NWZ-A10

NOTES:
- bootloader makefile convert an extra font to be installed alongside the bootloader
  since sysfont is way too small
- the toolsicon bitmap comes from the Oxygen iconset
- touchscreen driver is untested

TODO:
- implement audio routing driver (pcm is handled by pcm-alsa)
- fix playback: it crashes on illegal instruction in DEBUG builds
- find out why the browser starts at / instead of /contents
- implement radio support
- implement return to OF for usb handling
- calibrate battery curve (NB: of can report a battery level on a 0-5 scale but
  probabl don't want to use that ?)
- implement simulator build (we need a nice image of the player)
- figure out if we can detect jack removal

POTENTIAL TODOS:
- try to build a usb serial gadget and gdbserver

Change-Id: Ic77d71e0651355d47cc4e423a40fb64a60c69a80
diff --git a/apps/bitmaps/bitmaps.make b/apps/bitmaps/bitmaps.make
index a8165b9..d39531a 100644
--- a/apps/bitmaps/bitmaps.make
+++ b/apps/bitmaps/bitmaps.make
@@ -29,7 +29,8 @@
 
 BMPHFILES = $(BMPINCDIR)/usblogo.h $(BMPINCDIR)/remote_usblogo.h \
 	$(BMPINCDIR)/default_icons.h $(BMPINCDIR)/remote_default_icons.h \
-	$(BMPINCDIR)/rockboxlogo.h $(BMPINCDIR)/remote_rockboxlogo.h
+	$(BMPINCDIR)/rockboxlogo.h $(BMPINCDIR)/remote_rockboxlogo.h \
+	$(BMPINCDIR)/rockboxicon.h $(BMPINCDIR)/toolsicon.h
 
 $(BMPHFILES): $(BMPOBJ)
 
diff --git a/apps/bitmaps/native/SOURCES b/apps/bitmaps/native/SOURCES
index 88a571b..dbd0f57 100644
--- a/apps/bitmaps/native/SOURCES
+++ b/apps/bitmaps/native/SOURCES
@@ -39,6 +39,12 @@
 rockboxlogo.640x198x16.bmp
 #endif
 
+/* The Sony NWZ linux bootloader needs icons to display a menu */
+#if defined(BOOTLOADER) && defined(SONY_NWZ_LINUX)
+rockboxicon.130x130x16.bmp
+toolsicon.130x130x16.bmp
+#endif
+
 #ifndef BOOTLOADER  /* We don't need these for the bootloader */
 
 /* USB logo */
diff --git a/utils/nwztools/plattools/data/rockbox_icon.bmp b/apps/bitmaps/native/rockboxicon.130x130x16.bmp
similarity index 100%
rename from utils/nwztools/plattools/data/rockbox_icon.bmp
rename to apps/bitmaps/native/rockboxicon.130x130x16.bmp
Binary files differ
diff --git a/utils/nwztools/plattools/data/tools_icon.bmp b/apps/bitmaps/native/toolsicon.130x130x16.bmp
similarity index 100%
rename from utils/nwztools/plattools/data/tools_icon.bmp
rename to apps/bitmaps/native/toolsicon.130x130x16.bmp
Binary files differ
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 08fc6e0..55454e0 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -2594,7 +2594,7 @@
 #endif
         { "Skin Engine RAM usage", dbg_skin_engine },
 #endif
-#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
+#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SONY_NWZ_LINUX)
         { "View HW info", dbg_hw_info },
 #endif
 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
diff --git a/apps/keymaps/keymap-nwz.c b/apps/keymaps/keymap-nwz.c
index 210841b..90a26e5 100644
--- a/apps/keymaps/keymap-nwz.c
+++ b/apps/keymaps/keymap-nwz.c
@@ -210,6 +210,7 @@
 }; /* button_context_colorchooser */
 
 static const struct button_mapping button_context_eq[]  = {
+    { ACTION_STD_CANCEL,                BUTTON_BACK,                       BUTTON_NONE },
     { ACTION_STD_OK,                    BUTTON_PLAY|BUTTON_REL,            BUTTON_PLAY },
 
     LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_SETTINGS),
diff --git a/bootloader/SOURCES b/bootloader/SOURCES
index a9c6aeb..88b8aa0 100644
--- a/bootloader/SOURCES
+++ b/bootloader/SOURCES
@@ -71,6 +71,8 @@
 show_logo.c
 #elif defined(MPIO_HD200) || defined(MPIO_HD300)
 mpio_hd200_hd300.c
+#elif defined(SONY_NWZ_LINUX)
+nwz_linux.c
 #elif defined(RK27_GENERIC) || defined(HM60X) || defined(HM801) \
       || defined(MA9) || defined(MA9C) || defined(MA8) || defined(MA8C) \
       || defined(IHIFI760) || defined(IHIFI960)
diff --git a/bootloader/common.c b/bootloader/common.c
index 46c0e34..4969d92 100644
--- a/bootloader/common.c
+++ b/bootloader/common.c
@@ -60,6 +60,7 @@
 bool verbose = true;
 #endif
 
+#if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
 int line = 0;
 #ifdef HAVE_REMOTE_LCD
 int remote_line = 0;
@@ -101,6 +102,7 @@
 #endif
     return len;
 }
+#endif
 
 void error(int errortype, int error, bool shutdown)
 {
diff --git a/bootloader/common.h b/bootloader/common.h
index d09ff1a..56cbbb3 100644
--- a/bootloader/common.h
+++ b/bootloader/common.h
@@ -30,8 +30,10 @@
 #define     EBOOTFILE               -3
 
 /* Functions common to all bootloaders */
+#if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
 void reset_screen(void);
 int printf(const char *format, ...);
+#endif
 void error(int errortype, int error, bool shutdown);
 int load_raw_firmware(unsigned char* buf, char* firmware, int buffer_size);
 #ifdef ROCKBOX_HAS_LOGF
diff --git a/bootloader/nwz_linux.c b/bootloader/nwz_linux.c
new file mode 100644
index 0000000..7fe635b
--- /dev/null
+++ b/bootloader/nwz_linux.c
@@ -0,0 +1,524 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Amaury Pouly
+ *
+ * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
+ * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "system.h"
+#include "lcd.h"
+#include "backlight.h"
+#include "button-target.h"
+#include "button.h"
+#include "../kernel/kernel-internal.h"
+#include "core_alloc.h"
+#include "filesystem-app.h"
+#include "nvp-nwz.h"
+#include "power-nwz.h"
+#include "lcd.h"
+#include "font.h"
+#include "power.h"
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+
+/* all images must have the following size */
+#define ICON_WIDTH  130
+#define ICON_HEIGHT 130
+
+/* images */
+#include "bitmaps/rockboxicon.h"
+#include "bitmaps/toolsicon.h"
+
+/* don't issue an error when parsing the file for dependencies */
+#if defined(BMPWIDTH_rockboxicon) && (BMPWIDTH_rockboxicon != ICON_WIDTH || \
+    BMPHEIGHT_rockboxicon != ICON_HEIGHT)
+#error rockboxicon has the wrong resolution
+#endif
+#if defined(BMPWIDTH_toolsicon) && (BMPWIDTH_toolsicon != ICON_WIDTH || \
+    BMPHEIGHT_toolsicon != ICON_HEIGHT)
+#error toolsicon has the wrong resolution
+#endif
+
+/* buffer for Sony image, filled from NVP */
+unsigned short sonyicon[ICON_WIDTH * ICON_HEIGHT];
+const struct bitmap bm_sonyicon =
+{
+    .width = ICON_WIDTH,
+    .height = ICON_HEIGHT,
+    .format = FORMAT_NATIVE,
+    .data = (unsigned char*)sonyicon
+};
+
+/* return icon y position (x is always centered) */
+int get_icon_y(void)
+{
+    /* adjust so that this contains the Sony logo and produces a nice logo
+     * when used with rockbox */
+    if(LCD_HEIGHT == 320)
+        return 70;
+    else if(LCD_HEIGHT == 400)
+        return 100;
+    else
+        return LCD_HEIGHT / 2 - ICON_HEIGHT + 30; /* guess, probably won't work */
+}
+
+/* Sony logo extraction */
+bool extract_sony_logo(void)
+{
+    /* load the entire image from the nvp */
+    int bti_size = nwz_nvp_read(NWZ_NVP_BTI, NULL);
+    if(bti_size < 0)
+        return false;
+    unsigned short *bti = malloc(bti_size);
+    if(nwz_nvp_read(NWZ_NVP_BTI, bti) != bti_size)
+        return false;
+    /* compute the offset in the image of the logo itself */
+    int x_off = (LCD_WIDTH - ICON_WIDTH) / 2; /* logo is centered horizontally */
+    int y_off = get_icon_y();
+    /* extract part of the image */
+    for(int y = 0; y < ICON_HEIGHT; y++)
+    {
+        memcpy(sonyicon + ICON_WIDTH * y,
+            bti + LCD_WIDTH * (y + y_off) + x_off, ICON_WIDTH * sizeof(unsigned short));
+    }
+    free(bti);
+    return true;
+}
+
+/* Important Note: this bootloader is carefully written so that in case of
+ * error, the OF is run. This seems like the safest option since the OF is
+ * always there and might do magic things. */
+
+enum boot_mode
+{
+    BOOT_ROCKBOX,
+    BOOT_TOOLS,
+    BOOT_OF,
+    BOOT_COUNT,
+    BOOT_USB, /* special */
+    BOOT_STOP, /* power down/suspend */
+};
+
+static void display_text_center(int y, const char *text)
+{
+    int width;
+    lcd_getstringsize(text, &width, NULL);
+    lcd_putsxy(LCD_WIDTH / 2 - width / 2, y, text);
+}
+
+static void display_text_centerf(int y, const char *format, ...)
+{
+    char buf[1024];
+    va_list ap;
+    va_start(ap, format);
+
+    vsnprintf(buf, sizeof(buf), format, ap);
+    display_text_center(y, buf);
+}
+
+/* get timeout before taking action if the user doesn't touch the device */
+int get_inactivity_tmo(void)
+{
+    if(button_hold())
+        return 5 * HZ; /* Inactivity timeout when on hold */
+    else
+        return 10 * HZ; /* Inactivity timeout when not on hold */
+}
+
+/* return action on idle timeout */
+enum boot_mode inactivity_action(enum boot_mode cur_selection)
+{
+    if(button_hold())
+        return BOOT_STOP; /* power down/suspend */
+    else
+        return cur_selection; /* return last choice */
+}
+
+/* we store the boot mode in a file in /tmp so we can reload it between 'boots'
+ * (since the mostly suspends instead of powering down) */
+enum boot_mode load_boot_mode(enum boot_mode mode)
+{
+    int fd = open("/tmp/rb_bl_mode.txt", O_RDONLY);
+    if(fd >= 0)
+    {
+        read(fd, &mode, sizeof(mode));
+        close(fd);
+    }
+    return mode;
+}
+
+void save_boot_mode(enum boot_mode mode)
+{
+    int fd = open("/tmp/rb_bl_mode.txt", O_RDWR | O_CREAT | O_TRUNC);
+    if(fd >= 0)
+    {
+        write(fd, &mode, sizeof(mode));
+        close(fd);
+    }
+}
+
+enum boot_mode get_boot_mode(void)
+{
+    /* load previous mode, or start with rockbox if none */
+    enum boot_mode init_mode = load_boot_mode(BOOT_ROCKBOX);
+    /* wait for user action */
+    enum boot_mode mode = init_mode;
+    int last_activity = current_tick;
+    bool hold_status = button_hold();
+    while(true)
+    {
+        /* on usb detect, return to usb
+         * FIXME this is a hack, we need proper usb detection */
+        if(power_input_status() & POWER_INPUT_USB_CHARGER)
+        {
+            /* save last choice */
+            save_boot_mode(mode);
+            return BOOT_USB;
+        }
+        /* inactivity detection */
+        int timeout = last_activity + get_inactivity_tmo();
+        if(TIME_AFTER(current_tick, timeout))
+        {
+            /* save last choice */
+            save_boot_mode(mode);
+            return inactivity_action(mode);
+        }
+        /* redraw */
+        lcd_clear_display();
+        /* display top text */
+        if(button_hold())
+        {
+            lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
+            display_text_center(0, "ON HOLD!");
+        }
+        else
+        {
+            lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
+            display_text_center(0, "SELECT PLAYER");
+        }
+        lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
+        /* display icon */
+        const struct bitmap *icon = (mode == BOOT_OF) ? &bm_sonyicon :
+            (mode == BOOT_ROCKBOX) ? &bm_rockboxicon : &bm_toolsicon;
+        lcd_bmp(icon, (LCD_WIDTH - ICON_WIDTH) / 2, get_icon_y());
+        /* display bottom description */
+        const char *desc = (mode == BOOT_OF) ? "SONY" :
+            (mode == BOOT_ROCKBOX) ? "ROCKBOX" : "TOOLS";
+        display_text_center(get_icon_y() + ICON_HEIGHT + 30, desc);
+        /* display arrows */
+        int arrow_width, arrow_height;
+        lcd_getstringsize("<", &arrow_width, &arrow_height);
+        int arrow_y = get_icon_y() + ICON_HEIGHT / 2 - arrow_height / 2;
+        lcd_putsxy(arrow_width / 2, arrow_y, "<");
+        lcd_putsxy(LCD_WIDTH - 3 * arrow_width / 2, arrow_y, ">");
+
+        lcd_set_foreground(LCD_RGBPACK(0, 255, 0));
+        display_text_centerf(LCD_HEIGHT - arrow_height * 3 / 2, "timeout in %d sec",
+            (timeout - current_tick + HZ - 1) / HZ);
+
+        lcd_update();
+
+        /* wait for a key  */
+        int btn = button_get_w_tmo(HZ / 10);
+        /* record action, changing HOLD counts as action */
+        if(btn & BUTTON_MAIN || hold_status != button_hold())
+            last_activity = current_tick;
+        hold_status = button_hold();
+        /* ignore release, allow repeat */
+        if(btn & BUTTON_REL)
+            continue;
+        if(btn & BUTTON_REPEAT)
+            btn &= ~BUTTON_REPEAT;
+        /* play -> stop loop and return mode */
+        if(btn == BUTTON_PLAY)
+            break;
+        /* left/right/up/down: change mode */
+        if(btn == BUTTON_LEFT || btn == BUTTON_DOWN)
+            mode = (mode + BOOT_COUNT - 1) % BOOT_COUNT;
+        if(btn == BUTTON_RIGHT || btn == BUTTON_UP)
+            mode = (mode + 1) % BOOT_COUNT;
+    }
+
+    /* save mode */
+    save_boot_mode(mode);
+    return mode;
+}
+
+void error_screen(const char *msg)
+{
+    lcd_clear_display();
+    lcd_putsf(0, 0, msg);
+    lcd_update();
+}
+
+void create_sony_logo(void)
+{
+    for(int y = 0; y < ICON_HEIGHT; y++)
+        for(int x = 0; x < ICON_WIDTH; x++)
+            sonyicon[y * ICON_WIDTH + x] = 0xf81f;
+}
+
+int choice_screen(const char *title, bool center, int nr_choices, const char *choices[])
+{
+    int choice = 0;
+    int max_len = 0;
+    int h;
+    lcd_getstringsize("x", NULL, &h);
+    for(int i = 0; i < nr_choices; i++)
+    {
+        int len = strlen(choices[i]);
+        if(len > max_len)
+            max_len = len;
+    }
+    char *buf = malloc(max_len + 10);
+    int top_y = 2 * h;
+    int nr_lines = (LCD_HEIGHT - top_y) / h;
+    while(true)
+    {
+        /* make sure choice is visible */
+        int offset = choice - nr_lines / 2;
+        if(offset < 0)
+            offset = 0;
+        lcd_clear_display();
+        /* display top text */
+        lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
+        display_text_center(0, title);
+        int line = 0;
+        for(int i = 0; i < nr_choices && line < nr_lines; i++)
+        {
+            if(i < offset)
+                continue;
+            if(i == choice)
+                lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
+            else
+                lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
+            sprintf(buf, "%s", choices[i]);
+            if(center)
+                display_text_center(top_y + h * line, buf);
+            else
+                lcd_putsxy(0, top_y + h * line, buf);
+            line++;
+        }
+
+        lcd_update();
+
+        /* wait for a key  */
+        int btn = button_get_w_tmo(HZ / 10);
+        /* ignore release, allow repeat */
+        if(btn & BUTTON_REL)
+            continue;
+        if(btn & BUTTON_REPEAT)
+            btn &= ~BUTTON_REPEAT;
+        /* play -> stop loop and return mode */
+        if(btn == BUTTON_PLAY || btn == BUTTON_BACK)
+        {
+            free(buf);
+            return btn == BUTTON_PLAY ? choice : -1;
+        }
+        /* left/right/up/down: change mode */
+        if(btn == BUTTON_LEFT || btn == BUTTON_UP)
+            choice = (choice + nr_choices - 1) % nr_choices;
+        if(btn == BUTTON_RIGHT || btn == BUTTON_DOWN)
+            choice = (choice + 1) % nr_choices;
+    }
+}
+
+void run_file(const char *name)
+{
+    char *dirname = "/contents/";
+    char *buf = malloc(strlen(dirname) + strlen(name) + 1);
+    sprintf(buf, "%s%s", dirname, name);
+
+    lcd_clear_display();
+    lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
+    lcd_putsf(0, 0, "Running %s", name);
+    lcd_update();
+
+    pid_t pid = fork();
+    if(pid == 0)
+    {
+        execlp("sh", "sh", buf, NULL);
+        _exit(42);
+    }
+    int status;
+    waitpid(pid, &status, 0);
+    if(WIFEXITED(status))
+    {
+        lcd_set_foreground(LCD_RGBPACK(255, 201, 0));
+        lcd_putsf(0, 1, "program returned %d", WEXITSTATUS(status));
+    }
+    else
+    {
+        lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
+        lcd_putsf(0, 1, "an error occured: %x", status);
+    }
+    lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
+    lcd_putsf(0, 3, "Press any key or wait");
+    lcd_update();
+    /* wait a small time */
+    sleep(HZ);
+    /* ignore event */
+    while(button_get(false) != 0) {}
+    /* wait for any key or timeout */
+    button_get_w_tmo(4 * HZ);
+}
+
+void run_script_menu(void)
+{
+    const char **entries = NULL;
+    int nr_entries = 0;
+    DIR *dir = opendir("/contents/");
+    struct dirent *ent;
+    while((ent = readdir(dir)))
+    {
+        if(ent->d_type != DT_REG)
+            continue;
+        entries = realloc(entries, (nr_entries + 1) * sizeof(const char *));
+        entries[nr_entries++] = strdup(ent->d_name);
+    }
+    closedir(dir);
+    int idx = choice_screen("RUN SCRIPT", false, nr_entries, entries);
+    if(idx >= 0)
+        run_file(entries[idx]);
+    for(int i = 0; i < nr_entries; i++)
+        free((char *)entries[i]);
+    free(entries);
+}
+
+void tools_screen(void)
+{
+    const char *choices[] = {"Service menu", "Run script", "Restart", "Shutdown"};
+    int choice = choice_screen("TOOLS MENU", true, 4, choices);
+    if(choice == 0)
+    {
+        /* run service menu */
+        fflush(stdout);
+        execl("/usr/local/bin/mptapp", "mptapp", NULL);
+        error_screen("Cannot boot service menu");
+        sleep(5 * HZ);
+    }
+    else if(choice == 1)
+        run_script_menu();
+    else if(choice == 2)
+        nwz_power_restart();
+    else if(choice == 3)
+        nwz_power_shutdown();
+}
+
+/* open log file */
+int open_log(void)
+{
+    /* open regular log file */
+    int fd = open("/contents/rockbox.log", O_RDWR | O_CREAT | O_APPEND);
+    /* get its size */
+    struct stat stat;
+    if(fstat(fd, &stat) != 0)
+        return fd; /* on error, don't do anything */
+    /* if file is too large, rename it and start a new log file */
+    if(stat.st_size < 1000000)
+        return fd;
+    close(fd);
+    /* move file */
+    rename("/contents/rockbox.log", "/contents/rockbox.log.1");
+    /* re-open the file, truncate in case the move was unsuccessful */
+    return open("/contents/rockbox.log", O_RDWR | O_CREAT | O_APPEND | O_TRUNC);
+}
+
+int main(int argc, char **argv)
+{
+    (void) argc;
+    (void) argv;
+    /* redirect stdout and stderr to have error messages logged somewhere on the
+     * user partition */
+    int fd = open_log();
+    if(fd >= 0)
+    {
+        dup2(fd, fileno(stdout));
+        dup2(fd, fileno(stderr));
+        close(fd);
+    }
+    system_init();
+    core_allocator_init();
+    kernel_init();
+    paths_init();
+    lcd_init();
+    font_init();
+    button_init();
+    backlight_init();
+    backlight_set_brightness(DEFAULT_BRIGHTNESS_SETTING);
+    /* try to load the extra font we install on the device */
+    int font_id = font_load("/usr/local/share/rockbox/bootloader.fnt");
+    if(font_id >= 0)
+        lcd_setfont(font_id);
+    /* extract logo */
+    if(!extract_sony_logo())
+        create_sony_logo();
+    /* run all tools menu */
+    while(true)
+    {
+        enum boot_mode mode = get_boot_mode();
+        if(mode == BOOT_USB || mode == BOOT_OF)
+        {
+            fflush(stdout);
+            fflush(stderr);
+            close(fileno(stdout));
+            close(fileno(stderr));
+            /* for now the only way we have to trigger USB mode it to run the OF */
+            /* boot OF */
+            execvp("/usr/local/bin/SpiderApp.of", argv);
+            error_screen("Cannot boot OF");
+            sleep(5 * HZ);
+        }
+        else if(mode == BOOT_TOOLS)
+        {
+            tools_screen();
+        }
+        else if(mode == BOOT_ROCKBOX)
+        {
+            /* Rockbox expects /.rockbox to contain themes, rocks, etc, but we
+            * cannot easily create this symlink because the root filesystem is
+            * mounted read-only. Although we could remount it read-write temporarily,
+            * this is neededlessly complicated and we defer this job to the dualboot
+            * install script */
+            fflush(stdout);
+            execl("/contents/.rockbox/rockbox.sony", "rockbox.sony", NULL);
+            printf("execvp failed: %s\n", strerror(errno));
+            /* fallback to OF in case of failure */
+            error_screen("Cannot boot Rockbox");
+            sleep(5 * HZ);
+        }
+        else
+        {
+            /* FIXME doesn't seem to work */
+            printf("suspend\n");
+            nwz_power_suspend();
+        }
+    }
+    /* if we reach this point, everything failed, so return an error so that
+     * sysmgrd knows something is wrong */
+    return 1;
+}
diff --git a/firmware/SOURCES b/firmware/SOURCES
index e31bc2a..8ec17f7 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -95,6 +95,23 @@
 #endif
 #endif
 
+#ifdef SONY_NWZ_LINUX
+target/hosted/backtrace-glibc.c
+target/hosted/kernel-unix.c
+target/hosted/filesystem-unix.c
+target/hosted/lc-unix.c
+target/hosted/pcm-alsa.c
+target/hosted/sonynwz/lcd-nwz.c
+target/hosted/sonynwz/button-nwz.c
+target/hosted/sonynwz/system-nwz.c
+target/hosted/sonynwz/powermgmt-nwz.c
+target/hosted/sonynwz/power-nwz.c
+target/hosted/sonynwz/adc-nwz.c
+target/hosted/sonynwz/debug-nwz.c
+target/hosted/sonynwz/nvp-nwz.c
+target/hosted/sonynwz/nwz-db.c
+#endif
+
 #if defined(SAMSUNG_YPR0) && !defined(SIMULATOR)
 drivers/adc-as3514.c
 #if (CONFIG_RTC == RTC_AS3514)
@@ -447,6 +464,9 @@
 #elif defined(SAMSUNG_YPR1) && defined(HAVE_WM8978)
 drivers/audio/wm8978.c
 target/hosted/pcm-alsa.c
+#elif defined(HAVE_NWZ_LINUX_CODEC)
+drivers/audio/nwzlinux-codec.c
+target/hosted/alsa-controls.c
 #elif defined(HAVE_SDL_AUDIO)
 drivers/audio/sdl.c
 #if CONFIG_CODEC == SWCODEC
diff --git a/firmware/asm/SOURCES b/firmware/asm/SOURCES
index f16285e..5a1310e 100644
--- a/firmware/asm/SOURCES
+++ b/firmware/asm/SOURCES
@@ -15,7 +15,7 @@
     defined(CREATIVE_ZVx) || defined(SANSA_CONNECT) || defined(SANSA_FUZEPLUS) || \
     defined(COWON_D2) || defined(MINI2440) || defined(SAMSUNG_YPR0) || \
     defined(SAMSUNG_YPR1) || defined(DX50) || defined(DX90) || (defined(MROBE_500) && !defined(LCD_USE_DMA)) || \
-    defined(CREATIVE_ZEN) || defined(CREATIVE_ZENXFI)) && \
+    defined(CREATIVE_ZEN) || defined(CREATIVE_ZENXFI) || defined(SONY_NWZ_LINUX)) && \
     !defined(SIMULATOR)
 #if LCD_DEPTH == 24
 lcd-as-memframe-24bit.c
diff --git a/firmware/drivers/audio/nwzlinux-codec.c b/firmware/drivers/audio/nwzlinux-codec.c
new file mode 100644
index 0000000..aa0c7ef
--- /dev/null
+++ b/firmware/drivers/audio/nwzlinux-codec.c
@@ -0,0 +1,385 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (c) 2016 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "logf.h"
+#include "system.h"
+#include "kernel.h"
+#include "string.h"
+#include "stdio.h"
+#include "audio.h"
+#include "sound.h"
+#include "audiohw.h"
+#include "cscodec.h"
+#include "nwzlinux_codec.h"
+#include "stdlib.h"
+#include "panic.h"
+#include <sys/ioctl.h>
+#include "nwz_audio.h"
+#include "pcm-alsa.h"
+#include "alsa-controls.h"
+
+/* This driver handle the Sony linux audio drivers: despite using many differents
+ * codecs, it appears that they all share a common interface and common controls. */
+
+/* This is the alsa mixer interface exposed by Sony:
+numid=3,iface=MIXER,name='Capture Src Switch'
+  ; type=ENUMERATED,access=rw------,values=1,items=4
+  ; Item #0 'None'
+  ; Item #1 'Line'
+  ; Item #2 'Fm'
+  ; Item #3 'Mic'
+  : values=0
+numid=2,iface=MIXER,name='Playback Src Switch'
+  ; type=ENUMERATED,access=rw------,values=1,items=7
+  ; Item #0 'None'
+  ; Item #1 'Music'
+  ; Item #2 'Video'
+  ; Item #3 'Tv'
+  ; Item #4 'Fm'
+  ; Item #5 'Line'
+  ; Item #6 'Mic'
+  : values=1
+numid=1,iface=MIXER,name='Playback Volume'
+  ; type=INTEGER,access=rw------,values=2,min=0,max=100,step=1
+  : values=5,5
+numid=7,iface=MIXER,name='CODEC Acoustic Switch'
+  ; type=BOOLEAN,access=rw------,values=1
+  : values=on
+numid=8,iface=MIXER,name='CODEC Cue/Rev Switch'
+  ; type=BOOLEAN,access=rw------,values=1
+  : values=off
+numid=9,iface=MIXER,name='CODEC Fade In Switch'
+  ; type=BOOLEAN,access=rw------,values=1
+  : values=off
+numid=6,iface=MIXER,name='CODEC Mute Switch'
+  ; type=BOOLEAN,access=rw------,values=1
+  : values=off
+numid=5,iface=MIXER,name='CODEC Power Switch'
+  ; type=BOOLEAN,access=rw------,values=1
+  : values=on
+numid=10,iface=MIXER,name='CODEC Stanby Switch'
+  ; type=BOOLEAN,access=rw------,values=1
+  : values=off
+numid=4,iface=MIXER,name='Output Switch'
+  ; type=ENUMERATED,access=rw------,values=1,items=4
+  ; Item #0 'Headphone'
+  ; Item #1 'LineVariable'
+  ; Item #2 'LineFixed'
+  ; Item #3 'Speaker'
+  : values=0
+*/
+
+/* List of various codecs used by Sony */
+enum nwz_codec_t
+{
+    NWZ_CS42L56,
+    NWZ_R2A15602LG_D,
+    NWZ_CS47L01_A,
+    NWZ_CS47L01_D,
+    NWZ_CXD3774GF_D,
+    NWZ_UNK_CODEC,
+};
+
+#define NWZ_LEVEL_MUTE  -1000
+/* Description of the volume curve implemented by the kernel driver */
+struct nwz_vol_curve_t
+{
+    int count; /* number of levels */
+    int level[]; /* levels in tenth-dB, level[0] is always mute */
+};
+
+/* file descriptor of the icx_noican device */
+static int fd_noican;
+/* file descriptor of the hardware sound device */
+static int fd_hw;
+/* Codec */
+static enum nwz_codec_t nwz_codec;
+
+static enum nwz_codec_t find_codec(void)
+{
+    if(nwz_is_kernel_module_loaded("cs42L56_d"))
+        return NWZ_CS42L56;
+    if(nwz_is_kernel_module_loaded("r2A15602LG_d"))
+        return NWZ_R2A15602LG_D;
+    if(nwz_is_kernel_module_loaded("cs47L01_d"))
+        return NWZ_CS47L01_D;
+    if(nwz_is_kernel_module_loaded("cs47L01_a"))
+        return NWZ_CS47L01_A;
+    if(nwz_is_kernel_module_loaded("cxd3774gf_d"))
+        return NWZ_CXD3774GF_D;
+    return NWZ_UNK_CODEC;
+}
+
+const char *nwz_get_codec_name(void)
+{
+    switch(nwz_codec)
+    {
+        case NWZ_CS42L56: return "cs42L56_d";
+        case NWZ_R2A15602LG_D: return "r2A15602LG_d";
+        case NWZ_CS47L01_D: return "cs47L01_d";
+        case NWZ_CS47L01_A: return "cs47L01_a";
+        case NWZ_CXD3774GF_D: return "cxd3774gf_d";
+        default: return "Unknown";
+    }
+}
+
+static struct nwz_vol_curve_t cxd3774gf_vol_curve =
+{
+    .count = 31,
+    /* Most Sonys seem to follow the convention of 3dB/step then 2dB/step then 1dB/step */
+    .level = {NWZ_LEVEL_MUTE,
+        -550, -520, -490, -460, -430, -400, -370, -340, -310, -280, -250, /* 3dB/step */
+        -230, -210, -190, -170, -150, -130, -110, -90, /* 2dB/step */
+        -80, -70, -60, -50, -40, -30, -20, -10, 0, /* 1dB/step */
+        15, 35, /* 1.5dB then 2dB */
+    }
+};
+
+struct nwz_vol_curve_t *nwz_get_codec_vol_curve(void)
+{
+    switch(nwz_codec)
+    {
+        case NWZ_CS47L01_A:
+        case NWZ_CS47L01_D:
+            /* there are 32 levels but the last two are the same so in fact it
+             * is the same curve as the cxd3774gf_d */
+        case NWZ_CXD3774GF_D:
+            return &cxd3774gf_vol_curve;
+        default:
+            /* return the safest curve (only 31 levels) */
+            return &cxd3774gf_vol_curve;
+    }
+}
+
+static void noican_init(void)
+{
+    fd_noican = open(NWZ_NC_DEV, O_RDWR);
+    /* some targets don't have noise cancelling so silently fail */
+}
+
+static void noican_close(void)
+{
+    if(fd_noican >= 0)
+        close(fd_noican);
+}
+
+/* Set NC switch */
+static void noican_set_switch(int sw)
+{
+    if(ioctl(fd_noican, NWZ_NC_SET_SWITCH, &sw) < 0)
+        panicf("ioctl(NWZ_NC_SET_SWITCH) failed");
+}
+
+/* Get NC switch */
+static int noican_get_switch(void)
+{
+    int val;
+    if(ioctl(fd_noican, NWZ_NC_GET_SWITCH, &val) < 0)
+        panicf("ioctl(NWZ_NC_GET_SWITCH) failed");
+    return val;
+}
+
+/* Get HP status */
+static int noican_get_hp_status(void)
+{
+    int val;
+    if(ioctl(fd_noican, NWZ_NC_GET_HP_STATUS, &val) < 0)
+        panicf("ioctl(NWZ_NC_GET_HP_STATUS) failed");
+    return val;
+}
+
+/* Set HP type */
+static void noican_set_hp_type(int type)
+{
+    if(ioctl(fd_noican, NWZ_NC_SET_HP_TYPE, &type) < 0)
+        panicf("ioctl(NWZ_NC_SET_HP_TYPE) failed");
+}
+
+/* Get HP type */
+static int noican_get_hp_type(void)
+{
+    int val;
+    if(ioctl(fd_noican, NWZ_NC_GET_HP_TYPE, &val) < 0)
+        panicf("ioctl(NWZ_NC_GET_HP_TYPE) failed");
+    return val;
+}
+
+
+/* Set gain */
+static void noican_set_gain(int gain)
+{
+    if(ioctl(fd_noican, NWZ_NC_SET_GAIN, &gain) < 0)
+        panicf("ioctl(NWZ_NC_SET_GAIN) failed");
+}
+
+/* Get gain */
+static int noican_get_gain(void)
+{
+    int val;
+    if(ioctl(fd_noican, NWZ_NC_GET_GAIN, &val) < 0)
+        panicf("ioctl(NWZ_NC_GET_GAIN) failed");
+    return val;
+}
+
+/* Set filter */
+static void noican_set_filter(int filter)
+{
+    if(ioctl(fd_noican, NWZ_NC_SET_FILTER, &filter) < 0)
+        panicf("ioctl(NWZ_NC_SET_FILTER) failed");
+}
+
+/* Get filter */
+static int noican_get_filter(void)
+{
+    int val;
+    if(ioctl(fd_noican, NWZ_NC_GET_FILTER, &val) < 0)
+        panicf("ioctl(NWZ_NC_GET_FILTER) failed");
+    return val;
+}
+
+static void hw_open(void)
+{
+    fd_hw = open("/dev/snd/hwC0D0", O_RDWR);
+    if(fd_hw < 0)
+        panicf("Cannot open '/dev/snd/hwC0D0'");
+}
+
+static void hw_close(void)
+{
+    close(fd_hw);
+}
+
+void audiohw_preinit(void)
+{
+    alsa_controls_init();
+    /* turn on codec */
+    alsa_controls_set_bool("CODEC Power Switch", true);
+    /* mute */
+    alsa_controls_set_bool("CODEC Mute Switch", true);
+    /* Acoustic and Cue/Rev control how the volume curve, but it is not clear
+     * what the intention of these modes are and the OF does not seem to use
+     * them by default */
+    alsa_controls_set_bool("CODEC Acoustic Switch", false);
+    alsa_controls_set_bool("CODEC Cue/Rev Switch", false);
+    /* not sure exactly what it means */
+    alsa_controls_set_enum("Playback Src Switch", "Music");
+    /* use headphone output */
+    alsa_controls_set_enum("Output Switch", "Headphone");
+    /* unmute */
+    alsa_controls_set_bool("CODEC Mute Switch", false);
+
+    /* init noican */
+    noican_init();
+    if(fd_noican >= 0)
+    {
+        /* dump configuration, for debug purposes */
+        printf("nc hp status: %d\n", noican_get_hp_status());
+        printf("nc type: %d\n", noican_get_hp_type());
+        printf("nc switch: %d\n", noican_get_switch());
+        printf("nc gain: %d\n", noican_get_gain());
+        printf("nc filter: %d\n", noican_get_filter());
+        /* make sure we start in a clean state */
+        noican_set_switch(NWZ_NC_SWITCH_OFF);
+        noican_set_hp_type(NC_HP_TYPE_DEFAULT);
+        noican_set_filter(NWZ_NC_FILTER_INDEX_0);
+        noican_set_gain(NWZ_NC_GAIN_CENTER);
+    }
+
+    /* init hw */
+    hw_open();
+    nwz_codec = find_codec();
+    printf("Codec: %s\n", nwz_get_codec_name());
+}
+
+void audiohw_postinit(void)
+{
+}
+
+/* volume must be driver unit */
+static void nwz_set_driver_vol(int vol)
+{
+    long vols[2];
+    /* the driver expects percent, convert from centibel in range 0...x */
+    vols[0] = vols[1] = vol;
+    /* on some recent players like A10, Sony decided to merge left/right volume
+     * into one, thus we need to make sure we write the correct number of values */
+    int vol_cnt;
+    alsa_controls_get_info("Playback Volume", &vol_cnt);
+    alsa_controls_set_ints("Playback Volume", vol_cnt, vols);
+}
+
+/* volume is in tenth-dB */
+void audiohw_set_volume(int vol_l, int vol_r)
+{
+    /* FIXME at the moment we don't support balance and just average left and right.
+     * But this could be implemented using pcm alsa digital volume */
+
+    /* the Sony drivers expect vol_l = vol_r */
+    int vol = (vol_l + vol_r) / 2;
+    printf("request volume %d dB\n", vol / 10);
+    struct nwz_vol_curve_t *curve = nwz_get_codec_vol_curve();
+    /* min/max for pcm volume */
+    int min_pcm = -430;
+    int max_pcm = 0;
+    /* On some codecs (like cs47L01), Sony clear overdrives the DAC which produces
+     * massive clipping at any level (since they fix the DAC volume at around +6dB
+     * and then adjust HP volume in negative at the top of range !!). The only
+     * solution around this problem is to use the digital volume first so that
+     * very quickly the digital volume compensate for the DAC overdrive and we
+     * avoid clipping. */
+    int sony_clip_level = -80; /* any volume above this will cause massive clipping the DAC */
+
+    /* to avoid the clipping problem, virtually decrease requested volume by the
+     * clipping threshold, so that we will compensate in digital later by
+     * at least this amount if possibly */
+    vol -= sony_clip_level;
+
+    int drv_vol = curve->count - 1;
+    /* pick driver level just above request volume */
+    while(drv_vol > 0 && curve->level[drv_vol - 1] >= vol)
+        drv_vol--;
+    /* now remove the artifical volume change */
+    vol += sony_clip_level;
+    /* now adjust digital volume */
+    vol -= curve->level[drv_vol];
+    if(vol < min_pcm)
+    {
+        vol = min_pcm; /* digital cannot do <43dB */
+        drv_vol = 0; /* mute */
+    }
+    else if(vol > max_pcm)
+        vol = max_pcm; /* digital cannot do >0dB */
+    printf(" set driver volume %d (%d dB)\n", drv_vol, curve->level[drv_vol] / 10);
+    nwz_set_driver_vol(drv_vol);
+    printf(" set digital volume %d dB\n", vol / 10);
+    pcm_alsa_set_digital_volume(vol / 10);
+}
+
+void audiohw_close(void)
+{
+    hw_close();
+    alsa_controls_close();
+    noican_close();
+}
+
+void audiohw_set_frequency(int fsel)
+{
+    (void) fsel;
+}
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h
index e6bb8dc..6026a3b 100644
--- a/firmware/export/audiohw.h
+++ b/firmware/export/audiohw.h
@@ -207,6 +207,8 @@
 #include "df1704.h"
 #elif defined(HAVE_PCM1792_CODEC)
 #include "pcm1792.h"
+#elif defined(HAVE_NWZ_LINUX_CODEC)
+#include "nwzlinux_codec.h"
 #elif (CONFIG_PLATFORM & (PLATFORM_ANDROID | PLATFORM_MAEMO\
        | PLATFORM_PANDORA | PLATFORM_SDL))
 #include "hosted_codec.h"
diff --git a/firmware/export/backtrace.h b/firmware/export/backtrace.h
new file mode 100644
index 0000000..283e293
--- /dev/null
+++ b/firmware/export/backtrace.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2017 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/ 
+#ifndef __ROCKBOX_BACKTRACE_H__
+#define __ROCKBOX_BACKTRACE_H__
+
+#include "config.h"
+#ifdef BACKTRACE_UNWARMINDER
+#include "backtrace-unwarminder.h"
+#endif
+
+/* Print a backtrace using lcd_* functions, starting at the given line and updating
+ * the line number. On targets that support it (typically native targets), the
+ * backtrace will start at the given value of PC and using the stack frame given
+ * by PC. On hosted targets, it will typically ignore those values and backtrace
+ * from the caller */
+void rb_backtrace(int pcAddr, int spAddr, unsigned *line);
+
+#endif /* __ROCKBOX_BACKTRACE_H__ */
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 4209955..aa11766 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -277,6 +277,7 @@
 #define LCD_IHIFI         60 /* as used by IHIFI 760/960 */
 #define LCD_CREATIVEZENXFISTYLE 61 /* as used by Creative Zen X-Fi Style */
 #define LCD_SAMSUNGYPR1   62 /* as used by Samsung YP-R1 */
+#define LCD_NWZ_LINUX   63 /* as used in the Linux-based NWZ series */
 
 /* LCD_PIXELFORMAT */
 #define HORIZONTAL_PACKING 1
@@ -581,6 +582,16 @@
 #include "config/ibassodx50.h"
 #elif defined(DX90)
 #include "config/ibassodx90.h"
+#elif defined(SONY_NWZE460)
+#include "config/sonynwze460.h"
+#elif defined(SONY_NWZE450)
+#include "config/sonynwze450.h"
+#elif defined(SONY_NWZE580)
+#include "config/sonynwze580.h"
+#elif defined(SONY_NWZA10)
+#include "config/sonynwza10.h"
+#elif defined(SONY_NWZE470)
+#include "config/sonynwze470.h"
 #else
 /* no known platform */
 #endif
diff --git a/firmware/export/config/sonynwza10.h b/firmware/export/config/sonynwza10.h
new file mode 100644
index 0000000..a0650cf
--- /dev/null
+++ b/firmware/export/config/sonynwza10.h
@@ -0,0 +1,16 @@
+/*
+ * This config file is for the Sony NW-A10 series
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 104
+
+#define MODEL_NAME   "Sony NWZ-A10 Series"
+
+/* LCD dimensions */
+#define LCD_WIDTH  240
+#define LCD_HEIGHT 320
+/* sqrt(240^2 + 320^2) / 2 = 200 */
+#define LCD_DPI 200
+
+#include "sonynwzlinux.h"
diff --git a/firmware/export/config/sonynwze450.h b/firmware/export/config/sonynwze450.h
new file mode 100644
index 0000000..6b99550
--- /dev/null
+++ b/firmware/export/config/sonynwze450.h
@@ -0,0 +1,16 @@
+/*
+ * This config file is for the Sony NWZ-E450 series
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 100
+
+#define MODEL_NAME   "Sony NWZ-E450 Series"
+
+/* LCD dimensions */
+#define LCD_WIDTH  240
+#define LCD_HEIGHT 320
+/* sqrt(240^2 + 320^2) / 2 = 200 */
+#define LCD_DPI 200
+
+#include "sonynwzlinux.h"
diff --git a/firmware/export/config/sonynwze460.h b/firmware/export/config/sonynwze460.h
new file mode 100644
index 0000000..4f2bc8c
--- /dev/null
+++ b/firmware/export/config/sonynwze460.h
@@ -0,0 +1,16 @@
+/*
+ * This config file is for the Sony NWZ-E460 series
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 101
+
+#define MODEL_NAME   "Sony NWZ-E460 Series"
+
+/* LCD dimensions */
+#define LCD_WIDTH  240
+#define LCD_HEIGHT 320
+/* sqrt(240^2 + 320^2) / 2 = 200 */
+#define LCD_DPI 200
+
+#include "sonynwzlinux.h"
diff --git a/firmware/export/config/sonynwze470.h b/firmware/export/config/sonynwze470.h
new file mode 100644
index 0000000..23fe74a
--- /dev/null
+++ b/firmware/export/config/sonynwze470.h
@@ -0,0 +1,16 @@
+/*
+ * This config file is for the Sony NWZ-E470 series
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 103
+
+#define MODEL_NAME   "Sony NWZ-E470 Series"
+
+/* LCD dimensions */
+#define LCD_WIDTH  240
+#define LCD_HEIGHT 320
+/* sqrt(240^2 + 320^2) / 2 = 200 */
+#define LCD_DPI 200
+
+#include "sonynwzlinux.h"
diff --git a/firmware/export/config/sonynwze580.h b/firmware/export/config/sonynwze580.h
new file mode 100644
index 0000000..f692e6a
--- /dev/null
+++ b/firmware/export/config/sonynwze580.h
@@ -0,0 +1,16 @@
+/*
+ * This config file is for the Sony NWZ-E580 series
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 102
+
+#define MODEL_NAME   "Sony NWZ-E580 Series"
+
+/* LCD dimensions */
+#define LCD_WIDTH  240
+#define LCD_HEIGHT 320
+/* sqrt(240^2 + 320^2) / 2 = 200 */
+#define LCD_DPI 200
+
+#include "sonynwzlinux.h"
diff --git a/firmware/export/config/sonynwzlinux.h b/firmware/export/config/sonynwzlinux.h
new file mode 100644
index 0000000..4c66651
--- /dev/null
+++ b/firmware/export/config/sonynwzlinux.h
@@ -0,0 +1,105 @@
+/*
+ * This config file is for the Sony NWZ Linux based targets
+ */
+
+#define CONFIG_PLATFORM (PLATFORM_HOSTED)
+
+/* define this if you have a bitmap LCD display */
+#define HAVE_LCD_BITMAP
+
+/* define this if you have a colour LCD */
+#define HAVE_LCD_COLOR
+
+/* Define this if the LCD can shut down */
+#define HAVE_LCD_SHUTDOWN
+
+/* define this if you want album art for this target */
+#define HAVE_ALBUMART
+
+/* define this to enable bitmap scaling */
+#define HAVE_BMP_SCALING
+
+/* define this to enable JPEG decoding */
+#define HAVE_JPEG
+
+/* define this if you have access to the quickscreen */
+#define HAVE_QUICKSCREEN
+
+/* define this if you would like tagcache to build on this target */
+#define HAVE_TAGCACHE
+
+/* define this if the target has volume keys which can be used in the lists */
+#define HAVE_VOLUME_IN_LIST
+
+#define LCD_DEPTH  16
+/* Check that but should not matter */
+#define LCD_PIXELFORMAT RGB565
+
+#define HAVE_BACKLIGHT
+#define HAVE_BACKLIGHT_BRIGHTNESS
+
+/* Main LCD backlight brightness range and defaults: the backlight driver only
+ * has levels from 0 to 5. But 0 is off so start at 1. The driver has configurable
+ * periods for fade in/out but we can't easily export that to Rockbox */
+#define MIN_BRIGHTNESS_SETTING      1
+#define MAX_BRIGHTNESS_SETTING      5
+#define DEFAULT_BRIGHTNESS_SETTING  4
+
+/* Which backlight fading type? */
+#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING
+
+/* define this if you have a real-time clock */
+#define CONFIG_RTC 0
+
+/* The number of bytes reserved for loadable codecs */
+#define CODEC_SIZE 0x80000
+
+/* The number of bytes reserved for loadable plugins */
+#define PLUGIN_BUFFER_SIZE 0x100000
+
+/* Define this if you do software codec */
+#define CONFIG_CODEC SWCODEC
+
+/* KeyPad configuration for plugins */
+#define CONFIG_KEYPAD SONY_NWZ_PAD
+#define HAS_BUTTON_HOLD
+
+/* We have usb power and can detect usb but it is handled by Linux */
+#define HAVE_USB_POWER
+#define USB_NONE
+
+#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE
+
+/* Linux controlls charging, we can monitor */
+#define CONFIG_CHARGING CHARGING_MONITOR
+
+/* define this if the hardware can be powered off while charging */
+#define HAVE_POWEROFF_WHILE_CHARGING
+
+/* same dimensions as gigabeats */
+#define CONFIG_LCD LCD_NWZ_LINUX
+
+/* Define this if you have a software controlled poweroff */
+#define HAVE_SW_POWEROFF
+
+/* Define this to the CPU frequency */
+#define CPU_FREQ            532000000
+
+/* No special storage */
+#define CONFIG_STORAGE STORAGE_HOSTFS
+#define HAVE_STORAGE_FLUSH
+
+/* Battery */
+#define BATTERY_TYPES_COUNT  1
+
+/* Audio codec */
+#define HAVE_NWZ_LINUX_CODEC
+
+/* special define to be use in various places */
+#define SONY_NWZ_LINUX
+
+/* Battery */
+#define BATTERY_CAPACITY_DEFAULT 600 /* default battery capacity */
+#define BATTERY_CAPACITY_MIN 600  /* min. capacity selectable */
+#define BATTERY_CAPACITY_MAX 600 /* max. capacity selectable */
+#define BATTERY_CAPACITY_INC 0   /* capacity increment */
diff --git a/utils/nwztools/plattools/nwz_adc.h b/firmware/export/nwzlinux_codec.h
similarity index 63%
copy from utils/nwztools/plattools/nwz_adc.h
copy to firmware/export/nwzlinux_codec.h
index 86b2dc7..fbd424a 100644
--- a/utils/nwztools/plattools/nwz_adc.h
+++ b/firmware/export/nwzlinux_codec.h
@@ -5,9 +5,8 @@
  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  *                     \/            \/     \/    \/            \/
- * $Id$
  *
- * Copyright (C) 2016 Amaury Pouly
+ * Copyright (C) 2016 by Amaury Pouly
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -18,25 +17,13 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
-#ifndef __NWZ_ADC_H__
-#define __NWZ_ADC_H__
 
-#define NWZ_ADC_DEV  "/dev/icx_adc"
+#ifndef __NWZLINUX_CODEC_H__
+#define __NWZLINUX_CODEC_H__
 
-#define NWZ_ADC_TYPE    'm'
+#define AUDIOHW_CAPS 0
 
-#define NWZ_ADC_MIN_CHAN    0
-#define NWZ_ADC_MAX_CHAN    7
+/* Ranges from -100dB to 4dB */
+AUDIOHW_SETTING(VOLUME,       "dB", 0,  1, -100,  4, -10)
 
-#define NWZ_ADC_VCCBAT  0
-#define NWZ_ADC_VCCVBUS 1
-#define NWZ_ADC_ADIN3   2
-#define NWZ_ADC_ADIN4   3
-#define NWZ_ADC_ADIN5   4
-#define NWZ_ADC_ADIN6   5
-#define NWZ_ADC_ADIN7   6
-#define NWZ_ADC_ADIN8   7
-
-#define NWZ_ADC_GET_VAL(chan)   _IOR(NWZ_ADC_TYPE, chan, unsigned char)
-
-#endif /* __NWZ_ADC_H__ */
+#endif /* __NWZLINUX_CODEC_H__ */
diff --git a/firmware/export/rbpaths.h b/firmware/export/rbpaths.h
index fdbf081..8dc9b3a 100644
--- a/firmware/export/rbpaths.h
+++ b/firmware/export/rbpaths.h
@@ -40,10 +40,13 @@
 #define ROCKBOX_DIR_LEN (sizeof(ROCKBOX_DIR)-1)
 #endif /* def __PCTOOL__ */
 
-#if !defined(APPLICATION) || defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) || defined(DX50) || defined(DX90)
+#if !defined(APPLICATION) || defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) || \
+    defined(DX50) || defined(DX90) || defined(SONY_NWZ_LINUX)
 
 #if defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1)
 #define HOME_DIR "/mnt/media0"
+#elif defined(SONY_NWZ_LINUX)
+#define HOME_DIR "/contents"
 #elif defined(DX50) || defined(DX90)
 /* Where to put save files like recordings, playlists, screen dumps ...*/
 #define HOME_DIR "/mnt/sdcard"
@@ -83,7 +86,8 @@
 #define PLUGIN_DEMOS_DIR    PLUGIN_DIR "/demos"
 #define VIEWERS_DIR         PLUGIN_DIR "/viewers"
 
-#if defined(APPLICATION) && !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) || defined(DX50) || defined(DX90))
+#if defined(APPLICATION) && !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) || \
+    defined(DX50) || defined(DX90) || defined(SONY_NWZ_LINUX))
 #define PLUGIN_DATA_DIR          ROCKBOX_DIR "/rocks.data"
 #define PLUGIN_GAMES_DATA_DIR    PLUGIN_DATA_DIR
 #define PLUGIN_APPS_DATA_DIR     PLUGIN_DATA_DIR
diff --git a/firmware/export/system.h b/firmware/export/system.h
index 62da252..911c9ed 100644
--- a/firmware/export/system.h
+++ b/firmware/export/system.h
@@ -336,7 +336,7 @@
 #ifndef SIMULATOR
 bool dbg_ports(void);
 #endif
-#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
+#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SONY_NWZ_LINUX)
 bool dbg_hw_info(void);
 #endif
 
diff --git a/firmware/font.c b/firmware/font.c
index 617a8a3..3208125 100644
--- a/firmware/font.c
+++ b/firmware/font.c
@@ -85,7 +85,7 @@
 /* compiled-in font */
 extern struct font sysfont;
 
-#ifndef BOOTLOADER
+#if !defined(BOOTLOADER) || defined(SONY_NWZ_LINUX)
 
 struct buflib_alloc_data {
     struct font font;    /* must be the first member! */
diff --git a/firmware/panic.c b/firmware/panic.c
index a352916..7e7e43d 100644
--- a/firmware/panic.c
+++ b/firmware/panic.c
@@ -115,7 +115,7 @@
     }
 
 #if defined(CPU_ARM)
-    backtrace(pc, sp, &y);
+    rb_backtrace(pc, sp, &y);
 #endif
 #ifdef ROCKBOX_HAS_LOGF
     logf_panic_dump(&y);
diff --git a/firmware/target/arm/system-arm.c b/firmware/target/arm/system-arm.c
index e687e1d..74df5ed 100644
--- a/firmware/target/arm/system-arm.c
+++ b/firmware/target/arm/system-arm.c
@@ -148,7 +148,7 @@
     if (!triggered)
     {
         triggered = true;
-        backtrace(pc, __get_sp(), &line);
+        rb_backtrace(pc, __get_sp(), &line);
     }
 
     lcd_update();
diff --git a/firmware/target/hosted/alsa-controls.c b/firmware/target/hosted/alsa-controls.c
new file mode 100644
index 0000000..9747fbe
--- /dev/null
+++ b/firmware/target/hosted/alsa-controls.c
@@ -0,0 +1,181 @@
+/***************************************************************************
+ *             __________               __   ___.                  
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___  
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /  
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <   
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \  
+ *                     \/            \/     \/    \/            \/ 
+ *
+ * Copyright (C) 2016 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "alsa-controls.h"
+#include "panic.h"
+#include <stdlib.h>
+
+/* alsa control handle, we keep it open at all times */
+static snd_ctl_t *alsa_ctl;
+/* list of all controls, we allocate and fill it once, so we can easily lookup */
+static snd_ctl_elem_list_t *alsa_ctl_list;
+
+void alsa_controls_init(void)
+{
+    snd_ctl_elem_info_t *info;
+    /* allocate list on heap because it is used it is used in other functions */
+    snd_ctl_elem_list_malloc(&alsa_ctl_list);
+    /* allocate info on stack so there is no need to free them */
+    snd_ctl_elem_info_alloca(&info);
+    /* there is only one card and "default" always works */
+    if(snd_ctl_open(&alsa_ctl, "default", 0) < 0)
+        panicf("Cannot open ctl\n");
+    /* ALSA is braindead: first "get" the list -> only retrieve count */
+    if(snd_ctl_elem_list(alsa_ctl, alsa_ctl_list) < 0)
+        panicf("Cannot get element list\n");
+    /* now we can allocate the list since the know the size */
+    int count = snd_ctl_elem_list_get_count(alsa_ctl_list);
+    if(snd_ctl_elem_list_alloc_space(alsa_ctl_list, count) < 0)
+        panicf("Cannot allocate space for element list\n");
+    /* ... and get the list again! */
+    if(snd_ctl_elem_list(alsa_ctl, alsa_ctl_list) < 0)
+        panicf("Cannot get element list\n");
+}
+
+void alsa_controls_close(void)
+{
+    snd_ctl_close(alsa_ctl);
+}
+
+/* find a control element ID by name, return false of not found, the id needs
+ * to be allocated */
+bool alsa_controls_find(snd_ctl_elem_id_t *id, const char *name)
+{
+    /* ALSA identifies controls by "id"s, it almost makes sense, except ids
+     * are a horrible opaque structure */
+    int count = snd_ctl_elem_list_get_count(alsa_ctl_list);
+    /* enumerate controls */
+    for(int i = 0; i < count; i++)
+    {
+        snd_ctl_elem_list_get_id(alsa_ctl_list, i, id);
+
+        if(strcmp(snd_ctl_elem_id_get_name(id), name) == 0)
+            return true;
+    }
+    /* not found */
+    return false;
+}
+
+/* find a control element enum index by name, return -1 if not found */
+int alsa_controls_find_enum(const char *name, const char *enum_name)
+{
+    snd_ctl_elem_id_t *id;
+    snd_ctl_elem_info_t *info;
+    /* allocate things on stack to speedup */
+    snd_ctl_elem_id_alloca(&id);
+    snd_ctl_elem_info_alloca(&info);
+    /* find control */
+    if(!alsa_controls_find(id, name))
+        panicf("Cannot find control '%s'", name);
+    snd_ctl_elem_info_set_id(info, id);
+    if(snd_ctl_elem_info(alsa_ctl, info) < 0)
+        panicf("Cannot get control '%s' info", name);
+    /* list items */
+    unsigned count = snd_ctl_elem_info_get_items(info);
+    for(unsigned i = 0; i < count; i++)
+    {
+        snd_ctl_elem_info_set_item(info, i);
+        if(snd_ctl_elem_info(alsa_ctl, info) < 0)
+            panicf("Cannot get control '%s' info for item %u", name, i);
+        if(strcmp(snd_ctl_elem_info_get_item_name(info), enum_name) == 0)
+            return i;
+    }
+    return -1;
+}
+
+/* set a control, potentially supports several values */
+void alsa_controls_set(const char *name, snd_ctl_elem_type_t type,
+    unsigned nr_values, long *val)
+{
+    snd_ctl_elem_id_t *id;
+    snd_ctl_elem_info_t *info;
+    snd_ctl_elem_value_t *value;
+    /* allocate things on stack to speedup */
+    snd_ctl_elem_id_alloca(&id);
+    snd_ctl_elem_info_alloca(&info);
+    snd_ctl_elem_value_alloca(&value);
+    /* find control */
+    if(!alsa_controls_find(id, name))
+        panicf("Cannot find control '%s'", name);
+    /* check the type of the control */
+    snd_ctl_elem_info_set_id(info, id);
+    if(snd_ctl_elem_info(alsa_ctl, info) < 0)
+        panicf("Cannot get control '%s' info", name);
+    if(snd_ctl_elem_info_get_type(info) != type)
+        panicf("Control '%s' has wrong type (got %d, expected %d", name,
+            snd_ctl_elem_info_get_type(info), type);
+    if(snd_ctl_elem_info_get_count(info) != nr_values)
+        panicf("Control '%s' has wrong count (got %u, expected %u)",
+            name, snd_ctl_elem_info_get_count(info), nr_values);
+    /* set value */
+    snd_ctl_elem_value_set_id(value, id);
+    for(unsigned i = 0; i < nr_values; i++)
+    {
+        /* ALSA is braindead: there are "typed" setters but they all take long anyway */
+        if(type == SND_CTL_ELEM_TYPE_BOOLEAN)
+            snd_ctl_elem_value_set_boolean(value, i, val[i]);
+        else if(type == SND_CTL_ELEM_TYPE_INTEGER)
+            snd_ctl_elem_value_set_integer(value, i, val[i]);
+        else if(type == SND_CTL_ELEM_TYPE_ENUMERATED)
+            snd_ctl_elem_value_set_enumerated(value, i, val[i]);
+    }
+    /* write value */
+    if(snd_ctl_elem_write(alsa_ctl, value) < 0)
+        panicf("Cannot write control '%s'", name);
+}
+
+/* get control information */
+void alsa_controls_get_info(const char *name, int *out_count)
+{
+    snd_ctl_elem_id_t *id;
+    snd_ctl_elem_info_t *info;
+    /* allocate things on stack to speedup */
+    snd_ctl_elem_id_alloca(&id);
+    snd_ctl_elem_info_alloca(&info);
+    /* find control */
+    if(!alsa_controls_find(id, name))
+        panicf("Cannot find control '%s'", name);
+    /* get info */
+    snd_ctl_elem_info_set_id(info, id);
+    if(snd_ctl_elem_info(alsa_ctl, info) < 0)
+        panicf("Cannot get control '%s' info", name);
+    *out_count = snd_ctl_elem_info_get_count(info);
+}
+
+/* helper function: set a control with a single boolean value */
+void alsa_controls_set_bool(const char *name, bool val)
+{
+    long lval = val;
+    alsa_controls_set(name, SND_CTL_ELEM_TYPE_BOOLEAN, 1, &lval);
+}
+
+/* helper function: set a control with a single enum value */
+void alsa_controls_set_enum(const char *name, const char *enum_name)
+{
+    long idx = alsa_controls_find_enum(name, enum_name);
+    if(idx < 0)
+        panicf("Cannot find enum '%s' for control '%s'", enum_name, name);
+    alsa_controls_set(name, SND_CTL_ELEM_TYPE_ENUMERATED, 1, &idx);
+}
+
+/* helper function: set a control with one or more integers */
+void alsa_controls_set_ints(const char *name, int count, long *val)
+{
+    return alsa_controls_set(name, SND_CTL_ELEM_TYPE_INTEGER, count, val);
+}
diff --git a/firmware/target/hosted/alsa-controls.h b/firmware/target/hosted/alsa-controls.h
new file mode 100644
index 0000000..ea2475a
--- /dev/null
+++ b/firmware/target/hosted/alsa-controls.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ *             __________               __   ___.                  
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___  
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /  
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <   
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \  
+ *                     \/            \/     \/    \/            \/ 
+ *
+ * Copyright (C) 2016 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __ALSA_CONTROLS_RB_H__
+#define __ALSA_CONTROLS_RB_H__
+
+#include <config.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <alsa/asoundlib.h>
+#include <alloca.h>
+
+/* open alsa control interface and list all controls, keep control open */
+void alsa_controls_init(void);
+/* close alsa controls */
+void alsa_controls_close(void);
+
+/* find a control element ID by name, return false of not found, the id needs
+ * to be allocated */
+bool alsa_controls_find(snd_ctl_elem_id_t *id, const char *name);
+/* find a control element enum index by name, return -1 if not found */
+int alsa_controls_find_enum(const char *name, const char *enum_name);
+/* set a control, potentially supports several values */
+void alsa_controls_set(const char *name, snd_ctl_elem_type_t type,
+    unsigned nr_values, long *val);
+/* get control information: number of values */
+void alsa_controls_get_info(const char *name, int *out_count);
+/* helper function: set a control with a single boolean value */
+void alsa_controls_set_bool(const char *name, bool val);
+/* helper function: set a control with a single enum value */
+void alsa_controls_set_enum(const char *name, const char *enum_name);
+/* helper function: set a control with one or more integers */
+void alsa_controls_set_ints(const char *name, int count, long *val);
+
+#endif /* __ALSA_CONTROLS_RB_H__ */
diff --git a/firmware/target/hosted/backtrace-glibc.c b/firmware/target/hosted/backtrace-glibc.c
new file mode 100644
index 0000000..19becda
--- /dev/null
+++ b/firmware/target/hosted/backtrace-glibc.c
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (c) 2017 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include "system.h"
+#include "lcd.h"
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* backtrace from the call-site of this function */
+void rb_backtrace(int pc, int sp, unsigned *line)
+{
+    /* ignore SP and PC */
+    (void) pc;
+    (void) sp;
+
+    /* backtrace */
+    #define BT_BUF_SIZE 100
+    void *buffer[BT_BUF_SIZE];
+    int count = backtrace(buffer, BT_BUF_SIZE);
+    /* print symbols to stdout for debug */
+    fprintf(stdout, "backtrace:\n");
+    fflush(stdout);
+    backtrace_symbols_fd(buffer, count, STDOUT_FILENO);
+    /* print on screen */
+    char **strings;
+    strings = backtrace_symbols(buffer, count);
+    if(strings == NULL)
+    {
+        perror("backtrace_symbols");
+        return;
+    }
+
+    for(int i = 0; i < count; i++)
+    {
+        lcd_putsf(0, (*line)++, "  %s", buffer[i], strings[i]);
+        lcd_update();
+    }
+
+    free(strings);
+}
diff --git a/firmware/target/hosted/filesystem-app.c b/firmware/target/hosted/filesystem-app.c
index 826ab5b..64ce9f4 100644
--- a/firmware/target/hosted/filesystem-app.c
+++ b/firmware/target/hosted/filesystem-app.c
@@ -43,11 +43,12 @@
         && !defined(__PCTOOL__)
 static const char *rbhome;
 #else
-/* YPR0, YPR1 */
+/* YPR0, YPR1, NWZ */
 static const char rbhome[] = HOME_DIR;
 #endif
 
-#if !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) || defined(DX50) || defined(DX90)) && !defined(__PCTOOL__)
+#if !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) || defined(DX50) || \
+    defined(SONY_NWZ_LINUX) || defined(DX90)) && !defined(__PCTOOL__)
 /* Special dirs are user-accessible (and user-writable) dirs which take priority
  * over the ones where Rockbox is installed to. Classic example would be
  * $HOME/.config/rockbox.org vs /usr/share/rockbox */
diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c
index 715af58..d55eebc 100644
--- a/firmware/target/hosted/pcm-alsa.c
+++ b/firmware/target/hosted/pcm-alsa.c
@@ -50,12 +50,14 @@
 #include "system.h"
 #include "debug.h"
 #include "kernel.h"
+#include "panic.h"
 
 #include "pcm.h"
 #include "pcm-internal.h"
 #include "pcm_mixer.h"
 #include "pcm_sampr.h"
 #include "audiohw.h"
+#include "pcm-alsa.h"
 
 #include <pthread.h>
 #include <signal.h>
@@ -66,14 +68,21 @@
  * with multple applications running */
 static char device[] = "plughw:0,0";                    /* playback device */
 static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */
+#ifdef SONY_NWZ_LINUX
+/* Sony NWZ must use 32-bit per sample */
+static const snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE;    /* sample format */
+typedef long sample_t;
+#else
 static const snd_pcm_format_t format = SND_PCM_FORMAT_S16;    /* sample format */
+typedef short sample_t;
+#endif
 static const int channels = 2;                                /* count of channels */
 static unsigned int rate = 44100;                       /* stream rate */
 
 static snd_pcm_t *handle;
 static snd_pcm_sframes_t buffer_size = MIX_FRAME_SAMPLES * 32; /* ~16k */
 static snd_pcm_sframes_t period_size = MIX_FRAME_SAMPLES * 4;  /*  ~4k */
-static short *frames;
+static sample_t *frames;
 
 static const void  *pcm_data = 0;
 static size_t       pcm_size = 0;
@@ -153,7 +162,7 @@
         goto error;
     }
     if (!frames)
-        frames = malloc(period_size * channels * sizeof(short));
+        frames = malloc(period_size * channels * sizeof(sample_t));
 
     /* write the parameters to device */
     err = snd_pcm_hw_params(handle, params);
@@ -212,6 +221,40 @@
     return err;
 }
 
+#ifdef SONY_NWZ_LINUX
+/* Digital volume explanation:
+ * with very good approximation (<0.1dB) the convertion from dB to multiplicative
+ * factor, for dB>=0, is 2^(dB/3). We can then notice that if we write dB=3*k+r
+ * then this is 2^k*2^(r/3) so we only need to look at r=0,1,2. For r=0 this is
+ * 1, for r=1 we have 2^(1/3)~=1.25 so we approximate by 1+1/4, and 2^(2/3)~=1.5
+ * so we approximate by 1+1/2. To go from negative to nonnegative we notice that
+ * 48 dB => 63095 factor ~= 2^16 so we virtually pre-multiply everything by 2^(-16)
+ * and add 48dB to the input volume. We cannot go lower -43dB because several
+ * values between -48dB and -43dB would require a fractional multiplier, which is
+ * stupid to implement for such very low volume. */
+static int dig_vol_mult = 2 ^ 16; /* multiplicative factor to apply to each sample */
+
+void pcm_alsa_set_digital_volume(int vol_db)
+{
+    if(vol_db > 0 || vol_db < -43)
+        panicf("invalid pcm alsa volume");
+    if(format != SND_PCM_FORMAT_S32_LE)
+        panicf("this function assumes 32-bit sample size");
+    vol_db += 48; /* -42dB .. 0dB => 5dB .. 48dB */
+    /* NOTE if vol_dB = 5 then vol_shift = 1 but r = 1 so we do vol_shift - 1 >= 0
+     * otherwise vol_dB >= 0 implies vol_shift >= 2 so vol_shift - 2 >= 0 */
+    int vol_shift = vol_db / 3;
+    int r = vol_db % 3;
+    if(r == 0)
+        dig_vol_mult = 1 << vol_shift;
+    else if(r == 1)
+        dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 2);
+    else
+        dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 1);
+    printf("%d dB -> factor = %d\n", vol_db - 48, dig_vol_mult);
+}
+#endif
+
 /* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */
 static bool fill_frames(void)
 {
@@ -229,12 +272,28 @@
                 return false;
             }
         }
-        copy_n = MIN((ssize_t)pcm_size, frames_left*4);
-        memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n);
 
-        pcm_data += copy_n;
-        pcm_size -= copy_n;
-        frames_left -= copy_n/4;
+        if (pcm_size % 4)
+            panicf("Wrong pcm_size");
+        /* the compiler will optimize this test away */
+        copy_n = MIN((ssize_t)pcm_size/4, frames_left);
+        if (format == SND_PCM_FORMAT_S32_LE)
+        {
+            /* We have to convert 16-bit to 32-bit, the need to multiply the
+             * sample by some value so the sound is not too low */
+            const short *pcm_ptr = pcm_data;
+            sample_t *sample_ptr = &frames[2*(period_size-frames_left)];
+            for (int i = 0; i < copy_n*2; i++)
+                *sample_ptr++ = *pcm_ptr++ * dig_vol_mult;
+        }
+        else
+        {
+            /* Rockbox and PCM have same format: memcopy */
+            memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n);
+        }
+        pcm_data += copy_n*4;
+        pcm_size -= copy_n*4;
+        frames_left -= copy_n;
 
         if (new_buffer)
         {
@@ -285,7 +344,7 @@
 {
     int err;
     snd_pcm_sframes_t sample_size;
-    short *samples;
+    sample_t *samples;
 
 #ifdef USE_ASYNC_CALLBACK
     /* assign alternative stack for the signal handlers */
@@ -323,7 +382,7 @@
 
     /* fill buffer with silence to initiate playback without noisy click */
     sample_size = buffer_size;
-    samples = malloc(sample_size * channels * sizeof(short));
+    samples = malloc(sample_size * channels * sizeof(sample_t));
 
     snd_pcm_format_set_silence(format, samples, sample_size);
     err = snd_pcm_writei(handle, samples, sample_size);
@@ -367,23 +426,19 @@
 
     if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
     {
-        printf("%s(): Cannot open device %s: %s\n", __func__, device, snd_strerror(err));
-        exit(EXIT_FAILURE);
-        return;
+        panicf("%s(): Cannot open device %s: %s\n", __func__, device, snd_strerror(err));
     }
 
     if ((err = snd_pcm_nonblock(handle, 1)))
-        printf("Could not set non-block mode: %s\n", snd_strerror(err));
+        panicf("Could not set non-block mode: %s\n", snd_strerror(err));
 
     if ((err = set_hwparams(handle, rate)) < 0)
     {
-        printf("Setting of hwparams failed: %s\n", snd_strerror(err));
-        exit(EXIT_FAILURE);
+        panicf("Setting of hwparams failed: %s\n", snd_strerror(err));
     }
     if ((err = set_swparams(handle)) < 0)
     {
-        printf("Setting of swparams failed: %s\n", snd_strerror(err));
-        exit(EXIT_FAILURE);
+        panicf("Setting of swparams failed: %s\n", snd_strerror(err));
     }
 
     pcm_dma_apply_settings();
diff --git a/utils/nwztools/plattools/nwz_adc.h b/firmware/target/hosted/pcm-alsa.h
similarity index 61%
copy from utils/nwztools/plattools/nwz_adc.h
copy to firmware/target/hosted/pcm-alsa.h
index 86b2dc7..a251449 100644
--- a/utils/nwztools/plattools/nwz_adc.h
+++ b/firmware/target/hosted/pcm-alsa.h
@@ -1,11 +1,10 @@
 /***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
+ *             __________               __   ___.                  
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___  
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /  
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <   
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \  
+ *                     \/            \/     \/    \/            \/ 
  *
  * Copyright (C) 2016 Amaury Pouly
  *
@@ -18,25 +17,15 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
-#ifndef __NWZ_ADC_H__
-#define __NWZ_ADC_H__
+#ifndef __PCM_ALSA_RB_H__
+#define __PCM_ALSA_RB_H__
 
-#define NWZ_ADC_DEV  "/dev/icx_adc"
+#include <config.h>
 
-#define NWZ_ADC_TYPE    'm'
+#ifdef SONY_NWZ_LINUX
+/* Set the PCM volume in dB: each sample with have this volume applied digitally
+ * before being sent to ALSA. Volume must satisfy -43 <= dB <= 0 */
+void pcm_alsa_set_digital_volume(int vol_db);
+#endif
 
-#define NWZ_ADC_MIN_CHAN    0
-#define NWZ_ADC_MAX_CHAN    7
-
-#define NWZ_ADC_VCCBAT  0
-#define NWZ_ADC_VCCVBUS 1
-#define NWZ_ADC_ADIN3   2
-#define NWZ_ADC_ADIN4   3
-#define NWZ_ADC_ADIN5   4
-#define NWZ_ADC_ADIN6   5
-#define NWZ_ADC_ADIN7   6
-#define NWZ_ADC_ADIN8   7
-
-#define NWZ_ADC_GET_VAL(chan)   _IOR(NWZ_ADC_TYPE, chan, unsigned char)
-
-#endif /* __NWZ_ADC_H__ */
+#endif /* __PCM_ALSA_RB_H__ */
diff --git a/firmware/target/hosted/sonynwz/adc-nwz.c b/firmware/target/hosted/sonynwz/adc-nwz.c
new file mode 100644
index 0000000..d981ead
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/adc-nwz.c
@@ -0,0 +1,63 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2016 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "adc.h"
+#include "adc-target.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+static int adc_fd = -1; /* file descriptor */
+
+static const char *nwz_adc_channel_name[NWZ_ADC_MAX_CHAN + 1] =
+{
+    [NWZ_ADC_VCCBAT] = "VCCBAT",
+    [NWZ_ADC_VCCVBUS] = "VCCBUS",
+    [NWZ_ADC_ADIN3] = "ADIN3",
+    [NWZ_ADC_ADIN4] = "ADIN4",
+    [NWZ_ADC_ADIN5] = "ADIN5",
+    [NWZ_ADC_ADIN6] = "ADIN6",
+    [NWZ_ADC_ADIN7] = "ADIN7",
+    [NWZ_ADC_ADIN8] = "ADIN8"
+};
+
+void adc_init(void)
+{
+    adc_fd = open(NWZ_ADC_DEV, O_RDONLY);
+}
+
+unsigned short adc_read(int channel)
+{
+    unsigned char val;
+    if(ioctl(adc_fd, NWZ_ADC_GET_VAL(channel), &val) < 0)
+        return 0;
+    else
+        return val;
+}
+
+const char *adc_name(int channel)
+{
+    if(channel < NWZ_ADC_MIN_CHAN || channel > NWZ_ADC_MAX_CHAN)
+        return "";
+    return nwz_adc_channel_name[channel];
+}
+ 
diff --git a/utils/nwztools/plattools/nwz_adc.h b/firmware/target/hosted/sonynwz/adc-target.h
similarity index 88%
rename from utils/nwztools/plattools/nwz_adc.h
rename to firmware/target/hosted/sonynwz/adc-target.h
index 86b2dc7..bee028a 100644
--- a/utils/nwztools/plattools/nwz_adc.h
+++ b/firmware/target/hosted/sonynwz/adc-target.h
@@ -7,7 +7,7 @@
  *                     \/            \/     \/    \/            \/
  * $Id$
  *
- * Copyright (C) 2016 Amaury Pouly
+ * Copyright (C) 2016 by Amaury Pouly
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -18,8 +18,10 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
-#ifndef __NWZ_ADC_H__
-#define __NWZ_ADC_H__
+#ifndef _ADC_NWZ_H_
+#define _ADC_NWZ_H_
+
+#include "adc.h"
 
 #define NWZ_ADC_DEV  "/dev/icx_adc"
 
@@ -39,4 +41,7 @@
 
 #define NWZ_ADC_GET_VAL(chan)   _IOR(NWZ_ADC_TYPE, chan, unsigned char)
 
-#endif /* __NWZ_ADC_H__ */
+/* Return channel name */
+const char *adc_name(int channel);
+
+#endif
diff --git a/utils/nwztools/plattools/nwz_adc.h b/firmware/target/hosted/sonynwz/backlight-target.h
similarity index 63%
copy from utils/nwztools/plattools/nwz_adc.h
copy to firmware/target/hosted/sonynwz/backlight-target.h
index 86b2dc7..b5a200d 100644
--- a/utils/nwztools/plattools/nwz_adc.h
+++ b/firmware/target/hosted/sonynwz/backlight-target.h
@@ -7,7 +7,7 @@
  *                     \/            \/     \/    \/            \/
  * $Id$
  *
- * Copyright (C) 2016 Amaury Pouly
+ * Copyright (C) 2016 by Amaury Pouly
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -18,25 +18,12 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
-#ifndef __NWZ_ADC_H__
-#define __NWZ_ADC_H__
+#ifndef BACKLIGHT_TARGET_H
+#define BACKLIGHT_TARGET_H
 
-#define NWZ_ADC_DEV  "/dev/icx_adc"
+bool backlight_hw_init(void);
+void backlight_hw_on(void);
+void backlight_hw_off(void);
+void backlight_hw_brightness(int brightness);
 
-#define NWZ_ADC_TYPE    'm'
-
-#define NWZ_ADC_MIN_CHAN    0
-#define NWZ_ADC_MAX_CHAN    7
-
-#define NWZ_ADC_VCCBAT  0
-#define NWZ_ADC_VCCVBUS 1
-#define NWZ_ADC_ADIN3   2
-#define NWZ_ADC_ADIN4   3
-#define NWZ_ADC_ADIN5   4
-#define NWZ_ADC_ADIN6   5
-#define NWZ_ADC_ADIN7   6
-#define NWZ_ADC_ADIN8   7
-
-#define NWZ_ADC_GET_VAL(chan)   _IOR(NWZ_ADC_TYPE, chan, unsigned char)
-
-#endif /* __NWZ_ADC_H__ */
+#endif /* BACKLIGHT_TARGET_H */
diff --git a/firmware/target/hosted/sonynwz/button-nwz.c b/firmware/target/hosted/sonynwz/button-nwz.c
new file mode 100644
index 0000000..0cbb3c5
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/button-nwz.c
@@ -0,0 +1,323 @@
+/***************************************************************************
+ *             __________               __   ___
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2016 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "button.h"
+#define LOGF_ENABLE
+#include "logf.h"
+#include "panic.h"
+#include "backlight.h"
+
+#include "nwz_keys.h"
+#include "nwz_ts.h"
+
+#include <poll.h>
+#include <dir.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <linux/input.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* device types */
+#define DEV_KEY     0   /* icx_keys driver */
+#define DEV_TOUCH   1   /* icx_touch_screen driver */
+
+/* HOLD status */
+static bool hold_status;
+/* button bitmap */
+static int button_bitmap;
+/* poll() descriptors (up to 2 for now: keys and touchscreen) */
+#define NR_POLL_DESC    2
+static struct pollfd poll_fds[NR_POLL_DESC];
+static nfds_t poll_nfds;
+int dev_type[NR_POLL_DESC]; /* DEV_* */
+
+#ifdef HAVE_TOUCHSCREEN
+/* structure to track touch state */
+static struct
+{
+    int x, y; /* current position (valid is touch is true) */
+    int max_x, max_y; /* maximum possible values */
+    int pressure, tool_width; /* current pressure and tool width */
+    int max_pressure, max_tool_width; /* maximum possible values */
+    bool touch; /* is the user touching the screen? */
+    /* the hardware supports "flick" gesture */
+    bool flick; /* was the action a flick? */
+    int flick_x, flick_y; /* if so, this is the flick direction */
+}ts_state;
+/* rockbox state, updated from ts state on SYN event */
+static int touch_x, touch_y;
+static bool touch_detect;
+
+/* get touchscreen information and init state */
+int ts_init_state(int fd)
+{
+    memset(state, 0, sizeof(struct nwz_ts_state_t));
+    struct input_absinfo info;
+    if(ioctl(fd, EVIOCGABS(ABS_X), &info) < 0)
+        return -1;
+    state->max_x = info.maximum;
+    if(ioctl(fd, EVIOCGABS(ABS_Y), &info) < 0)
+        return -1;
+    state->max_y = info.maximum;
+    if(ioctl(fd, EVIOCGABS(ABS_PRESSURE), &info) < 0)
+        return -1;
+    state->max_pressure = info.maximum;
+    if(ioctl(fd, EVIOCGABS(ABS_TOOL_WIDTH), &info) < 0)
+        return -1;
+    state->max_tool_width = info.maximum;
+    touch_detect = false;
+    return 0;
+}
+
+void handle_touch(struct input_event *evt)
+{
+    switch(evt->type)
+    {
+        case EV_SYN:
+            /* on SYN, we copy the state to the rockbox state */
+            touch_x = ts_state->x;
+            touch_y = ts_state->y;
+            /* map coordinate to screen */
+            x = x * LCD_WIDTH / ts_state->max_x;
+            y = y * LCD_HEIGHT / ts_state->max_y;
+            /* don't trust driver reported ranges */
+            x = MAX(0, MIN(x, LCD_WIDTH - 1));
+            y = MAX(0, MIN(y, LCD_HEIGHT - 1));
+            touch_detect = ts_state->touch;
+            /* reset flick */
+            state->flick = false;
+            break;
+        case EV_REL:
+            if(evt->code == REL_RX)
+                state->flick_x = evt->value;
+            else if(evt->code == REL_RY)
+                state->flick_y = evt->value;
+            else
+                break;
+            state->flick = true;
+            break;
+        case EV_ABS:
+            if(evt->code == ABS_X)
+                state->x = evt->value;
+            else if(evt->code == ABS_Y)
+                state->y = evt->value;
+            else if(evt->code == ABS_PRESSURE)
+                state->pressure = evt->value;
+            else if(evt->code == ABS_TOOL_WIDTH)
+                state->tool_width = evt->value;
+            break;
+        case EV_KEY:
+            if(evt->code == BTN_TOUCH)
+                state->touch = evt->value;
+            break;
+        default:
+            break;
+    }
+}
+#endif
+
+static void load_hold_status(int fd)
+{
+    /* HOLD is reported as the first LED */
+    unsigned long led_hold = 0;
+    if(ioctl(fd, EVIOCGLED(sizeof(led_hold)), &led_hold) < 0)
+        logf("cannot read HOLD status: %s", strerror(errno));
+    hold_status = !!led_hold;
+}
+
+static void key_init_state(int fd)
+{
+    /* the driver knows the HOLD statu at all times */
+    load_hold_status(fd);
+    /* the driver can be queried for button status but the output is garbage
+     * so just assume no keys are pressed */
+    button_bitmap = 0;
+}
+
+static void open_input_device(const char *path)
+{
+    int fd = open(path, O_RDWR);
+    if(fd < 0)
+        return;
+    /* query name */
+    char name[256];
+    if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0)
+    {
+        close(fd);
+        return;
+    }
+
+    if(strcmp(name, NWZ_KEY_NAME) == 0)
+        dev_type[poll_nfds] = DEV_KEY;
+    else if(strcmp(name, NWZ_TS_NAME) == 0)
+        dev_type[poll_nfds] = DEV_TOUCH;
+    else
+    {
+        /* only keep devices we know about */
+        close(fd);
+        return;
+    }
+    /* if we found a key driver, we can read the hold status from it (and keep
+     * it updated with events) */
+    if(dev_type[poll_nfds] == DEV_KEY)
+        key_init_state(fd);
+#ifdef HAVE_TOUCHSCREEN
+    else if(dev_type[poll_nfds] == DEV_TOUCH)
+        ts_init_state(fd);
+#endif
+    /* fill poll descriptor */
+    poll_fds[poll_nfds].fd = fd;
+    poll_fds[poll_nfds].events = POLLIN;
+    poll_fds[poll_nfds].revents = 0;
+    poll_nfds++;
+}
+
+/* keycode -> rockbox button mapping */
+static int button_map[NWZ_KEY_MASK + 1] =
+{
+    [0 ... NWZ_KEY_MASK] = 0,
+    [NWZ_KEY_PLAY] = BUTTON_PLAY,
+    [NWZ_KEY_RIGHT] = BUTTON_RIGHT,
+    [NWZ_KEY_LEFT] = BUTTON_LEFT,
+    [NWZ_KEY_UP] = BUTTON_UP,
+    [NWZ_KEY_DOWN] = BUTTON_DOWN,
+    [NWZ_KEY_ZAPPIN] = 0,
+    [NWZ_KEY_AD0_6] = 0,
+    [NWZ_KEY_AD0_7] = 0,
+    [NWZ_KEY_NONE] = 0,
+    [NWZ_KEY_VOL_DOWN] = BUTTON_VOL_DOWN,
+    [NWZ_KEY_VOL_UP] = BUTTON_VOL_UP,
+    [NWZ_KEY_BACK] = BUTTON_BACK,
+    [NWZ_KEY_OPTION] = BUTTON_POWER,
+    [NWZ_KEY_BT] = 0,
+    [NWZ_KEY_AD1_5] = 0,
+    [NWZ_KEY_AD1_6] = 0,
+    [NWZ_KEY_AD1_7] = 0,
+};
+
+static void handle_key(struct input_event evt)
+{
+    /* See headers/nwz_keys.h for explanation of Sony's nonstandard interface */
+    int keycode = evt.code & NWZ_KEY_MASK;
+    bool press = (evt.value == 0);
+    if(press)
+        button_bitmap |= button_map[keycode];
+    else
+        button_bitmap &= ~button_map[keycode];
+    bool new_hold_status = !!(evt.code & NWZ_KEY_HOLD_MASK);
+    if(new_hold_status != hold_status)
+    {
+        hold_status = new_hold_status;
+#ifndef BOOTLOADER
+        backlight_hold_changed(hold_status);
+#endif
+    }
+}
+
+bool button_hold(void)
+{
+    return hold_status;
+}
+
+void button_init_device(void)
+{
+    const char *input_path = "/dev/input";
+    char device_name[PATH_MAX];
+    /* find what input devices are available */
+    DIR* input_dir = opendir(input_path);
+    if(input_dir == NULL)
+        panicf("Cannot read /dev/input directory: %s", strerror(errno));
+    strcpy(device_name, input_path);
+    strcat(device_name, "/");
+    char *device_name_p = device_name + strlen(device_name);
+    struct dirent *dir_entry;
+    while((dir_entry = readdir(input_dir)))
+    {
+        /* skip '.' and '..' entries */
+        if(strcmp(dir_entry->d_name, ".") == 0 || strcmp(dir_entry->d_name, "..") == 0)
+            continue;
+        /* create device full path and open it */
+        strcpy(device_name_p, dir_entry->d_name);
+        open_input_device(device_name);
+    }
+    closedir(input_dir);
+    /* check if we have at least one device */
+    if(poll_nfds == 0)
+        panicf("No input device found");
+}
+
+int button_read_device(
+#ifdef HAVE_BUTTON_DATA
+    int *data
+#else
+    void
+#endif
+    )
+{
+    struct input_event event;
+    /* check if there are any events pending and process them */
+    while(true)
+    {
+        /* stop when there are no more events */
+        if(poll(poll_fds, poll_nfds, 0) == 0)
+            break;
+        for(unsigned int i = 0; i < poll_nfds; i++)
+        {
+            /* only read if we won't block */
+            if(!(poll_fds[i].revents & POLLIN))
+                continue;
+            if(read(poll_fds[i].fd, &event, sizeof(event)) != (int)sizeof(event))
+                continue;
+            if(dev_type[i] == DEV_KEY)
+                handle_key(event);
+#ifdef HAVE_TOUCHSCREEN
+            else if(dev_type[i] == DEV_TOUCH)
+                handle_touch(event);
+#endif
+        }
+    }
+#ifdef HAVE_TOUCHSCREEN
+    button_bitmap |= touchscreen_to_pixels(touch_x, touch_y, data);
+#endif
+    return hold_status ? 0 : button_bitmap;
+}
+
+void nwz_button_reload_after_suspend(void)
+{
+    /* reinit everything, particularly important for keys and HOLD */
+    for(unsigned int i = 0; i < poll_nfds; i++)
+    {
+        if(dev_type[i] == DEV_KEY)
+            key_init_state(poll_fds[i].fd);
+#ifdef HAVE_TOUCHSCREEN
+        else if(dev_type[i] == DEV_TOUCH)
+            ts_init_state(poll_fds[i].fd);
+#endif
+    }
+}
+
+void button_close_device(void)
+{
+    /* close descriptors */
+    for(unsigned int i = 0; i < poll_nfds; i++)
+        close(poll_fds[i].fd);
+}
diff --git a/firmware/target/hosted/sonynwz/button-target.h b/firmware/target/hosted/sonynwz/button-target.h
new file mode 100644
index 0000000..6cf915b
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/button-target.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _BUTTON_TARGET_H_
+#define _BUTTON_TARGET_H_
+
+#include <stdbool.h>
+#include "config.h"
+
+/* Main unit's buttons */
+#define BUTTON_POWER                0x00000001
+#define BUTTON_BACK                 0x00000002
+#define BUTTON_PLAY                 0x00000004
+#define BUTTON_LEFT                 0x00000008
+#define BUTTON_UP                   0x00000010
+#define BUTTON_DOWN                 0x00000020
+#define BUTTON_RIGHT                0x00000040
+#define BUTTON_VOL_DOWN             0x00000080
+#define BUTTON_VOL_UP               0x00000100
+
+#define BUTTON_MAIN                 0x000001ff
+
+/* Software power-off */
+#define POWEROFF_BUTTON BUTTON_POWER
+#define POWEROFF_COUNT 10
+
+/* force driver to reload button state (useful after suspend) */
+void nwz_button_reload_after_suspend(void);
+
+#endif /* _BUTTON_TARGET_H_ */
diff --git a/firmware/target/hosted/sonynwz/debug-nwz.c b/firmware/target/hosted/sonynwz/debug-nwz.c
new file mode 100644
index 0000000..c550295
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/debug-nwz.c
@@ -0,0 +1,439 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2016 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "cpu.h"
+#include "system.h"
+#include "kernel.h"
+#include "lcd.h"
+#include "font.h"
+#include "adc.h"
+#include "adc-target.h"
+#include "button.h"
+#include "button-target.h"
+#include "powermgmt.h"
+#include "power-nwz.h"
+#include "nvp-nwz.h"
+#include "nwz_sysinfo.h"
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+/* NOTE: some targets with touchscreen don't have the usual keypad, on those
+ * we use a mixture of rewind/forward/volume+/- to emulate it */
+#define ACT_NONE    0
+#define ACT_CANCEL  1
+#define ACT_OK      2
+#define ACT_PREV    3
+#define ACT_NEXT    4
+#define ACT_REPEAT  0x1000
+
+int xlate_button(int btn)
+{
+    switch(btn)
+    {
+#ifdef BUTTON_POWER
+        case BUTTON_POWER:
+#endif
+        case BUTTON_BACK:
+            return ACT_CANCEL;
+        case BUTTON_PLAY:
+            return ACT_OK;
+        case BUTTON_UP:
+        case BUTTON_LEFT:
+        case BUTTON_VOL_UP:
+            return ACT_PREV;
+        case BUTTON_DOWN:
+        case BUTTON_RIGHT:
+        case BUTTON_VOL_DOWN:
+            return ACT_NEXT;
+        default:
+            return ACT_NONE;
+    }
+}
+
+int my_get_status(void)
+{
+    return xlate_button(button_status());
+}
+
+int my_get_action(int tmo)
+{
+    int btn = button_get_w_tmo(tmo);
+    while(btn & BUTTON_REL)
+        btn = button_get_w_tmo(tmo);
+    bool repeat = btn & BUTTON_REPEAT;
+    int act = xlate_button(btn & ~BUTTON_REPEAT);
+    if(repeat)
+        act |= ACT_REPEAT;
+    return act;
+}
+
+bool dbg_hw_info_adc(void)
+{
+    lcd_setfont(FONT_SYSFIXED);
+
+    while(1)
+    {
+        int button = my_get_action(HZ / 25);
+        switch(button)
+        {
+            case ACT_NEXT:
+            case ACT_PREV:
+            case ACT_OK:
+                lcd_setfont(FONT_UI);
+                return true;
+            case ACT_CANCEL:
+                lcd_setfont(FONT_UI);
+                return false;
+        }
+
+        lcd_clear_display();
+
+        /* add battery readout in mV, this it is not the direct output of a channel */
+        lcd_putsf(0, 0, "Battery(mV) %d", _battery_voltage());
+        for(unsigned i = NWZ_ADC_MIN_CHAN; i <= NWZ_ADC_MAX_CHAN; i++)
+            lcd_putsf(0, i + 1, "%7s %3d", adc_name(i), adc_read(i));
+
+        lcd_update();
+        yield();
+    }
+}
+
+static const char *charge_status_name(int chgstat)
+{
+    switch(chgstat)
+    {
+        case NWZ_POWER_STATUS_CHARGE_STATUS_CHARGING: return "charging";
+        case NWZ_POWER_STATUS_CHARGE_STATUS_SUSPEND: return "suspend";
+        case NWZ_POWER_STATUS_CHARGE_STATUS_TIMEOUT: return "timeout";
+        case NWZ_POWER_STATUS_CHARGE_STATUS_NORMAL: return "normal";
+        default: return "unknown";
+    }
+}
+
+static const char *get_batt_gauge_name(int gauge)
+{
+    switch(gauge)
+    {
+        case NWZ_POWER_BAT_NOBAT: return "no batt";
+        case NWZ_POWER_BAT_VERYLOW: return "very low";
+        case NWZ_POWER_BAT_LOW: return "low";
+        case NWZ_POWER_BAT_GAUGE0: return "____";
+        case NWZ_POWER_BAT_GAUGE1: return "O___";
+        case NWZ_POWER_BAT_GAUGE2: return "OO__";
+        case NWZ_POWER_BAT_GAUGE3: return "OOO_";
+        case NWZ_POWER_BAT_GAUGE4: return "OOOO";
+        default: return "unknown";
+    }
+}
+
+static const char *acc_charge_mode_name(int mode)
+{
+    switch(mode)
+    {
+        case NWZ_POWER_ACC_CHARGE_NONE: return "none";
+        case NWZ_POWER_ACC_CHARGE_VBAT: return "vbat";
+        case NWZ_POWER_ACC_CHARGE_VSYS: return "vsys";
+        default: return "unknown";
+    }
+}
+
+bool dbg_hw_info_power(void)
+{
+    lcd_setfont(FONT_SYSFIXED);
+
+    while(1)
+    {
+        int button = my_get_action(HZ / 25);
+        switch(button)
+        {
+            case ACT_NEXT:
+            case ACT_PREV:
+            case ACT_OK:
+                lcd_setfont(FONT_UI);
+                return true;
+            case ACT_CANCEL:
+                lcd_setfont(FONT_UI);
+                return false;
+        }
+
+        lcd_clear_display();
+
+        int line = 0;
+        int status = nwz_power_get_status();
+        int chgstat = status & NWZ_POWER_STATUS_CHARGE_STATUS;
+        int acc_chg_mode = nwz_power_get_acc_charge_mode();
+        lcd_putsf(0, line++, "ac detected: %s",
+            (status & NWZ_POWER_STATUS_AC_DET) ? "yes" : "no");
+        lcd_putsf(0, line++, "vbus detected: %s   ",
+            (status & NWZ_POWER_STATUS_VBUS_DET) ? "yes" : "no");
+        lcd_putsf(0, line++, "vbus voltage: %d mV (AD=%d)",
+            nwz_power_get_vbus_voltage(), nwz_power_get_vbus_adval());
+        lcd_putsf(0, line++, "vbus limit: %d mA      ",
+            nwz_power_get_vbus_limit());
+        lcd_putsf(0, line++, "vsys voltage: %d mV (AD=%d)",
+            nwz_power_get_vsys_voltage(), nwz_power_get_vsys_adval());
+        lcd_putsf(0, line++, "charge switch: %s       ",
+            nwz_power_get_charge_switch() ? "on" : "off");
+        lcd_putsf(0, line++, "full voltage: %s V      ",
+            (status & NWZ_POWER_STATUS_CHARGE_LOW) ? "4.1" : "4.2");
+        lcd_putsf(0, line++, "current limit: %d mA",
+            nwz_power_get_charge_current());
+        lcd_putsf(0, line++, "charge status: %s (%x)",
+            charge_status_name(chgstat), chgstat);
+        lcd_putsf(0, line++, "battery full: %s       ",
+            nwz_power_is_fully_charged() ? "yes" : "no");
+        lcd_putsf(0, line++, "bat gauge: %s (%d)",
+            get_batt_gauge_name(nwz_power_get_battery_gauge()),
+            nwz_power_get_battery_gauge());
+        lcd_putsf(0, line++, "avg voltage: %d mV (AD=%d)",
+            nwz_power_get_battery_voltage(), nwz_power_get_battery_adval());
+        lcd_putsf(0, line++, "sample count: %d       ",
+            nwz_power_get_sample_count());
+        lcd_putsf(0, line++, "raw voltage: %d mV (AD=%d)",
+            nwz_power_get_vbat_voltage(), nwz_power_get_vbat_adval());
+        lcd_putsf(0, line++, "acc charge mode: %s (%d)",
+            acc_charge_mode_name(acc_chg_mode), acc_chg_mode);
+
+        lcd_update();
+        yield();
+    }
+}
+
+bool dbg_hw_info_button(void)
+{
+    lcd_setfont(FONT_SYSFIXED);
+
+    while(1)
+    {
+        int btn = my_get_action(0);
+        switch(btn)
+        {
+            case ACT_OK:
+                lcd_setfont(FONT_UI);
+                return true;
+            case ACT_CANCEL:
+                lcd_setfont(FONT_UI);
+                return false;
+        }
+
+        lcd_clear_display();
+        int line = 0;
+
+#ifdef HAVE_BUTTON_DATA
+        int data;
+        btn = button_read_device(&data);
+#else
+        btn = button_read_device();
+#endif
+        lcd_putsf(0, line++, "raw buttons: %x", btn);
+#ifdef HAS_BUTTON_HOLD
+        lcd_putsf(0, line++, "hold: %d", button_hold());
+#endif
+#ifdef HAVE_HEADPHONE_DETECTION
+        lcd_putsf(0, line++, "headphones: %d", headphones_inserted());
+#endif
+#ifdef HAVE_BUTTON_DATA
+#ifdef HAVE_TOUCHSCREEN
+        lcd_putsf(0, line++, "touch: x=%d y=%d", data >> 16, data & 0xffff);
+#else
+        lcd_putsf(0, line++, "data: %d", data);
+#endif
+#endif
+
+        lcd_update();
+        yield();
+    }
+}
+
+int read_sysinfo(int ioctl_nr, unsigned int *val)
+{
+    int fd = open(NWZ_SYSINFO_DEV, O_RDONLY);
+    if(fd < 0)
+        return -1;
+    int ret = ioctl(fd, ioctl_nr, val);
+    close(fd);
+    return ret;
+}
+
+bool dbg_hw_info_sysinfo(void)
+{
+    lcd_setfont(FONT_SYSFIXED);
+
+    while(1)
+    {
+        int btn = my_get_action(0);
+        switch(btn)
+        {
+            case ACT_OK:
+                lcd_setfont(FONT_UI);
+                return true;
+            case ACT_CANCEL:
+                lcd_setfont(FONT_UI);
+                return false;
+        }
+
+        lcd_clear_display();
+        int line = 0;
+        unsigned int val;
+
+        lcd_putsf(0, line++, "mid: %x (%s)", nwz_get_model_id(), nwz_get_model_name());
+#define print_info(def, name) \
+        if(read_sysinfo(NWZ_SYSINFO_GET_##def##_TYPE, &val) < 0) \
+            lcd_putsf(0, line++, "%s: -", name); \
+        else \
+            lcd_putsf(0, line++, "%s: %d", name, val);
+
+        /* WARNING the interpretation of values is difficult because it changes
+         * very often */
+        /* DAC type: ... */
+        print_info(DAC, "dac")
+        /* Noise cancelling: 0=no, 1=yes */
+        print_info(NCR, "nc")
+        /* Speaker: 0=no, 1=yes */
+        print_info(SPK, "spk")
+        /* Microphone: 0=no, 1=yes */
+        print_info(MIC, "mic")
+        /* Video encoder: 0=no, ... */
+        print_info(NPE, "videoenc")
+        /* FM receiver: 0=no, 1=si470x */
+        print_info(FMT, "fm")
+        /* Touch screen: 0=none, ... */
+        print_info(TSP, "touch")
+        /* Bluetooth: 0=no, 1=yes */
+        print_info(WAB, "bt")
+        /* SD card: 0=no, ... */
+        print_info(SDC, "sd")
+
+        lcd_update();
+        yield();
+    }
+}
+
+#include "pcm-alsa.h"
+
+bool dbg_hw_info_audio(void)
+{
+    lcd_setfont(FONT_SYSFIXED);
+    int vol = 0;
+
+    while(1)
+    {
+        int btn = my_get_action(0);
+        switch(btn)
+        {
+            case ACT_PREV:
+                vol--;
+                pcm_alsa_set_digital_volume(vol);
+                break;
+            case ACT_NEXT:
+                vol++;
+                pcm_alsa_set_digital_volume(vol);
+                break;
+            case ACT_OK:
+                lcd_setfont(FONT_UI);
+                return true;
+            case ACT_CANCEL:
+                lcd_setfont(FONT_UI);
+                return false;
+        }
+
+        lcd_clear_display();
+        int line = 0;
+        unsigned int val;
+
+        lcd_putsf(0, line++, "vol: %d dB", vol);
+
+        lcd_update();
+        yield();
+    }
+}
+
+static struct
+{
+    const char *name;
+    bool (*fn)(void);
+} debug_screens[] =
+{
+    {"sysinfo", dbg_hw_info_sysinfo},
+    {"adc", dbg_hw_info_adc},
+    {"power", dbg_hw_info_power},
+    {"button", dbg_hw_info_button},
+    {"audio", dbg_hw_info_audio},
+};
+
+bool dbg_hw_info(void)
+{
+    int nr_lines = lcd_getheight() / font_get(lcd_getfont())->height;
+    int len = ARRAYLEN(debug_screens);
+    int top_visible = 0;
+    int highlight = 0;
+    while(1)
+    {
+        int button = my_get_action(HZ / 10);
+        switch(button)
+        {
+            case ACT_NEXT:
+                highlight = (highlight + 1) % len;
+                break;
+            case ACT_PREV:
+                highlight = (highlight + len - 1) % len;
+                break;
+            case ACT_OK:
+                // if the screen returns true, advance to next screen
+                while(debug_screens[highlight].fn())
+                    highlight = (highlight + 1) % len;
+                lcd_setfont(FONT_UI);
+                break;
+            case ACT_CANCEL:
+                return false;
+        }
+        // adjust top visible if needed
+        if(highlight < top_visible)
+            top_visible = highlight;
+        else if(highlight >= top_visible + nr_lines)
+            top_visible = highlight - nr_lines + 1;
+
+        lcd_clear_display();
+
+        for(int i = top_visible; i < len && i < top_visible + nr_lines; i++)
+        {
+            if(i == highlight)
+            {
+                lcd_set_foreground(LCD_BLACK);
+                lcd_set_background(LCD_RGBPACK(255, 255, 0));
+            }
+            else
+            {
+                lcd_set_foreground(LCD_WHITE);
+                lcd_set_background(LCD_BLACK);
+            }
+            lcd_putsf(0, i - top_visible, "%s", debug_screens[i].name);
+        }
+        lcd_set_foreground(LCD_WHITE);
+        lcd_set_background(LCD_BLACK);
+
+        lcd_update();
+        yield();
+    }
+    return false;
+}
diff --git a/firmware/target/hosted/sonynwz/lcd-nwz.c b/firmware/target/hosted/sonynwz/lcd-nwz.c
new file mode 100644
index 0000000..bfcde3a
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/lcd-nwz.c
@@ -0,0 +1,200 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2016 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/fb.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include "lcd.h"
+#include "lcd-target.h"
+#include "backlight-target.h"
+
+static int fb_fd = 0;
+fb_data *nwz_framebuffer = 0; /* global variable, see lcd-target.h */
+enum
+{
+    FB_MP200, /* MP200 fb driver */
+    FB_EMXX, /* EMXX fb driver */
+    FB_OTHER, /* unknown */
+}nwz_fb_type;
+
+void identify_fb(const char *id)
+{
+    if(strcmp(id, "MP200 FB") == 0)
+        nwz_fb_type = FB_MP200;
+    else if(strcmp(id, "EMXX FB") == 0)
+        nwz_fb_type = FB_EMXX;
+    else
+        nwz_fb_type = FB_OTHER;
+    printf("lcd: fb id = '%s -> type = %d\n", id, nwz_fb_type);
+}
+
+/* select which page (0 or 1) to display, disable DSP, transparency and rotation */
+static int nwz_fb_set_page(int page)
+{
+    /* set page mode to no transparency and no rotation */
+    struct nwz_fb_image_info mode_info;
+    mode_info.tc_enable = 0;
+    mode_info.t_color = 0;
+    mode_info.alpha = 0;
+    mode_info.rot = 0;
+    mode_info.page = page;
+    mode_info.update = NWZ_FB_ONLY_2D_MODE;
+    if(ioctl(fb_fd, NWZ_FB_UPDATE, &mode_info) < 0)
+        return -1;
+    return 0;
+}
+
+/* make sure framebuffer is in standard state so rendering works */
+static int nwz_fb_set_standard_mode(void)
+{
+    /* disable timer (apparently useless with LCD) */
+    struct nwz_fb_update_timer update_timer;
+    update_timer.timerflag = NWZ_FB_TIMER_OFF;
+    update_timer.timeout = NWZ_FB_DEFAULT_TIMEOUT;
+    /* we don't check the result of the next ioctl() because it will fail in
+     * newer version of the driver, where the timer disapperared. */
+    ioctl(fb_fd, NWZ_FB_UPDATE_TIMER, &update_timer);
+    return nwz_fb_set_page(0);
+}
+
+void backlight_hw_brightness(int brightness)
+{
+    struct nwz_fb_brightness bl;
+    bl.level = brightness; /* brightness level: 0-5 */
+    bl.step = 25; /* number of hardware steps to do when changing: 1-100 (smooth transition) */
+    bl.period = NWZ_FB_BL_MIN_PERIOD; /* period in ms between steps when changing: >=10 */
+
+    ioctl(fb_fd, nwz_fb_type == FB_MP200 ? NWZ_FB_SET_BRIGHTNESS_MP200 : NWZ_FB_SET_BRIGHTNESS_EMXX, &bl);
+}
+
+bool backlight_hw_init(void)
+{
+    backlight_hw_brightness(DEFAULT_BRIGHTNESS_SETTING);
+    return true;
+}
+
+void backlight_hw_on(void)
+{
+#ifdef HAVE_LCD_ENABLE
+    lcd_enable(true); /* power on lcd + visible display */
+#endif
+    /* don't do anything special, the core will set the brightness */
+}
+
+void backlight_hw_off(void)
+{
+    /* there is no real on/off but we can set to 0 brightness */
+    backlight_hw_brightness(0);
+#ifdef HAVE_LCD_ENABLE
+    lcd_enable(false); /* power off visible display */
+#endif
+}
+
+void lcd_shutdown(void)
+{
+    munmap(nwz_framebuffer, FRAMEBUFFER_SIZE);
+    close(fb_fd);
+}
+
+void lcd_init_device(void)
+{
+    fb_fd = open("/dev/fb/0", O_RDWR);
+    if(fb_fd < 0)
+    {
+        perror("Cannot open framebuffer");
+        exit(0);
+    }
+
+    /* get fixed and variable information */
+    struct fb_fix_screeninfo finfo;
+    if(ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) < 0)
+    {
+        perror("Cannot read framebuffer fixed information");
+        exit(0);
+    }
+    identify_fb(finfo.id);
+    struct fb_var_screeninfo vinfo;
+    if(ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
+    {
+        perror("Cannot read framebuffer variable information");
+        exit(0);
+    }
+    /* check resolution and framebuffer size */
+    if(vinfo.xres != LCD_WIDTH || vinfo.yres != LCD_HEIGHT || vinfo.bits_per_pixel != LCD_DEPTH)
+    {
+        printf("Unexpected framebuffer resolution: %dx%dx%d\n", vinfo.xres,
+            vinfo.yres, vinfo.bits_per_pixel);
+        exit(0);
+    }
+    /* Note: we use a framebuffer size of width*height*bbp. We cannot trust the
+     * values returned by the driver for line_length */
+
+    /* map framebuffer */
+    nwz_framebuffer = mmap(0, FRAMEBUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
+    if((void *)nwz_framebuffer == (void *)-1)
+    {
+        perror("Cannot map framebuffer");
+        fflush(stdout);
+        execlp("/usr/local/bin/SpiderApp.of", "SpiderApp", NULL);
+        exit(0);
+    }
+    /* make sure rendering state is correct */
+    nwz_fb_set_standard_mode();
+}
+
+static void redraw(void)
+{
+    nwz_fb_set_page(0);
+}
+
+extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src,
+                                 int width, int height);
+
+void lcd_update(void)
+{
+    /* Copy the Rockbox framebuffer to the second framebuffer */
+    lcd_copy_buffer_rect(LCD_FRAMEBUF_ADDR(0, 0), FBADDR(0,0),
+                         LCD_WIDTH*LCD_HEIGHT, 1);
+    redraw();
+}
+
+void lcd_update_rect(int x, int y, int width, int height)
+{
+    fb_data *dst = LCD_FRAMEBUF_ADDR(x, y);
+    fb_data * src = FBADDR(x,y);
+
+    /* Copy part of the Rockbox framebuffer to the second framebuffer */
+    if (width < LCD_WIDTH)
+    {
+        /* Not full width - do line-by-line */
+        lcd_copy_buffer_rect(dst, src, width, height);
+    }
+    else
+    {
+        /* Full width - copy as one line */
+        lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1);
+    }
+    redraw();
+}
diff --git a/utils/nwztools/plattools/nwz_fb.h b/firmware/target/hosted/sonynwz/lcd-target.h
similarity index 85%
rename from utils/nwztools/plattools/nwz_fb.h
rename to firmware/target/hosted/sonynwz/lcd-target.h
index 9334b62..dcc4a61 100644
--- a/utils/nwztools/plattools/nwz_fb.h
+++ b/firmware/target/hosted/sonynwz/lcd-target.h
@@ -5,7 +5,6 @@
  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  *                     \/            \/     \/    \/            \/
- * $Id$
  *
  * Copyright (C) 2016 Amaury Pouly
  *
@@ -18,8 +17,12 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
-#ifndef __NWZ_FB_H__
-#define __NWZ_FB_H__
+
+#ifndef __LCD_TARGET_H__
+#define __LCD_TARGET_H__
+
+extern fb_data *nwz_framebuffer; /* see lcd-nwz.c */
+#define LCD_FRAMEBUF_ADDR(col, row) (nwz_framebuffer + (row)*LCD_WIDTH + (col))
 
 #define NWZ_FB_LCD_DEV  "/dev/fb/0"
 #define NWZ_FB_TV_DEV   "/dev/fb/1"
@@ -62,6 +65,7 @@
  *
  * FIXME I don't know what the timer is, it seems irrelevant for the LCD but
  * the OF uses it for TV, maybe this controls the refresh rate of the TV output?
+ * Also it only exists on early version (up to generation x60 roughly)
  *
  * On a side note, this information only applies to a subset of LCD types (the
  * LCD type can be gathered from icx_sysinfo):
@@ -126,14 +130,17 @@
 
 /* NOTE: I renamed those from Sony's header, because their original names were
  * pure crap */
-/* FIXME: Sony uses _IOR for NWZ_FB_WAIT_REFRESH but it should be _IORW */
-#define NWZ_FB_WAIT_REFRESH     _IORW(NWZ_FB_TYPE, 0x00, struct nwz_fb_status)
+#define NWZ_FB_WAIT_REFRESH     _IOR(NWZ_FB_TYPE, 0x00, struct nwz_fb_status)
 #define NWZ_FB_UPDATE           _IOW(NWZ_FB_TYPE, 0x01, struct nwz_fb_image_info)
 #define NWZ_FB_SET_MODE         _IOW(NWZ_FB_TYPE, 0x02, struct nwz_fb_image_info)
 #define NWZ_FB_GET_MODE         _IOR(NWZ_FB_TYPE, 0x03, struct nwz_fb_image_info)
+/* the timer only exits on MP200, it disappeared in EMXX and the ioctl fails */
 #define NWZ_FB_UPDATE_TIMER     _IOR(NWZ_FB_TYPE, 0x04, struct nwz_fb_update_timer)
-#define NWZ_FB_SET_BRIGHTNESS   _IOW(NWZ_FB_TYPE, 0x07, struct nwz_fb_brightness)
-#define NWZ_FB_GET_BRIGHTNESS   _IOR(NWZ_FB_TYPE, 0x08, struct nwz_fb_brightness)
+/* unfortnately, Sony change the ioctl numbers of those between MP200 and EMXX */
+#define NWZ_FB_SET_BRIGHTNESS_MP200 _IOW(NWZ_FB_TYPE, 0x07, struct nwz_fb_brightness)
+#define NWZ_FB_GET_BRIGHTNESS_MP200 _IOR(NWZ_FB_TYPE, 0x08, struct nwz_fb_brightness)
+#define NWZ_FB_SET_BRIGHTNESS_EMXX  _IOW(NWZ_FB_TYPE, 0x10, struct nwz_fb_brightness)
+#define NWZ_FB_GET_BRIGHTNESS_EMXX  _IOR(NWZ_FB_TYPE, 0x11, struct nwz_fb_brightness)
 
+#endif /* __LCD_TARGET_H__ */
 
-#endif /* __NWZ_FB_H__ */
diff --git a/firmware/target/hosted/sonynwz/nvp-nwz.c b/firmware/target/hosted/sonynwz/nvp-nwz.c
new file mode 100644
index 0000000..f7511d6
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/nvp-nwz.c
@@ -0,0 +1,119 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "nvp-nwz.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+static unsigned long find_model_id(void)
+{
+    /* try with the environment variable */
+    const char *mid = getenv("ICX_MODEL_ID");
+    if(mid == NULL)
+        return 0;
+    char *end;
+    unsigned long v = strtoul(mid, &end, 0);
+    if(*end)
+        return 0;
+    else
+        return v;
+}
+
+unsigned long nwz_get_model_id(void)
+{
+    static unsigned long model_id = 0xffffffff;
+    if(model_id == 0xffffffff)
+        model_id = find_model_id();
+    return model_id;
+}
+
+const char *nwz_get_model_name(void)
+{
+    for(int i = 0; i < NWZ_MODEL_COUNT; i++)
+        if(nwz_model[i].mid == nwz_get_model_id())
+            return nwz_model[i].name;
+    return NULL;
+}
+
+static int find_series(void)
+{
+    for(int i = 0; i < NWZ_SERIES_COUNT; i++)
+        for(int j = 0; j < nwz_series[i].mid_count; j++)
+            if(nwz_series[i].mid[j] == nwz_get_model_id())
+                return i;
+    return -1;
+}
+
+int nwz_get_series(void)
+{
+    static int series = -2;
+    if(series == -2)
+        series = find_series();
+    return series;
+}
+
+static nwz_nvp_index_t *get_nvp_index(void)
+{
+    static nwz_nvp_index_t *index = 0;
+    if(index == 0)
+    {
+        int series = nwz_get_series();
+        index = series < 0 ? 0 : nwz_series[series].nvp_index;
+    }
+    return index;
+}
+
+int nwz_nvp_read(enum nwz_nvp_node_t node, void *data)
+{
+    int size = nwz_nvp[node].size;
+    if(data == 0)
+        return size;
+    nwz_nvp_index_t *index = get_nvp_index();
+    if(index == 0 || (*index)[node] == NWZ_NVP_INVALID)
+        return -1;
+    char nvp_path[32];
+    snprintf(nvp_path, sizeof(nvp_path), "/dev/icx_nvp/%03d", (*index)[node]);
+    int fd = open(nvp_path, O_RDONLY);
+    if(fd < 0)
+        return -1;
+    int cnt = read(fd, data, size);
+    close(fd);
+    return cnt == size ? size : -1;
+}
+
+int nwz_nvp_write(enum nwz_nvp_node_t node, void *data)
+{
+    int size = nwz_nvp[node].size;
+    nwz_nvp_index_t *index = get_nvp_index();
+    if(index == 0 || (*index)[node] == NWZ_NVP_INVALID)
+        return -1;
+    char nvp_path[32];
+    snprintf(nvp_path, sizeof(nvp_path), "/dev/icx_nvp/%03d", (*index)[node]);
+    int fd = open(nvp_path, O_WRONLY);
+    if(fd < 0)
+        return -1;
+    int cnt = write(fd, data, size);
+    close(fd);
+    return cnt == size ? 0 : -1;
+}
diff --git a/firmware/target/hosted/sonynwz/nvp-nwz.h b/firmware/target/hosted/sonynwz/nvp-nwz.h
new file mode 100644
index 0000000..648e8b5
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/nvp-nwz.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __NVP_NWZ_H__
+#define __NVP_NWZ_H__
+
+#include "system.h"
+#include "nwz-db.h"
+
+/* get model ID */
+unsigned long nwz_get_model_id(void);
+/* get model NAME (ie NWZ-E463) */
+const char *nwz_get_model_name(void);
+/* return series (index into nwz_db) */
+int nwz_get_series(void);
+
+/* read a nvp node and return its size, if the data pointer is null, then simply
+ * return the size, return -1 on error */
+int nwz_nvp_read(enum nwz_nvp_node_t node, void *data);
+/* write a nvp node, return 0 on success and -1 on error, the size of the buffer
+ * must be the one returned by nwz_nvp_read */
+int nwz_nvp_write(enum nwz_nvp_node_t node, void *data);
+
+#endif /* __NVP_NWZ_H__ */
diff --git a/utils/nwztools/database/nwz_db.c b/firmware/target/hosted/sonynwz/nwz-db.c
similarity index 99%
rename from utils/nwztools/database/nwz_db.c
rename to firmware/target/hosted/sonynwz/nwz-db.c
index b65b49d..2aef1e3 100644
--- a/utils/nwztools/database/nwz_db.c
+++ b/firmware/target/hosted/sonynwz/nwz-db.c
@@ -20,7 +20,7 @@
 
 /** /!\ This file was automatically generated, DO NOT MODIFY IT DIRECTLY /!\ */
 
-#include "nwz_db.h"
+#include "nwz-db.h"
 
 struct nwz_model_info_t nwz_model[NWZ_MODEL_COUNT] =
 {
diff --git a/utils/nwztools/database/nwz_db.h b/firmware/target/hosted/sonynwz/nwz-db.h
similarity index 100%
rename from utils/nwztools/database/nwz_db.h
rename to firmware/target/hosted/sonynwz/nwz-db.h
diff --git a/firmware/target/hosted/sonynwz/nwz_audio.h b/firmware/target/hosted/sonynwz/nwz_audio.h
new file mode 100644
index 0000000..f186743
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/nwz_audio.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2016 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __NWZ_AUDIO_H__
+#define __NWZ_AUDIO_H__
+
+/* The Sony audio driver is a beast that involves several modules but eventually
+ * all boils down to the codec driver that handles everything, including ALSA
+ * controls. The volume, power up and other controls are doing through the ALSA
+ * interface. The driver also accepts private IOCTL on the hardware device
+ * (/dev/snd/hwC0D0). Finally some noice cancelling (NC) ioctl must be sent to
+ * the noican driver (/dev/icx_noican).
+ */
+
+/**
+ * Sound driver
+ */
+
+#define NWZ_AUDIO_TYPE  'a'
+
+#define NWZ_AUDIO_GET_CLRSTRO_VAL   _IOR(NWZ_AUDIO_TYPE, 0x04, struct nwz_cst_param_t)
+struct nwz_cst_param_t
+{
+    int no_ext_cbl;
+    int with_ext_cbl;
+};
+
+#define NEW_AUDIO_ALC_DATA_NUM      32
+
+enum nwz_audio_alc_types
+{
+    NWZ_ALC_TYPE_NONE = 0,  /* invalid        */
+    NWZ_ALC_TYPE_HP_DSP,    /* HP   / DSP ALC */
+    NWZ_ALC_TYPE_HP_ARM,    /* HP   / ARM ALC */
+    NWZ_ALC_TYPE_LINE_DSP,  /* LINE / DSP ALC */
+    NWZ_ALC_TYPE_LINE_ARM,  /* LINE / ARM ALC */
+    NWZ_ALC_TYPE_BT_DSP,    /* BT   / DSP ALC */
+    NWZ_ALC_TYPE_BT_ARM	    /* BT   / ARM ALC */
+};
+
+struct nwz_audio_alc_data_ex_t
+{
+    enum nwz_audio_alc_types type;
+    unsigned short table[NEW_AUDIO_ALC_DATA_NUM];
+};
+
+#define NWZ_AUDIO_GET_ALC_DATA_EX   _IOWR(NWZ_AUDIO_TYPE, 0x0f, struct nwz_audio_alc_data_ex_t)
+
+/**
+ * Noise cancelling driver
+ */
+
+#define NWZ_NC_DEV      "/dev/icx_noican"
+
+#define NWZ_NC_TYPE     'c'
+
+/* Enable/Disable NC switch */
+#define NWZ_NC_SET_SWITCH       _IOW(NWZ_NC_TYPE, 0x01, int)
+#define NWZ_NC_GET_SWITCH       _IOR(NWZ_NC_TYPE, 0x02, int)
+#define NWZ_NC_SWITCH_OFF       0
+#define NWZ_NC_SWITCH_ON        1
+
+/* Get NC HP status (whether it is NC capable or not) */
+#define NWZ_NC_GET_HP_STATUS    _IOR(NWZ_NC_TYPE, 0x09, int)
+#define NWZ_NC_HP_NMLHP        (0x1 << 0)
+#define NWZ_NC_HP_NCHP         (0x1 << 1)
+
+/* NC amp gain */
+#define NWZ_NC_SET_GAIN         _IOW(NWZ_NC_TYPE, 0x03, int)
+#define NWZ_NC_GET_GAIN         _IOR(NWZ_NC_TYPE, 0x04, int)
+#define NWZ_NC_GAIN_MIN         0
+#define NWZ_NC_GAIN_CENTER      15
+#define NWZ_NC_GAIN_MAX         30
+
+/* NC amp gain by value */
+#define NWZ_NC_SET_GAIN_VALUE   _IOW(NWZ_NC_TYPE, 0x05, int)
+#define NWZ_NC_GET_GAIN_VALUE   _IOR(NWZ_NC_TYPE, 0x06, int)
+#define NWZ_NC_MAKE_GAIN(l, r)  (((r) << 8) | (l))
+#define NWZ_NC_GET_L_GAIN(vol)  ((vol) & 0xff)
+#define NWZ_NC_GET_R_GAIN(vol)  (((vol) >> 8) & 0xff)
+
+/* Set/Get NC filter */
+#define NWZ_NC_SET_FILTER       _IOWR(NWZ_NC_TYPE, 0x07, int)
+#define NWZ_NC_GET_FILTER       _IOWR(NWZ_NC_TYPE, 0x08, int)
+#define NWZ_NC_FILTER_INDEX_0   0
+#define NWZ_NC_FILTER_INDEX_1   1
+#define NWZ_NC_FILTER_INDEX_2   2
+
+/* Get/Set HP type */
+#define NWZ_NC_SET_HP_TYPE      _IOWR(NWZ_NC_TYPE, 0x09, int)
+#define NWZ_NC_GET_HP_TYPE      _IOWR(NWZ_NC_TYPE, 0x0a, int)
+#define	NC_HP_TYPE_DEFAULT      0
+#define	NC_HP_TYPE_NWNC200      1
+
+#endif /* __NWZ_AUDIO_H__ */
diff --git a/utils/nwztools/plattools/nwz_keys.h b/firmware/target/hosted/sonynwz/nwz_keys.h
similarity index 98%
rename from utils/nwztools/plattools/nwz_keys.h
rename to firmware/target/hosted/sonynwz/nwz_keys.h
index 9fc5b4c..d2314d4 100644
--- a/utils/nwztools/plattools/nwz_keys.h
+++ b/firmware/target/hosted/sonynwz/nwz_keys.h
@@ -21,8 +21,6 @@
 #ifndef __NWZ_KEYS_H__
 #define __NWZ_KEYS_H__
 
-#define NWZ_KEY_NAME    "icx_key"
-
 /* The Sony icx_key driver reports keys via the /dev/input/event0 device and
  * abuses the standard struct input_event. The input_event.code is split into
  * two parts:
@@ -32,6 +30,9 @@
  * the first LED.
  */
 
+/* device name */
+#define NWZ_KEY_NAME    "icx_key"
+
 /* key code and mask */
 #define NWZ_KEY_MASK        0x1f
 #define NWZ_KEY_PLAY        0
diff --git a/firmware/target/hosted/sonynwz/nwz_sysinfo.h b/firmware/target/hosted/sonynwz/nwz_sysinfo.h
new file mode 100644
index 0000000..ef63c9a
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/nwz_sysinfo.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2017 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __NWZ_SYSINFO_H__
+#define __NWZ_SYSINFO_H__
+
+#define NWZ_SYSINFO_DEV     "/dev/icx_sysinfo"
+#define NWZ_SYSINFO_TYPE    's'
+
+#define NWZ_SYSINFO_GET_SYS_INFO _IOR(NWZ_SYSINFO_TYPE, 0, unsigned int *)
+#define NWZ_SYSINFO_PUT_SYS_INFO _IOW(NWZ_SYSINFO_TYPE, 1, unsigned int *)
+#define NWZ_SYSINFO_GET_BRD_REVS _IOR(NWZ_SYSINFO_TYPE, 2, unsigned int *)
+#define NWZ_SYSINFO_PUT_BRD_REVS _IOW(NWZ_SYSINFO_TYPE, 3, unsigned int *)
+#define NWZ_SYSINFO_GET_MEM_SIZE _IOR(NWZ_SYSINFO_TYPE, 4, unsigned int *)
+#define NWZ_SYSINFO_PUT_MEM_SIZE _IOW(NWZ_SYSINFO_TYPE, 5, unsigned int *)
+#define NWZ_SYSINFO_GET_BTT_TYPE _IOR(NWZ_SYSINFO_TYPE, 6, unsigned int *)
+#define NWZ_SYSINFO_PUT_BTT_TYPE _IOW(NWZ_SYSINFO_TYPE, 7, unsigned int *)
+#define NWZ_SYSINFO_GET_LCD_TYPE _IOR(NWZ_SYSINFO_TYPE, 8, unsigned int *)
+#define NWZ_SYSINFO_PUT_LCD_TYPE _IOW(NWZ_SYSINFO_TYPE, 9, unsigned int *)
+#define NWZ_SYSINFO_GET_NPE_TYPE _IOR(NWZ_SYSINFO_TYPE, 10, unsigned int *)
+#define NWZ_SYSINFO_PUT_NPE_TYPE _IOW(NWZ_SYSINFO_TYPE, 11, unsigned int *)
+#define NWZ_SYSINFO_GET_DAC_TYPE _IOR(NWZ_SYSINFO_TYPE, 12, unsigned int *)
+#define NWZ_SYSINFO_PUT_DAC_TYPE _IOW(NWZ_SYSINFO_TYPE, 13, unsigned int *)
+#define NWZ_SYSINFO_GET_NCR_TYPE _IOR(NWZ_SYSINFO_TYPE, 14, unsigned int *)
+#define NWZ_SYSINFO_PUT_NCR_TYPE _IOW(NWZ_SYSINFO_TYPE, 15, unsigned int *)
+#define NWZ_SYSINFO_GET_SPK_TYPE _IOR(NWZ_SYSINFO_TYPE, 16, unsigned int *)
+#define NWZ_SYSINFO_PUT_SPK_TYPE _IOW(NWZ_SYSINFO_TYPE, 17, unsigned int *)
+#define NWZ_SYSINFO_GET_FMT_TYPE _IOR(NWZ_SYSINFO_TYPE, 18, unsigned int *)
+#define NWZ_SYSINFO_PUT_FMT_TYPE _IOW(NWZ_SYSINFO_TYPE, 19, unsigned int *)
+#define NWZ_SYSINFO_GET_OSG_TYPE _IOR(NWZ_SYSINFO_TYPE, 20, unsigned int *)
+#define NWZ_SYSINFO_PUT_OSG_TYPE _IOW(NWZ_SYSINFO_TYPE, 21, unsigned int *)
+#define NWZ_SYSINFO_GET_WAB_TYPE _IOR(NWZ_SYSINFO_TYPE, 22, unsigned int *)
+#define NWZ_SYSINFO_PUT_WAB_TYPE _IOW(NWZ_SYSINFO_TYPE, 23, unsigned int *)
+#define NWZ_SYSINFO_GET_TSP_TYPE _IOR(NWZ_SYSINFO_TYPE, 24, unsigned int *)
+#define NWZ_SYSINFO_PUT_TSP_TYPE _IOW(NWZ_SYSINFO_TYPE, 25, unsigned int *)
+#define NWZ_SYSINFO_GET_GSR_TYPE _IOR(NWZ_SYSINFO_TYPE, 26, unsigned int *)
+#define NWZ_SYSINFO_PUT_GSR_TYPE _IOW(NWZ_SYSINFO_TYPE, 27, unsigned int *)
+#define NWZ_SYSINFO_GET_MIC_TYPE _IOR(NWZ_SYSINFO_TYPE, 28, unsigned int *)
+#define NWZ_SYSINFO_PUT_MIC_TYPE _IOW(NWZ_SYSINFO_TYPE, 29, unsigned int *)
+#define NWZ_SYSINFO_GET_WMP_TYPE _IOR(NWZ_SYSINFO_TYPE, 30, unsigned int *)
+#define NWZ_SYSINFO_PUT_WMP_TYPE _IOW(NWZ_SYSINFO_TYPE, 31, unsigned int *)
+#define NWZ_SYSINFO_GET_SMS_TYPE _IOR(NWZ_SYSINFO_TYPE, 32, unsigned int *)
+#define NWZ_SYSINFO_PUT_SMS_TYPE _IOW(NWZ_SYSINFO_TYPE, 33, unsigned int *)
+#define NWZ_SYSINFO_GET_HCG_TYPE _IOR(NWZ_SYSINFO_TYPE, 34, unsigned int *)
+#define NWZ_SYSINFO_PUT_HCG_TYPE _IOW(NWZ_SYSINFO_TYPE, 35, unsigned int *)
+#define NWZ_SYSINFO_GET_RTC_TYPE _IOR(NWZ_SYSINFO_TYPE, 36, unsigned int *)
+#define NWZ_SYSINFO_PUT_RTC_TYPE _IOW(NWZ_SYSINFO_TYPE, 37, unsigned int *)
+#define NWZ_SYSINFO_GET_SDC_TYPE _IOR(NWZ_SYSINFO_TYPE, 38, unsigned int *)
+#define NWZ_SYSINFO_PUT_SDC_TYPE _IOW(NWZ_SYSINFO_TYPE, 39, unsigned int *)
+#define NWZ_SYSINFO_GET_SCG_TYPE _IOR(NWZ_SYSINFO_TYPE, 40, unsigned int *)
+#define NWZ_SYSINFO_PUT_SCG_TYPE _IOW(NWZ_SYSINFO_TYPE, 41, unsigned int *)
+#define NWZ_SYSINFO_GET_NFC_TYPE _IOR(NWZ_SYSINFO_TYPE, 42, unsigned int *)
+#define NWZ_SYSINFO_PUT_NFC_TYPE _IOW(NWZ_SYSINFO_TYPE, 43, unsigned int *)
+
+#endif /* __NWZ_SYSINFO_H__ */
diff --git a/utils/nwztools/plattools/nwz_ts.h b/firmware/target/hosted/sonynwz/nwz_ts.h
similarity index 100%
rename from utils/nwztools/plattools/nwz_ts.h
rename to firmware/target/hosted/sonynwz/nwz_ts.h
diff --git a/firmware/target/hosted/sonynwz/power-nwz.c b/firmware/target/hosted/sonynwz/power-nwz.c
new file mode 100644
index 0000000..a5b19d6
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/power-nwz.c
@@ -0,0 +1,208 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2016 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "system.h"
+#include "power-nwz.h"
+#include "button-target.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <sys/reboot.h>
+
+static int power_fd = -1; /* file descriptor */
+
+void power_init(void)
+{
+    power_fd = open(NWZ_POWER_DEV, O_RDWR);
+}
+
+void power_close(void)
+{
+    close(power_fd);
+}
+
+int nwz_power_get_status(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_STATUS, &status) < 0)
+        return -1;
+    return status;
+}
+
+static int nwz_power_adval_to_mv(int adval, int ad_base)
+{
+    if(adval == -1)
+        return -1;
+    /* the AD base corresponds to the millivolt value if adval was 255 */
+    return (adval * ad_base) / 255;
+}
+
+int nwz_power_get_vbus_adval(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_VBUS_ADVAL, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_get_vbus_voltage(void)
+{
+    return nwz_power_adval_to_mv(nwz_power_get_vbus_adval(), NWZ_POWER_AD_BASE_VBUS);
+}
+
+int nwz_power_get_vbus_limit(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_VBUS_LIMIT, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_get_charge_switch(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_CHARGE_SWITCH, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_get_charge_current(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_CHARGE_CURRENT, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_get_battery_gauge(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_BAT_GAUGE, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_get_battery_adval(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_BAT_ADVAL, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_get_battery_voltage(void)
+{
+    return nwz_power_adval_to_mv(nwz_power_get_battery_adval(), NWZ_POWER_AD_BASE_VBAT);
+}
+
+int nwz_power_get_vbat_adval(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_VBAT_ADVAL, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_get_vbat_voltage(void)
+{
+    return nwz_power_adval_to_mv(nwz_power_get_vbat_adval(), NWZ_POWER_AD_BASE_VBAT);
+}
+
+int nwz_power_get_sample_count(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_SAMPLE_COUNT, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_get_vsys_adval(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_VSYS_ADVAL, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_get_vsys_voltage(void)
+{
+    return nwz_power_adval_to_mv(nwz_power_get_vsys_adval(), NWZ_POWER_AD_BASE_VSYS);
+}
+
+int nwz_power_get_acc_charge_mode(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_GET_ACCESSARY_CHARGE_MODE, &status) < 0)
+        return -1;
+    return status;
+}
+
+int nwz_power_is_fully_charged(void)
+{
+    int status;
+    if(ioctl(power_fd, NWZ_POWER_IS_FULLY_CHARGED, &status) < 0)
+        return -1;
+    return status;
+}
+
+static int write_string_to_file(const char *file, const char *msg)
+{
+    int fd = open(file, O_WRONLY);
+    if(fd < 0)
+        return -1;
+    const int len = strlen(msg);
+    int res = write(fd, msg, len);
+    close(fd);
+    return res == len ? 0 : -1;
+}
+
+int do_nwz_power_suspend(void)
+{
+    /* older devices use /proc/pm, while the new one use the standard sys file */
+    if(write_string_to_file("/proc/pm", "S3") == 0)
+        return 0;
+    return write_string_to_file("/sys/power/state", "mem");
+}
+
+int nwz_power_suspend(void)
+{
+    int ret = do_nwz_power_suspend();
+    /* the button driver tracks button status using events, but the kernel does
+     * not generate an event if a key is changed during suspend, so make sure we
+     * reload as much information as possible */
+    nwz_button_reload_after_suspend();
+    return ret;
+}
+
+int nwz_power_shutdown(void)
+{
+    sync(); /* man page advises to sync to avoid data loss */
+    return reboot(RB_POWER_OFF);
+}
+
+int nwz_power_restart(void)
+{
+    sync(); /* man page advises to sync to avoid data loss */
+    return reboot(RB_AUTOBOOT);
+}
diff --git a/utils/nwztools/plattools/nwz_power.h b/firmware/target/hosted/sonynwz/power-nwz.h
similarity index 76%
rename from utils/nwztools/plattools/nwz_power.h
rename to firmware/target/hosted/sonynwz/power-nwz.h
index 7b325ce..965013a 100644
--- a/utils/nwztools/plattools/nwz_power.h
+++ b/firmware/target/hosted/sonynwz/power-nwz.h
@@ -18,8 +18,10 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
-#ifndef __NWZ_POWER_H__
-#define __NWZ_POWER_H__
+#ifndef __POWER_NWZ_H__
+#define __POWER_NWZ_H__
+
+#include "power.h"
 
 /** power */
 
@@ -112,4 +114,42 @@
 #define ICX_PMINFO_FACTOR_KEY_PAD  0x00001000 /* keypad */
 #define ICX_PMINFO_FACTOR_KEY_CODE 0x00000FFF /* keycode */
 
-#endif /* __NWZ_POWER_H__ */
+void power_init(void);
+/* get power status (return -1 on error, bitmap on success) */
+int nwz_power_get_status(void);
+/* get vbus adval (or -1 on error) */
+int nwz_power_get_vbus_adval(void);
+/* get vbus voltage in mV (or -1 on error) */
+int nwz_power_get_vbus_voltage(void);
+/* get vbus current limit (or -1 on error) */
+int nwz_power_get_vbus_limit(void);
+/* get charge switch (or -1 on error) */
+int nwz_power_get_charge_switch(void);
+/* get charge current (or -1 on error) */
+int nwz_power_get_charge_current(void);
+/* get battery gauge (or -1 on error) */
+int nwz_power_get_battery_gauge(void);
+/* get battery adval (or -1 on error) */
+int nwz_power_get_battery_adval(void);
+/* get battery voltage in mV (or -1 on error) */
+int nwz_power_get_battery_voltage(void);
+/* get vbat adval (or -1 on error) */
+int nwz_power_get_vbat_adval(void);
+/* get vbat voltage (or -1 on error) */
+int nwz_power_get_vbat_voltage(void);
+/* get sample count (or -1 on error) */
+int nwz_power_get_sample_count(void);
+/* get vsys adval (or -1 on error) */
+int nwz_power_get_vsys_adval(void);
+/* get vsys voltage in mV (or -1 on error) */
+int nwz_power_get_vsys_voltage(void);
+/* get accessory charge mode */
+int nwz_power_get_acc_charge_mode(void);
+/* is battery fully charged? (or -1 on error) */
+int nwz_power_is_fully_charged(void);
+/* change power state (-1 on error, 0 otherwise)*/
+int nwz_power_suspend(void);
+int nwz_power_shutdown(void);
+int nwz_power_restart(void);
+
+#endif /* __POWER_NWZ_H__ */
diff --git a/firmware/target/hosted/sonynwz/powermgmt-nwz.c b/firmware/target/hosted/sonynwz/powermgmt-nwz.c
new file mode 100644
index 0000000..ce5f251
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/powermgmt-nwz.c
@@ -0,0 +1,69 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2016 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "powermgmt.h"
+#include "power.h"
+#include "power-nwz.h"
+
+const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
+{
+    3470
+};
+
+/* the OF shuts down at this voltage */
+const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
+{
+    3450
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
+{
+    { 3450, 3502, 3550, 3587, 3623, 3669, 3742, 3836, 3926, 4026, 4200 }
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
+const unsigned short const percent_to_volt_charge[11] =
+{
+      3450, 3670, 3721, 3751, 3782, 3821, 3876, 3941, 4034, 4125, 4200
+};
+
+unsigned int power_input_status(void)
+{
+    unsigned pwr = 0;
+    int sts = nwz_power_get_status();
+    if(sts & NWZ_POWER_STATUS_VBUS_DET)
+        pwr |= POWER_INPUT_USB_CHARGER;
+    if(sts & NWZ_POWER_STATUS_AC_DET)
+        pwr |= POWER_INPUT_MAIN_CHARGER;
+    return pwr;
+}
+
+int _battery_voltage(void)
+{
+    /* the raw voltage is unstable on some devices, so use the average provided
+     * by the driver */
+    return nwz_power_get_battery_voltage();
+}
+
+bool charging_state(void)
+{
+    return (nwz_power_get_status() & NWZ_POWER_STATUS_CHARGE_STATUS) ==
+        NWZ_POWER_STATUS_CHARGE_STATUS_CHARGING;
+}
diff --git a/firmware/target/hosted/sonynwz/sonynwz.make b/firmware/target/hosted/sonynwz/sonynwz.make
new file mode 100644
index 0000000..6c58e1a
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/sonynwz.make
@@ -0,0 +1,82 @@
+#             __________               __   ___.
+#   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+#   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+#   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+#   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+#                     \/            \/     \/    \/            \/
+# $Id$
+#
+
+INCLUDES += -I$(FIRMDIR)/include -I$(FIRMDIR)/export $(TARGET_INC) -I$(BUILDDIR) -I$(APPSDIR)
+
+SIMFLAGS += $(INCLUDES) $(DEFINES) -DHAVE_CONFIG_H $(GCCOPTS)
+
+# bootloader build is sligtly different
+ifneq (,$(findstring bootloader,$(APPSDIR)))
+
+SRC += $(call preprocess, $(APPSDIR)/SOURCES)
+CLEANOBJS += $(BUILDDIR)/bootloader.*
+
+endif #bootloader
+
+.SECONDEXPANSION: # $$(OBJ) is not populated until after this
+
+# bootloader build is sligtly different
+ifneq (,$(findstring bootloader,$(APPSDIR)))
+
+# We install a second font along the bootloader because sysfont is too small
+# for our purpose
+BL_FONT = $(ROOTDIR)/fonts/27-Adobe-Helvetica.bdf
+
+# Limits for the bootloader sysfont: ASCII
+BL_MAXCHAR = 127
+
+# Function that adds a single file to a tar and explicitely set the name
+# in the archive (which can be completely different from the original filename)
+# their devices
+# arguments:
+#   $(1) = tar file
+#   $(2) = archive file name
+#   $(3) = file to add
+tar_add_file = \
+    tar -Prf $(1) --transform="s|.*|$(strip $(2))|" $(3)
+
+$(BUILDDIR)/bootloader.fnt: $(BL_FONT) $(TOOLS)
+	$(call PRINTS,CONVBDF $(subst $(ROOTDIR)/,,$<))$(TOOLSDIR)/convbdf -l $(MAXCHAR) -f -o $@ $<
+
+$(BUILDDIR)/bootloader.elf : $$(OBJ) $(FIRMLIB) $(CORE_LIBS)
+	$(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -o $@ $(OBJ) \
+		-L$(BUILDDIR)/firmware -lfirmware \
+		-L$(BUILDDIR)/lib $(call a2lnk,$(CORE_LIBS)) \
+		$(LDOPTS) $(GLOBAL_LDOPTS) -Wl,--gc-sections -Wl,-Map,$(BUILDDIR)/bootloader.map
+
+$(BUILDDIR)/$(BINARY): $(BUILDDIR)/bootloader.elf $(BUILDDIR)/bootloader.fnt
+# NOTE: the install script will call a command like
+#   tar -C $(ROOTFS_MOUNT_POINT) -f bootloader.tar
+# thus the names in the archive must be of the form ./absolute/path
+#
+# NOTE 2: Sony uses unusual user IDs (500 on somes devices, 1002 on others)
+# so make sure the files are readable/executable by anyone
+	$(SILENT)rm -rf $(BUILDDIR)/bootloader.tar
+	$(SILENT)$(call tar_add_file, $(BUILDDIR)/bootloader.tar,\
+		./usr/local/bin/SpiderApp, \
+		$(BUILDDIR)/bootloader.elf)
+	$(SILENT)$(call tar_add_file, $(BUILDDIR)/bootloader.tar, \
+		./usr/local/share/rockbox/bootloader.fnt, \
+		$(BUILDDIR)/bootloader.fnt)
+	$(call PRINTS,SCRAMBLE $(notdir $@))$(MKFIRMWARE) $(BUILDDIR)/bootloader.tar $@;
+
+else # bootloader
+
+$(BUILDDIR)/rockbox.elf : $$(OBJ) $(FIRMLIB) $(VOICESPEEXLIB) $(CORE_LIBS)
+	$(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -o $@ $(OBJ) \
+		-L$(BUILDDIR)/firmware -lfirmware \
+		-L$(RBCODEC_BLD)/codecs $(call a2lnk, $(VOICESPEEXLIB)) \
+		-L$(BUILDDIR)/lib $(call a2lnk,$(CORE_LIBS)) \
+		$(LDOPTS) $(GLOBAL_LDOPTS) -Wl,-Map,$(BUILDDIR)/rockbox.map
+
+$(BUILDDIR)/rockbox.sony : $(BUILDDIR)/rockbox.elf
+	$(call PRINTS,OC $(@F))$(call objcopy,$^,$@)
+
+endif # bootloader
+
diff --git a/firmware/target/hosted/sonynwz/system-nwz.c b/firmware/target/hosted/sonynwz/system-nwz.c
new file mode 100644
index 0000000..c804c5a
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/system-nwz.c
@@ -0,0 +1,204 @@
+/***************************************************************************
+ *             __________               __   ___.                  
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___  
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /  
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <   
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \  
+ *                     \/            \/     \/    \/            \/ 
+ *
+ * Copyright (C) 2016 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ucontext.h>
+#include <string.h>
+#include "system.h"
+#include "lcd.h"
+#include "font.h"
+#include "logf.h"
+#include "system.h"
+#include "backlight-target.h"
+#include "button.h"
+#include "adc.h"
+#include "power.h"
+#include "power-nwz.h"
+#include <backtrace.h>
+#include <stdio.h>
+
+static const char **kern_mod_list;
+
+void power_off(void)
+{
+    exit(0);
+}
+
+static void compute_kern_mod_list(void)
+{
+    /* create empty list */
+    kern_mod_list = malloc(sizeof(const char **));
+    kern_mod_list[0] = NULL;
+    /* read from proc file system */
+    FILE *f = fopen("/proc/modules", "r");
+    if(f == NULL)
+    {
+        printf("Cannot open /proc/modules");
+        return;
+    }
+    for(int i = 0;; i++)
+    {
+        /* the last entry of the list points to NULL so getline() will allocate
+         * some memory */
+        size_t n;
+        if(getline((char **)&kern_mod_list[i], &n, f) < 0)
+        {
+            /* make sure last entry is NULL and stop */
+            kern_mod_list[i] = NULL;
+            break;
+        }
+        /* grow array */
+        kern_mod_list = realloc(kern_mod_list, (i + 2) * sizeof(const char **));
+        /* and fill last entry with NULL */
+        kern_mod_list[i + 1] = NULL;
+        /* parse line to only keep module name */
+        char *p = strchr(kern_mod_list[i], ' ');
+        if(p != NULL)
+            *p = 0; /* stop at first blank */
+    }
+    fclose(f);
+}
+
+static void print_kern_mod_list(void)
+{
+    printf("Kernel modules:\n");
+    const char **p = kern_mod_list;
+    while(*p)
+        printf("  %s\n", *p++);
+}
+
+/* to make thread-internal.h happy */
+uintptr_t *stackbegin;
+uintptr_t *stackend;
+
+static void nwz_sig_handler(int sig, siginfo_t *siginfo, void *context)
+{
+    /* safe guard variable - we call backtrace() only on first
+     * UIE call. This prevent endless loop if backtrace() touches
+     * memory regions which cause abort
+     */
+    static bool triggered = false;
+
+    lcd_set_backdrop(NULL);
+    lcd_set_drawmode(DRMODE_SOLID);
+    lcd_set_foreground(LCD_BLACK);
+    lcd_set_background(LCD_WHITE);
+    unsigned line = 0;
+
+    lcd_setfont(FONT_SYSFIXED);
+    lcd_set_viewport(NULL);
+    lcd_clear_display();
+
+    /* get context info */
+    ucontext_t *uc = (ucontext_t *)context;
+    unsigned long pc = uc->uc_mcontext.arm_pc;
+    unsigned long sp = uc->uc_mcontext.arm_sp;
+
+    lcd_putsf(0, line++, "%s at %08x", strsignal(sig), pc);
+
+    if(sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS || sig == SIGTRAP)
+        lcd_putsf(0, line++, "address 0x%08x", siginfo->si_addr);
+
+    if(!triggered)
+    {
+        triggered = true;
+        rb_backtrace(pc, sp, &line);
+    }
+
+#ifdef ROCKBOX_HAS_LOGF
+    lcd_putsf(0, line++, "logf:");
+    logf_panic_dump(&line);
+#endif
+
+    lcd_update();
+
+    system_exception_wait(); /* If this returns, try to reboot */
+    system_reboot();
+    while (1);       /* halt */
+}
+
+void system_init(void)
+{
+    int *s;
+    /* fake stack, to make thread-internal.h happy */
+    stackbegin = stackend = (uintptr_t*)&s;
+    /* catch some signals for easier debugging */
+    struct sigaction sa;
+    sigfillset(&sa.sa_mask);
+    sa.sa_flags = SA_SIGINFO;
+    sa.sa_sigaction = &nwz_sig_handler;
+    sigaction(SIGILL, &sa, NULL);
+    sigaction(SIGABRT, &sa, NULL);
+    sigaction(SIGFPE, &sa, NULL);
+    sigaction(SIGSEGV, &sa, NULL);
+    sigaction(SIGPIPE, &sa, NULL);
+    sigaction(SIGTERM, &sa, NULL);
+    sigaction(SIGBUS, &sa, NULL);
+    sigaction(SIGTERM, &sa, NULL);
+    compute_kern_mod_list();
+    print_kern_mod_list();
+    /* some init not done on hosted targets */
+    adc_init();
+    power_init();
+}
+
+
+void system_reboot(void)
+{
+    power_off();
+}
+
+void system_exception_wait(void)
+{
+    backlight_hw_on();
+    backlight_hw_brightness(DEFAULT_BRIGHTNESS_SETTING);
+    /* wait until button press and release */
+    while(button_read_device() != 0) {}
+    while(button_read_device() == 0) {}
+    while(button_read_device() != 0) {}
+    while(button_read_device() == 0) {}
+}
+
+int hostfs_init(void)
+{
+    return 0;
+}
+
+int hostfs_flush(void)
+{
+    sync();
+    return 0;
+}
+
+const char **nwz_get_kernel_module_list(void)
+{
+    return kern_mod_list;
+}
+
+bool nwz_is_kernel_module_loaded(const char *name)
+{
+    const char **p = kern_mod_list;
+    while(*p)
+        if(strcmp(*p++, name) == 0)
+            return true;
+    return false;
+}
diff --git a/firmware/target/hosted/sonynwz/system-target.h b/firmware/target/hosted/sonynwz/system-target.h
new file mode 100644
index 0000000..0e3ed5f
--- /dev/null
+++ b/firmware/target/hosted/sonynwz/system-target.h
@@ -0,0 +1,34 @@
+/***************************************************************************
+ *             __________               __   ___.                  
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___  
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /  
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <   
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \  
+ *                     \/            \/     \/    \/            \/ 
+ * $Id$
+ *
+ * Copyright (C) 2016 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __SYSTEM_TARGET_H__
+#define __SYSTEM_TARGET_H__
+
+#include "kernel-unix.h"
+#include "system-hosted.h"
+
+#define NEED_GENERIC_BYTESWAPS
+
+/* get list of loaded kernel modules (computed once at init time), list is NULL
+ * terminated */
+const char **nwz_get_kernel_module_list(void);
+bool nwz_is_kernel_module_loaded(const char *name);
+
+#endif /* __SYSTEM_TARGET_H__ */
diff --git a/lib/unwarminder/SOURCES b/lib/unwarminder/SOURCES
index b2e5e3e..87c7d69 100644
--- a/lib/unwarminder/SOURCES
+++ b/lib/unwarminder/SOURCES
@@ -1,4 +1,4 @@
-backtrace.c
+backtrace-unwarminder.c
 get_sp.S
 unwarm_arm.c
 unwarm.c
diff --git a/lib/unwarminder/backtrace.c b/lib/unwarminder/backtrace-unwarminder.c
similarity index 98%
rename from lib/unwarminder/backtrace.c
rename to lib/unwarminder/backtrace-unwarminder.c
index 683d2fd..7808a1f 100644
--- a/lib/unwarminder/backtrace.c
+++ b/lib/unwarminder/backtrace-unwarminder.c
@@ -106,7 +106,7 @@
     return TRUE;
 }
 
-void backtrace(int pcAddr, int spAddr, unsigned *line)
+void rb_backtrace(int pcAddr, int spAddr, unsigned *line)
 {
     lcd_putsf(0, (*line)++, "pc:%08x sp:%08x", pcAddr, spAddr);
     lcd_update();
diff --git a/lib/unwarminder/backtrace.h b/lib/unwarminder/backtrace-unwarminder.h
similarity index 96%
rename from lib/unwarminder/backtrace.h
rename to lib/unwarminder/backtrace-unwarminder.h
index 3bf3eb5..e08f725 100644
--- a/lib/unwarminder/backtrace.h
+++ b/lib/unwarminder/backtrace-unwarminder.h
@@ -49,7 +49,7 @@
 
 extern const UnwindCallbacks cliCallbacks;
 
-void backtrace(int pcAddr, int spAddr, unsigned *line);
+void rb_backtrace(int pcAddr, int spAddr, unsigned *line);
 
 #endif
 
diff --git a/lib/unwarminder/unwarminder.make b/lib/unwarminder/unwarminder.make
index 5093156..563c5ca 100644
--- a/lib/unwarminder/unwarminder.make
+++ b/lib/unwarminder/unwarminder.make
@@ -16,6 +16,7 @@
 CORE_LIBS += $(UNWARMLIB)
 
 INCLUDES += -I$(UNWARMLIB_DIR)
+DEFINES += -DBACKTRACE_UNWARMINDER
 
 $(UNWARMLIB): $(UNWARMLIB_OBJ)
 	$(SILENT)$(shell rm -f $@)
diff --git a/rbutil/mknwzboot/Makefile b/rbutil/mknwzboot/Makefile
new file mode 100644
index 0000000..9530ac3
--- /dev/null
+++ b/rbutil/mknwzboot/Makefile
@@ -0,0 +1,35 @@
+#             __________               __   ___.
+#   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+#   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+#   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+#   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+#                     \/            \/     \/    \/            \/
+
+# We use the SB code available in the Rockbox utils/sbtools directory
+UPGTOOLS_DIR=../../utils/nwztools/upgtools/
+CFLAGS += -I$(UPGTOOLS_DIR) -Wall
+# std=gnu99 is required by MinGW on Windows (c99 is sufficient for Linux / MXE)
+CFLAGS += -std=gnu99 -g -O3
+# dependencies
+# FIXME make it work for windows and maybe embed crypto++
+LDOPTS += `pkg-config --libs libcrypto++`
+
+OUTPUT = mknwzboot
+
+# inputs for lib
+UPGTOOLS_SOURCES = misc.c upg.c fwp.c mg.cpp md5.cpp
+LIBSOURCES := mknwzboot.c install_script.c \
+	      $(addprefix $(UPGTOOLS_DIR),$(UPGTOOLS_SOURCES))
+# inputs for binary only
+SOURCES := $(LIBSOURCES) main.c
+# dependencies for binary
+EXTRADEPS := 
+
+include ../libtools.make
+
+install_script.c install_script.h: install_script.sh $(BIN2C)
+	$(BIN2C) install_script.sh install_script
+
+# explicit dependencies on install_script.{c,h} and mknwzboot.h
+$(OBJDIR)mknwzboot.o: install_script.h install_script.c mknwzboot.h
+$(OBJDIR)main.o: install_script.h install_script.c main.c mknwzboot.h
diff --git a/rbutil/mknwzboot/install_script.sh b/rbutil/mknwzboot/install_script.sh
new file mode 100644
index 0000000..18296d2
--- /dev/null
+++ b/rbutil/mknwzboot/install_script.sh
@@ -0,0 +1,142 @@
+#!/bin/sh
+
+# The updater script on the NWZ has a major bug/feature:
+# it does NOT clear the update flag if the update scrit fails
+# thus causing a update/reboot loop and a bricked device
+# always clear to make sure we don't end up being screwed
+nvpflag fup 0xFFFFFFFF
+
+# go to /tmp
+cd /tmp
+
+# get content partition path
+CONTENTS="/contents"
+CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'`
+
+lcdmsg -c -f /usr/local/bin/font_08x12.bmp -l 0,3 "Contents partition:\n$CONTENTS_PART"
+
+# We need to remount the contents partition in read-write mode be able to
+# write something on it
+lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,6 "Remount $CONTENTS rw"
+mount -o remount,rw $CONTENTS_PART $CONTENTS
+if [ "$?" != 0 ]; then
+    lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: remount failed"
+    sleep 3
+    exit 0
+fi
+
+# redirect all output to a log file
+exec > "$CONTENTS/install_dualboot_log.txt" 2>&1
+
+# import constants
+. /install_script/constant.txt
+_UPDATE_FN_=`nvpstr ufn`
+ROOTFS_TMP_DIR=/tmp/rootfs
+SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp
+
+# mount root partition
+lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,7 "Mount root filesystem"
+mkdir $ROOTFS_TMP_DIR
+if [ "$?" != 0 ]; then
+    lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: mkdir failed"
+    sleep 3
+    exit 0
+fi
+
+# If there is an ext4 mounter, try it. Otherwise or on failure, try ext3 and
+# then ext2.
+# NOTE some platforms probably use an mtd and this might need some fixing
+if [ -e /usr/local/bin/icx_mount.ext4 ]; then
+    /usr/local/bin/icx_mount.ext4 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
+else
+    false
+fi
+if [ "$?" != 0 ]; then
+    mount -t ext3 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
+fi
+if [ "$?" != 0 ]; then
+    mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
+fi
+if [ "$?" != 0 ]; then
+    lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: mount failed"
+    sleep 3
+    exit 0
+fi
+
+# rename the previous main application unless there is already a copy
+lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,8 "Backup OF"
+if [ ! -e $SPIDERAPP_PATH.of ]; then
+    mv $SPIDERAPP_PATH $SPIDERAPP_PATH.of
+fi
+
+# extract our payload: the second file in the upgrade is a tar file
+# the files in the archive have paths of the form ./absolute/path and we extract
+# it at the rootfs mount it, so it can create/overwrite any file
+#
+# we need a small trick here: we want to pipe directly the output of the decryption
+# tool to tar, to avoid using space in /tmp/ or on the user partition
+lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,9 "Install rockbox"
+FIFO_FILE=/tmp/rb.fifo
+mkfifo $FIFO_FILE
+if [ "$?" != 0 ]; then
+    umount "$ROOTFS_TMP_DIR"
+    lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: cannot create fifo"
+    sleep 3
+    exit 0
+fi
+fwpchk -f /contents/$_UPDATE_FN_.UPG -c -1 $FIFO_FILE &
+#tar -tvf $FIFO_FILE
+tar -C $ROOTFS_TMP_DIR -xvf $FIFO_FILE
+if [ "$?" != 0 ]; then
+    umount "$ROOTFS_TMP_DIR"
+    lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: extraction failed"
+    sleep 3
+    exit 0
+fi
+# wait for fwpchk
+wait
+if [ "$?" != 0 ]; then
+    umount "$ROOTFS_TMP_DIR"
+    lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: no file to extract"
+    sleep 3
+    exit 0
+fi
+
+# create a symlink from /.rockbox to /contents/.rockbox (see dualboot code
+# for why)
+lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,10 "Create rockbox symlink"
+rm -f "$ROOTFS_TMP_DIR/.rockbox"
+ln -s "$CONTENTS/.rockbox" "$ROOTFS_TMP_DIR/.rockbox"
+if [ "$?" != 0 ]; then
+    umount "$ROOTFS_TMP_DIR"
+    lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: cannot create rockbox symlink"
+    sleep 3
+    exit 0
+fi
+
+# unmount root partition
+lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,11 "Unmount root filesystem"
+sync
+if [ "$?" != 0 ]; then
+    umount "$ROOTFS_TMP_DIR"
+    lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: sync failed"
+    sleep 3
+    exit 0
+fi
+
+umount $ROOTFS_TMP_DIR
+if [ "$?" != 0 ]; then
+    lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: umount failed"
+    sleep 3
+    exit 0
+fi
+
+# Success screen
+lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "Rebooting in 3 seconds."
+sleep 3
+sync
+
+echo "Installation successful"
+# finish
+exit 0
+ 
diff --git a/rbutil/mknwzboot/main.c b/rbutil/mknwzboot/main.c
new file mode 100644
index 0000000..a36c24e
--- /dev/null
+++ b/rbutil/mknwzboot/main.c
@@ -0,0 +1,105 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2011 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "mknwzboot.h"
+
+static void usage(void)
+{
+    printf("Usage: mknwzboot [options | file]...\n");
+    printf("Options:\n");
+    printf("  -h/--help   Display this message\n");
+    printf("  -o <file>   Set output file\n");
+    printf("  -b <file>   Set boot file\n");
+    printf("  -d/--debug  Enable debug output\n");
+    printf("  -x          Dump device informations\n");
+    exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+    char *outfile = NULL;
+    char *bootfile = NULL;
+    bool debug = false;
+
+    if(argc == 1)
+        usage();
+
+    while(1)
+    {
+        static struct option long_options[] =
+        {
+            {"help", no_argument, 0, 'h'},
+            {"out-file", required_argument, 0, 'o'},
+            {"boot-file", required_argument, 0, 'b'},
+            {"debug", no_argument, 0, 'd'},
+            {"dev-info", no_argument, 0, 'x'},
+            {0, 0, 0, 0}
+        };
+
+        int c = getopt_long(argc, argv, "ho:b:dx", long_options, NULL);
+        if(c == -1)
+            break;
+        switch(c)
+        {
+            case 'd':
+                debug = true;
+                break;
+            case 'h':
+                usage();
+                break;
+            case 'o':
+                outfile = optarg;
+                break;
+            case 'b':
+                bootfile = optarg;
+                break;
+            case 'x':
+                dump_nwz_dev_info("");
+                break;
+            default:
+                abort();
+        }
+    }
+
+    if(!outfile)
+    {
+        printf("You must specify an output file\n");
+        return 1;
+    }
+    if(!bootfile)
+    {
+        printf("You must specify a boot file\n");
+        return 1;
+    }
+    if(optind != argc)
+    {
+        printf("Extra arguments on command line\n");
+        return 1;
+    }
+
+    int err = mknwzboot(bootfile, outfile, debug);
+    printf("Result: %d\n", err);
+    return err;
+}
diff --git a/rbutil/mknwzboot/mknwzboot.c b/rbutil/mknwzboot/mknwzboot.c
new file mode 100644
index 0000000..1fc105a
--- /dev/null
+++ b/rbutil/mknwzboot/mknwzboot.c
@@ -0,0 +1,230 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2011 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include "mknwzboot.h"
+#include "upg.h"
+
+#include "install_script.h"
+
+struct nwz_model_desc_t
+{
+    /* Descriptive name of this model */
+    const char *model_name;
+    /* Model name used in the Rockbox header in ".sansa" files - these match the
+       -add parameter to the "scramble" tool */
+    const char *rb_model_name;
+    /* Model number used to initialise the checksum in the Rockbox header in
+       ".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
+    const int rb_model_num;
+    /* Codename used in upgtool */
+    const char *codename;
+};
+
+static const struct nwz_model_desc_t nwz_models[] =
+{
+    { "Sony NWZ-E450 Series", "e450", 100, "nwz-e450" },
+    { "Sony NWZ-E460 Series", "e460", 101, "nwz-e460" },
+    { "Sony NWZ-E470 Series", "e470", 103, "nwz-e470" },
+    { "Sony NWZ-E580 Series", "e580", 102, "nwz-e580" },
+    { "Sony NWZ-A10 Series", "a10", 104, "nwz-a10" },
+};
+
+#define NR_NWZ_MODELS     (sizeof(nwz_models) / sizeof(nwz_models[0]))
+
+void dump_nwz_dev_info(const char *prefix)
+{
+    printf("%smknwzboot models:\n", prefix);
+    for(int i = 0; i < NR_NWZ_MODELS; i++)
+    {
+        printf("%s  %s: rb_model=%s rb_num=%d codename=%s\n", prefix,
+            nwz_models[i].model_name, nwz_models[i].rb_model_name,
+            nwz_models[i].rb_model_num, nwz_models[i].codename);
+    }
+}
+
+/* read a file to a buffer */
+static void *read_file(const char *file, size_t *size)
+{
+    FILE *f = fopen(file, "rb");
+    if(f == NULL)
+    {
+        printf("[ERR] Cannot open file '%s' for reading: %m\n", file);
+        return NULL;
+    }
+    fseek(f, 0, SEEK_END);
+    *size = ftell(f);
+    fseek(f, 0, SEEK_SET);
+    void *buffer = malloc(*size);
+    if(fread(buffer, *size, 1, f) != 1)
+    {
+        free(buffer);
+        fclose(f);
+        printf("[ERR] Cannot read file '%s': %m\n", file);
+        return NULL;
+    }
+    fclose(f);
+    return buffer;
+}
+
+/* write a file from a buffer */
+static bool write_file(const char *file, void *buffer, size_t size)
+{
+    FILE *f = fopen(file, "wb");
+    if(f == NULL)
+    {
+        printf("[ERR] Cannot open file '%s' for writing: %m\n", file);
+        return false;
+    }
+    if(fwrite(buffer, size, 1, f) != 1)
+    {
+        fclose(f);
+        printf("[ERR] Cannot write file '%s': %m\n", file);
+        return false;
+    }
+    fclose(f);
+    return true;
+}
+
+static unsigned int be2int(unsigned char* buf)
+{
+   return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+}
+
+static int find_model(uint8_t *boot, size_t boot_size)
+{
+    if(boot_size < 8)
+    {
+        printf("[ERR] Boot file is too small to be valid\n");
+        return -1;
+    }
+    /* find model by comparing magic scramble value */
+    int model = 0;
+    for(; model < NR_NWZ_MODELS; model++)
+        if(memcmp(boot + 4, nwz_models[model].rb_model_name, 4) == 0)
+            break;
+    if(model == NR_NWZ_MODELS)
+    {
+        printf("[ERR] This player is not supported: %.4s\n", boot + 4);
+        return -1;
+    }
+    printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name);
+    /* verify checksum */
+    uint32_t sum = nwz_models[model].rb_model_num;
+    for(int i = 8; i < boot_size; i++)
+        sum += boot[i];
+    if(sum != be2int(boot))
+    {
+        printf("[ERR] Checksum mismatch\n");
+        return -1;
+    }
+    return model;
+}
+
+static bool get_model_keysig(int model, char key[NWZ_KEY_SIZE], char sig[NWZ_SIG_SIZE])
+{
+    const char *codename = nwz_models[model].codename;
+    for(int i = 0; g_model_list[i].model; i++)
+        if(strcmp(g_model_list[i].model, codename) == 0)
+        {
+            if(decrypt_keysig(g_model_list[i].kas, key, sig) == 0)
+                return true;
+            printf("[ERR] Cannot decrypt kas '%s'\n", g_model_list[i].kas);
+            return false;
+        }
+    printf("[ERR] Codename '%s' matches to entry in upg database\n", codename);
+    return false;
+}
+
+void nwz_printf(void *u, bool err, color_t c, const char *f, ...)
+{
+    (void)err;
+    (void)c;
+    bool *debug = u;
+    va_list args;
+    va_start(args, f);
+    if(err || *debug)
+        vprintf(f, args);
+    va_end(args);
+}
+
+static void *memdup(void *data, size_t size)
+{
+    void *buf = malloc(size);
+    memcpy(buf, data, size);
+    return buf;
+}
+
+int mknwzboot(const char *bootfile, const char *outfile, bool debug)
+{
+    size_t boot_size;
+    uint8_t *boot = read_file(bootfile, &boot_size);
+    if(boot == NULL)
+    {
+        printf("[ERR] Cannot open boot file\n");
+        return 1;
+    }
+    /* check that it is a valid scrambled file */
+    int model = find_model(boot, boot_size);
+    if(model < 0)
+    {
+        free(boot);
+        printf("[ERR] Invalid boot file\n");
+        return 2;
+    }
+    /* find keys */
+    char key[NWZ_KEY_SIZE];
+    char sig[NWZ_SIG_SIZE];
+    if(!get_model_keysig(model, key, sig))
+    {
+        printf("[ERR][INTERNAL] Cannot get keys for model\n");
+        return 3;
+    }
+    /* create the upg file */
+    struct upg_file_t *upg = upg_new();
+    /* first file is the install script: we have to copy data because upg_free()
+     * will free it */
+    upg_append(upg, memdup(install_script, LEN_install_script), LEN_install_script);
+    /* second file is the bootloader content (expected to be a tar file): we have
+     * to copy data because upg_free() will free it */
+    upg_append(upg, memdup(boot + 8, boot_size - 8), boot_size - 8);
+    free(boot);
+    /* write file to buffer */
+    size_t upg_size;
+    void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf);
+    upg_free(upg);
+    if(upg_buf == NULL)
+    {
+        printf("[ERR] Cannot create UPG file\n");
+        return 4;
+    }
+    if(!write_file(outfile, upg_buf, upg_size))
+    {
+        free(upg_buf);
+        printf("[ERR] Cannpt write UPG file\n");
+        return 5;
+    }
+    free(upg_buf);
+    return 0;
+}
diff --git a/utils/nwztools/plattools/nwz_adc.h b/rbutil/mknwzboot/mknwzboot.h
similarity index 64%
copy from utils/nwztools/plattools/nwz_adc.h
copy to rbutil/mknwzboot/mknwzboot.h
index 86b2dc7..f46dd75 100644
--- a/utils/nwztools/plattools/nwz_adc.h
+++ b/rbutil/mknwzboot/mknwzboot.h
@@ -7,7 +7,7 @@
  *                     \/            \/     \/    \/            \/
  * $Id$
  *
- * Copyright (C) 2016 Amaury Pouly
+ * Copyright (C) 2011 by Amaury Pouly
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -18,25 +18,24 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
-#ifndef __NWZ_ADC_H__
-#define __NWZ_ADC_H__
 
-#define NWZ_ADC_DEV  "/dev/icx_adc"
+#ifndef MKIMXBOOT_H
+#define MKIMXBOOT_H
 
-#define NWZ_ADC_TYPE    'm'
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
 
-#define NWZ_ADC_MIN_CHAN    0
-#define NWZ_ADC_MAX_CHAN    7
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-#define NWZ_ADC_VCCBAT  0
-#define NWZ_ADC_VCCVBUS 1
-#define NWZ_ADC_ADIN3   2
-#define NWZ_ADC_ADIN4   3
-#define NWZ_ADC_ADIN5   4
-#define NWZ_ADC_ADIN6   5
-#define NWZ_ADC_ADIN7   6
-#define NWZ_ADC_ADIN8   7
+void dump_nwz_dev_info(const char *prefix);
+/* return 0 on success */
+int mknwzboot(const char *bootfile, const char *outfile, bool debug);
 
-#define NWZ_ADC_GET_VAL(chan)   _IOR(NWZ_ADC_TYPE, chan, unsigned char)
+#ifdef __cplusplus
+}
+#endif
+#endif
 
-#endif /* __NWZ_ADC_H__ */
diff --git a/tools/configure b/tools/configure
index fd86d8a..3b481e9 100755
--- a/tools/configure
+++ b/tools/configure
@@ -706,12 +706,15 @@
  GCCOPTS="$GCCOPTS -ffast-math -fsingle-precision-constant"
 }
 
-ypr0cc () {
-
+arm1176jzlinuxcc () {
  GCCOPTS=`echo $CCOPTS | sed -e s/-ffreestanding// -e s/-nostdlib//`
+ # Although the ARM1176JZ-S supports unaligned accesses, those seems to disabled
+ # by the kernel. Since GCC emits unaligned accesses by default on ARMv6, we
+ # need to disable that
+ GCCOPTS="$GCCOPTS -mcpu=arm1176jz-s -mno-unaligned-access -mfloat-abi=softfp"
  GCCOPTIMIZE=''
  LDOPTS="-lasound -lpthread -lm -ldl -lrt $LDOPTS"
- GLOBAL_LDOPTS="$GLOBAL_LDOPTS -Wl,-z,defs"
+ GLOBAL_LDOPTS="$GLOBAL_LDOPTS -Wl,-z,defs" # warn about undefined symbols in shared libraries
  SHARED_LDFLAG="-shared"
  SHARED_CFLAGS=''
  endian="little"
@@ -721,8 +724,18 @@
  GCCOPTS="$GCCOPTS  -D_GNU_SOURCE=1 -U_FORTIFY_SOURCE -D_REENTRANT"
 
  # Set up compiler
- gccchoice="4.4.6"
- prefixtools "arm-ypr0-linux-gnueabi-"
+ gccchoice="4.9.4"
+ prefixtools "arm-rockbox-linux-gnueabi-"
+}
+
+ypr0cc () {
+ arm1176jzlinuxcc
+ app_type="ypr0"
+}
+
+sonynwzcc () {
+ arm1176jzlinuxcc
+ app_type="sonynwz"
 }
 
 androidcc () {
@@ -1493,11 +1506,14 @@
  202) Nokia N8xx          211) MA9C              ==Sony==
  203) Nokia N900          212) MA8               220) NWZ-E370/E380 series
  204) Pandora             213) MA8C              221) NWZ-E360 series
- 205) Samsung YP-R0
- 206) Android MIPS        ==IHIFI==              ==iBasso==
- 207) Android x86         230) 760               232) DX50
- 208) Samsung YP-R1       231) 960               233) DX90
-
+ 205) Samsung YP-R0                              222) NWZ-E450 series
+ 206) Android MIPS        ==IHIFI==              223) NWZ-E460 series
+ 207) Android x86         230) 760               224) NWZ-E470 series
+ 208) Samsung YP-R1       231) 960               225) NWZ-E580 series
+                                                 226) NWZ-A10 series
+ ==iBasso==
+ 232) DX50
+ 233) DX90
 
 EOF
 
@@ -3853,6 +3869,121 @@
     arm926ejscc
     ;;
 
+   222|sonynwze450)
+    application="yes"
+    target_id=96
+    modelname="sonynwze450"
+    target="SONY_NWZE450"
+    memory=16
+    bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
+    bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
+    tool="cp"
+    output="rockbox.sony"
+    boottool="$rootdir/tools/scramble -add=e450"
+    bootoutput="bootloader-nwze450.sony"
+    appextra="gui:recorder"
+    plugins=""
+    swcodec="yes"
+    toolset=$genericbitmaptools
+    t_cpu="hosted"
+    t_manufacturer="sonynwz"
+    t_model="nwze450"
+    uname=`uname`
+    sonynwzcc
+    ;;
+
+   223|sonynwze460)
+    application="yes"
+    target_id=97
+    modelname="sonynwze460"
+    target="SONY_NWZE460"
+    memory=16
+    bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
+    bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
+    tool="cp"
+    output="rockbox.sony"
+    boottool="$rootdir/tools/scramble -add=e460"
+    bootoutput="bootloader-nwze460.sony"
+    appextra="gui:recorder"
+    plugins="yes"
+    swcodec="yes"
+    toolset=$genericbitmaptools
+    t_cpu="hosted"
+    t_manufacturer="sonynwz"
+    t_model="nwze460"
+    uname=`uname`
+    sonynwzcc
+    ;;
+
+   224|sonynwze470)
+    application="yes"
+    target_id=100
+    modelname="sonynwze470"
+    target="SONY_NWZE470"
+    memory=16
+    bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
+    bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
+    tool="cp"
+    output="rockbox.sony"
+    boottool="$rootdir/tools/scramble -add=e470"
+    bootoutput="bootloader-nwze470.sony"
+    appextra="gui:recorder"
+    plugins=""
+    swcodec="yes"
+    toolset=$genericbitmaptools
+    t_cpu="hosted"
+    t_manufacturer="sonynwz"
+    t_model="nwze470"
+    uname=`uname`
+    sonynwzcc
+    ;;
+
+   225|sonynwze580)
+    application="yes"
+    target_id=98
+    modelname="sonynwze580"
+    target="SONY_NWZE580"
+    memory=16
+    bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
+    bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
+    tool="cp"
+    output="rockbox.sony"
+    boottool="$rootdir/tools/scramble -add=e580"
+    bootoutput="bootloader-nwze580.sony"
+    appextra="gui:recorder"
+    plugins=""
+    swcodec="yes"
+    toolset=$genericbitmaptools
+    t_cpu="hosted"
+    t_manufacturer="sonynwz"
+    t_model="nwze580"
+    uname=`uname`
+    sonynwzcc
+    ;;
+
+   226|sonynwza10)
+    application="yes"
+    target_id=101
+    modelname="sonynwza10"
+    target="SONY_NWZA10"
+    memory=16
+    bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
+    bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
+    tool="cp"
+    output="rockbox.sony"
+    boottool="$rootdir/tools/scramble -add=a10"
+    bootoutput="bootloader-nwza10.sony"
+    appextra="gui:recorder"
+    plugins=""
+    swcodec="yes"
+    toolset=$genericbitmaptools
+    t_cpu="hosted"
+    t_manufacturer="sonynwz"
+    t_model="nwza10"
+    uname=`uname`
+    sonynwzcc
+    ;;
+
    230|ihifi760)
     target_id=92
     modelname="ihifi760"
diff --git a/tools/root.make b/tools/root.make
index c9f4a2e..b5bd0e8 100644
--- a/tools/root.make
+++ b/tools/root.make
@@ -73,7 +73,10 @@
       include $(FIRMDIR)/firmware.make
       include $(ROOTDIR)/apps/bitmaps/bitmaps.make
       ifeq (arch_arm,$(ARCH))
-          include $(ROOTDIR)/lib/unwarminder/unwarminder.make
+          # some targets don't use the unwarminder because they have the glibc backtrace
+          ifeq (,$(filter sonynwz,$(APP_TYPE)))
+            include $(ROOTDIR)/lib/unwarminder/unwarminder.make
+          endif
       endif
       ifeq (,$(findstring bootloader,$(APPSDIR)))
         include $(ROOTDIR)/lib/skin_parser/skin_parser.make
@@ -98,7 +101,11 @@
 endif
 
 ifneq (,$(findstring bootloader,$(APPSDIR)))
-  include $(APPSDIR)/bootloader.make
+  ifneq (,$(findstring sonynwz,$(APP_TYPE)))
+    include $(ROOTDIR)/firmware/target/hosted/sonynwz/sonynwz.make
+  else
+    include $(APPSDIR)/bootloader.make
+  endif
 else ifneq (,$(findstring bootbox,$(APPSDIR)))
   include $(APPSDIR)/bootbox.make
 else ifneq (,$(findstring checkwps,$(APP_TYPE)))
@@ -132,6 +139,10 @@
     include $(ROOTDIR)/firmware/target/hosted/samsungypr/ypr1/ypr1.make
   endif
 
+  ifneq (,$(findstring sonynwz,$(APP_TYPE)))
+    include $(ROOTDIR)/firmware/target/hosted/sonynwz/sonynwz.make
+  endif
+
   ifneq (,$(findstring android_ndk, $(APP_TYPE)))
     include $(ROOTDIR)/firmware/target/hosted/ibasso/android_ndk.make
   else
diff --git a/tools/scramble.c b/tools/scramble.c
index 5378be2..8c5230c 100644
--- a/tools/scramble.c
+++ b/tools/scramble.c
@@ -129,7 +129,8 @@
            "\t                   m2v4, fuze, c2v2, clv2, y820, y920, y925, x747,\n"
            "\t                   747p, x777, nn2g, m244, cli+, fuz2, hd20, hd30,\n"
            "\t                   ip6g, rk27, clzp, zxf2, zxf3, fuz+, e370, e360,\n"
-           "\t                   zxfi, zmoz, zen, zenv, ypz5, zxfs)\n");
+           "\t                   zxfi, zmoz, zen, zenv, ypz5, zxfs, e450, e460,\n"
+           "\t                   e470,e580,a10)\n");
     printf("\nNo option results in Archos standard player/recorder format.\n");
 
     exit(1);
@@ -382,6 +383,16 @@
             modelnum = 90;
         else if (!strcmp(&argv[1][5], "zxfs")) /* Creative ZEN X-Fi Style */
             modelnum = 94;
+        else if (!strcmp(&argv[1][5], "e450")) /* Sony NWZ-E450 series */
+            modelnum = 100;
+        else if (!strcmp(&argv[1][5], "e460")) /* Sony NWZ-E460 series */
+            modelnum = 101;
+        else if (!strcmp(&argv[1][5], "e580")) /* Sony NWZ-E580 series */
+            modelnum = 102;
+        else if (!strcmp(&argv[1][5], "e470")) /* Sony NWZ-E470 series */
+            modelnum = 103;
+        else if (!strcmp(&argv[1][5], "a10")) /* Sony NW-A10 series */
+            modelnum = 104;
         else {
             fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
             return 2;
diff --git a/utils/nwztools/database/gen_db.py b/utils/nwztools/database/gen_db.py
index de78d05..be4cc34 100755
--- a/utils/nwztools/database/gen_db.py
+++ b/utils/nwztools/database/gen_db.py
@@ -200,7 +200,7 @@
 #endif /* __NWZ_DB_H__ */
 """
 
-with open("nwz_db.h", "w") as fp:
+with open("nwz-db.h", "w") as fp:
     fp.write(header_begin)
     # generate list of all nvp nodes
     for name in sorted(g_nvp_names):
@@ -241,7 +241,7 @@
 
 /** /!\ This file was automatically generated, DO NOT MODIFY IT DIRECTLY /!\ */
 
-#include "nwz_db.h"
+#include "nwz-db.h"
 
 struct nwz_model_info_t nwz_model[NWZ_MODEL_COUNT] =
 {
@@ -256,7 +256,7 @@
 def codename_to_c(codename):
     return re.sub('[^a-zA-Z0-9]', '_', codename, 0)
 
-with open("nwz_db.c", "w") as fp:
+with open("nwz-db.c", "w") as fp:
     fp.write(impl_begin)
     # generate model list (sort by mid)
     for model in sorted(g_models, key = by_mid):
diff --git a/utils/nwztools/plattools/Makefile b/utils/nwztools/plattools/Makefile
deleted file mode 100644
index 71188ba..0000000
--- a/utils/nwztools/plattools/Makefile
+++ /dev/null
@@ -1,31 +0,0 @@
-PREFIX?=arm-sony-linux-gnueabi-
-CC=$(PREFIX)gcc
-LD=$(PREFIX)gcc
-CFLAGS=-std=gnu99 -Wall -O2
-NWZ_DB_DIR=../database
-INCLUDES=-I. -I$(NWZ_DB_DIR)
-
-LIB_FILES=nwz_lib.c $(NWZ_DB_DIR)/nwz_db.c
-TOOL_FILES=dest_tool.c test_adc.c test_adc.c test_bl.c test_display.c \
-	test_keys.c test_power.c test_ts.c test_fb.c
-ALL_ELF=$(patsubst %.c,%.elf,$(TOOL_FILES)) all_tools.elf dualboot.elf
-
-all: $(ALL_ELF)
-
-# image dependency
-data/rockbox_icon.h data/tools_icon.h:
-	make -C data
-
-dualboot.elf: data/rockbox_icon.h data/tools_icon.h
-
-%.elf: %.c $(LIB_FILES)
-	$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
-
-all_tools.elf: all_tools.c $(TOOL_FILES) $(LIB_FILES)
-	$(CC) $(CFLAGS) -DNWZ_EMBED_TOOLS $(INCLUDES) -o $@ $^
-
-dualboot.elf: dualboot.c all_tools.c $(TOOL_FILES) $(LIB_FILES)
-	$(CC) $(CFLAGS) -DNWZ_DUALBOOT -DNWZ_EMBED_TOOLS $(INCLUDES) -o $@ $^
-
-clean:
-	rm -rf $(ALL_ELF)
diff --git a/utils/nwztools/plattools/README b/utils/nwztools/plattools/README
deleted file mode 100644
index e33dfeb..0000000
--- a/utils/nwztools/plattools/README
+++ /dev/null
@@ -1,27 +0,0 @@
-Platform tools
---------------
-
-Those tools are designed to run on the devices. They are mostly tests that can
-be run in firmware upgrade mode (using exec_file in utils/nwztools/scripts/). To
-compile those, you will need the sony nwz cross compiler. The canonical way to
-run them is as follows:
-
-1) Build the tools:
-    cd /path/to/utils/nwztools/plattools
-    make
-Note that the default cross compiler prefix is arm-sony-linux-gnueabi- but it
-can be changed using PREFIX:
-PREFIX="sony-nwz-linux-gnueabi-" make
-
-2) Embed the wanted excutable in a firmware upgrade for your device. The README
-in utils/nwztools/scripts contains more documentation on how to select the right
-target. For example if you want to embed test_display for the NWZ-E460 series,
-you should run:
-    cd /path/to/utils/nwztools/scripts
-    make exec_file UPG=test_display_nwze46x.upg NWZ_TARGET=nwz-e46x EXEC=../plattools/test_display.elf
-
-3) Put the upgrade file on the device and trigger a firmware upgrade. Assuming
-your NWZ device is /dev/sdb1 and is mounted at /media/pamaury/WALKMAN, run:
-    cd /path/to/utils/nwztools/scripts
-    make copy_fw_upgrade UPG=test_display_nwze46x.upg NWZ_MOUNT=/media/pamaury/WALKMAN/
-    sudo make do_fw_upgrade NWZ_DEV=/dev/sdb1
diff --git a/utils/nwztools/plattools/all_tools.c b/utils/nwztools/plattools/all_tools.c
deleted file mode 100644
index c93e26b..0000000
--- a/utils/nwztools/plattools/all_tools.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2011 by Amaury Pouly
- *
- * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
- * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_plattools.h"
-
-#define TOOL_LIST \
-    TOOL(dest_tool) \
-    TOOL(test_adc) \
-    TOOL(test_bl) \
-    TOOL(test_display) \
-    TOOL(test_keys) \
-    TOOL(test_power) \
-    TOOL(test_ts) \
-    TOOL(test_fb) \
-
-typedef int (*nwz_tool_main_t)(int argc, char **argv);
-
-struct nwz_tool_t
-{
-    const char *name;
-    nwz_tool_main_t main;
-};
-
-/* create list of extern definition */
-#define TOOL(name) extern int NWZ_TOOL_MAIN(name)(int argc, char **argv);
-TOOL_LIST
-#undef TOOL
-
-/* create actual list */
-#define TOOL(name) { #name, NWZ_TOOL_MAIN(name) },
-static struct nwz_tool_t g_tools[] =
-{
-    TOOL_LIST
-};
-#undef TOOL
-
-#define NR_TOOLS    (sizeof(g_tools) / sizeof(g_tools[0]))
-
-static void hello(void)
-{
-    /* clear screen and display welcome message */
-    nwz_lcdmsg(true, 0, 0, "all_tools");
-    nwz_lcdmsg(false, 0, 1, "BACK: quit");
-    nwz_lcdmsg(false, 0, 2, "LEFT/RIGHT: change tool");
-    nwz_lcdmsg(false, 0, 3, "PLAY: run tool");
-}
-
-/* this tool itself can be embedded in the dualboot */
-#ifdef NWZ_DUALBOOT
-int NWZ_TOOL_MAIN(all_tools)(int argc, char **argv)
-#else
-int main(int argc, char **argv)
-#endif
-{
-    hello();
-    /* open input device */
-    int input_fd = nwz_key_open();
-    if(input_fd < 0)
-    {
-        nwz_lcdmsg(false, 3, 5, "Cannot open input device");
-        sleep(2);
-        return 1;
-    }
-    /* main loop */
-    int cur_tool = 0;
-    while(true)
-    {
-        /* print tools */
-        int line = 5;
-        for(size_t i = 0; i < NR_TOOLS; i++)
-        {
-            nwz_lcdmsgf(false, 0, line++, "%c %s", (i == cur_tool) ? '>' : ' ',
-                g_tools[i].name);
-        }
-        /* wait for event (1000ms) */
-        int ret = nwz_key_wait_event(input_fd, 1000000);
-        if(ret != 1)
-            continue;
-        struct input_event evt;
-        if(nwz_key_read_event(input_fd, &evt) != 1)
-            continue;
-        /* only act on key release */
-        if(nwz_key_event_is_press(&evt))
-            continue;
-        int keycode = nwz_key_event_get_keycode(&evt);
-        if(keycode == NWZ_KEY_LEFT)
-        {
-            cur_tool--;
-            if(cur_tool == -1)
-                cur_tool += NR_TOOLS;
-        }
-        else if(keycode == NWZ_KEY_RIGHT)
-        {
-            cur_tool++;
-            if(cur_tool == NR_TOOLS)
-                cur_tool = 0;
-        }
-        else if(keycode == NWZ_KEY_PLAY)
-        {
-            /* close input */
-            nwz_key_close(input_fd);
-            g_tools[cur_tool].main(argc, argv);
-            /* reopen input and clear the screen */
-            input_fd = nwz_key_open();
-            hello();
-        }
-        else if(keycode == NWZ_KEY_BACK)
-            break;
-    }
-    nwz_key_close(input_fd);
-    return 0;
-}
diff --git a/utils/nwztools/plattools/data/Makefile b/utils/nwztools/plattools/data/Makefile
deleted file mode 100644
index 86f3bb3..0000000
--- a/utils/nwztools/plattools/data/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-TOOLS_DIR=../../../../tools/
-all: rockbox_icon.h tools_icon.h
-
-%.h: %.bmp
-	$(TOOLS_DIR)/bmp2rb -f 4 $^ > $@
-
-clean:
-	rm -rf *.h
diff --git a/utils/nwztools/plattools/data/Oxygen480-categories-preferences-system.svg b/utils/nwztools/plattools/data/Oxygen480-categories-preferences-system.svg
deleted file mode 100644
index 0835251..0000000
--- a/utils/nwztools/plattools/data/Oxygen480-categories-preferences-system.svg
+++ /dev/null
@@ -1,334 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="128" height="128" id="svg5676" sodipodi:version="0.32" inkscape:version="0.45+devel" sodipodi:docname="settings-wip.svgz" inkscape:output_extension="org.inkscape.output.svgz.inkscape" version="1.0">
-  <defs id="defs5678">
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4322" id="linearGradient4338" gradientUnits="userSpaceOnUse" gradientTransform="translate(-2.6296821,21.172877)" x1="5.1934605" y1="88.98745" x2="5.1934605" y2="145.64882"/>
-    <linearGradient y2="0" x2="28" y1="57.5" x1="28" gradientUnits="userSpaceOnUse" id="linearGradient8081">
-      <stop id="stop8083" style="stop-color:#ffd700;stop-opacity:1;" offset="0"/>
-      <stop offset="0.25242719" style="stop-color:#ffea00;stop-opacity:1;" id="stop8087"/>
-      <stop id="stop8085" style="stop-color:#b06d00;stop-opacity:1;" offset="1"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient8081" id="linearGradient7698" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0872079,0,0,1.0872079,-59.143229,30.210796)" x1="58.557281" y1="107.76735" x2="63.943447" y2="107.76735"/>
-    <linearGradient id="linearGradient6924">
-      <stop style="stop-color:#ffffff;stop-opacity:0.73885351;" offset="0" id="stop6926"/>
-      <stop id="stop10395" offset="0.24999999" style="stop-color:#ffffff;stop-opacity:0;"/>
-      <stop id="stop10393" offset="0.5" style="stop-color:#cccccc;stop-opacity:0;"/>
-      <stop style="stop-color:#9a9a9a;stop-opacity:1;" offset="1" id="stop6928"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient6924" id="linearGradient6930" x1="8.3827581" y1="8.3199806" x2="15.021504" y2="14.958727" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.2050468,0,0,1.2050468,-2.1016162,-2.0259658)"/>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4529" id="linearGradient4640" gradientUnits="userSpaceOnUse" x1="9.3031492" y1="133.25163" x2="-5.8540711" y2="130.59308"/>
-    <filter inkscape:collect="always" x="-0.10337079" width="1.2067416" y="-0.10337079" height="1.2067416" id="filter4626">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="0.42488862" id="feGaussianBlur4628"/>
-    </filter>
-    <clipPath clipPathUnits="userSpaceOnUse" id="clipPath4632">
-      <rect style="opacity:0.83895126;fill:url(#linearGradient4636);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1;filter:url(#filter4626)" id="rect4634" width="13.334369" height="3.7415669" x="-2.9263651" y="130.97287" rx="0" ry="0" inkscape:transform-center-x="-16.434708" inkscape:transform-center-y="-5.5242717"/>
-    </clipPath>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4529" id="linearGradient4604" gradientUnits="userSpaceOnUse" x1="9.3031492" y1="133.25163" x2="-5.8540711" y2="130.59308"/>
-    <radialGradient inkscape:collect="always" xlink:href="#linearGradient4434" id="radialGradient4602" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.3939752,0.4817163,48.449986)" cx="4.7494926" cy="132.25244" fx="4.7494926" fy="132.25244" r="5.3222656"/>
-    <filter inkscape:collect="always" id="filter4584">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="1.0829419" id="feGaussianBlur4586"/>
-    </filter>
-    <clipPath clipPathUnits="userSpaceOnUse" id="clipPath4588">
-      <path sodipodi:nodetypes="ccsccccsccc" id="path4590" d="M 13.037731,82.09273 L 18.342123,87.397123 C 21.331352,87.817882 24.407038,89.18508 26.895219,91.673261 C 29.411177,94.189215 30.893289,97.328601 31.294715,100.34972 L 56.289372,125.34436 C 62.090282,131.14528 77.301422,116.01036 71.462392,110.17133 L 46.467742,85.176682 C 43.446635,84.775254 40.307258,83.29314 37.791293,80.777186 C 35.303111,78.289007 33.935917,75.213314 33.515156,72.22409 L 28.210762,66.919697 L 13.037731,82.09273 z" style="opacity:1;fill:url(#linearGradient4592);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1"/>
-    </clipPath>
-    <filter inkscape:collect="always" id="filter4551">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="0.15501048" id="feGaussianBlur4553"/>
-    </filter>
-    <linearGradient inkscape:collect="always" id="linearGradient4529">
-      <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop4531"/>
-      <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop4533"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4529" id="linearGradient4537" x1="9.3031492" y1="133.25163" x2="-5.8540711" y2="130.59308" gradientUnits="userSpaceOnUse"/>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient2575" id="linearGradient4525" x1="58.557281" y1="107.76735" x2="63.943447" y2="107.76735" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0872079,0,0,1.0872079,-71.164046,29.503688)"/>
-    <linearGradient inkscape:collect="always" id="linearGradient4509">
-      <stop style="stop-color:#ffe900;stop-opacity:1;" offset="0" id="stop4511"/>
-      <stop style="stop-color:#ffe900;stop-opacity:0;" offset="1" id="stop4513"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4509" id="linearGradient4515" x1="75.585938" y1="85.083641" x2="89.453125" y2="79.224266" gradientUnits="userSpaceOnUse"/>
-    <filter inkscape:collect="always" id="filter4501">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="0.48665741" id="feGaussianBlur4503"/>
-    </filter>
-    <linearGradient inkscape:collect="always" id="linearGradient4465">
-      <stop style="stop-color:#ffa300;stop-opacity:1;" offset="0" id="stop4467"/>
-      <stop style="stop-color:#ffa300;stop-opacity:0;" offset="1" id="stop4469"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4465" id="linearGradient4471" x1="83.886719" y1="77.661766" x2="86.300743" y2="86.671021" gradientUnits="userSpaceOnUse" gradientTransform="translate(-4,-4)"/>
-    <linearGradient inkscape:collect="always" id="linearGradient4434">
-      <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop4436"/>
-      <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop4438"/>
-    </linearGradient>
-    <radialGradient inkscape:collect="always" xlink:href="#linearGradient4434" id="radialGradient4440" cx="4.7494926" cy="132.25244" fx="4.7494926" fy="132.25244" r="5.3222656" gradientTransform="matrix(1,0,0,0.3939752,-7.0710881e-2,74.137847)" gradientUnits="userSpaceOnUse"/>
-    <filter inkscape:collect="always" id="filter4404">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="0.15249406" id="feGaussianBlur4406"/>
-    </filter>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4322" id="linearGradient4342" gradientUnits="userSpaceOnUse" gradientTransform="translate(1.6836694,24.213436)" x1="3.5450988" y1="107.64014" x2="3.190912" y2="104.64899"/>
-    <linearGradient inkscape:collect="always" id="linearGradient4322">
-      <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop4324"/>
-      <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop4326"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4322" id="linearGradient4346" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,-2.6879854,-4.0690534)" x1="5.1934605" y1="103.9544" x2="5.1348171" y2="115.65614"/>
-    <filter inkscape:collect="always" x="-0.074906364" width="1.1498127" y="-0.11235955" height="1.224719" id="filter4238">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="1.1235955" id="feGaussianBlur4240"/>
-    </filter>
-    <clipPath clipPathUnits="userSpaceOnUse" id="clipPath4242">
-      <path sodipodi:nodetypes="ccsccccsccc" id="path4244" d="M -4,77.788157 L -4,83.381653 C -2.645772,85.179573 -1.744968,87.522089 -1.744968,90.145881 C -1.744968,92.798965 -2.618764,95.23565 -4,97.040192 L -4,123.39712 C -4,129.51419 12,129.55437 12,123.39712 L 12,97.040192 C 10.618764,95.23565 9.744972,92.798965 9.744968,90.145881 C 9.744968,87.522089 10.645776,85.179573 12,83.381653 L 12,77.788157 L -4,77.788157 z" style="opacity:1;fill:url(#linearGradient4247);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1"/>
-    </clipPath>
-    <linearGradient id="linearGradient2575" gradientUnits="userSpaceOnUse" x1="28" y1="57.5" x2="28" y2="0">
-      <stop offset="0" style="stop-color:#FFEA00" id="stop2577"/>
-      <stop offset="1" style="stop-color:#cd8000;stop-opacity:1;" id="stop2579"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient2575" id="linearGradient4190" x1="36" y1="100" x2="28" y2="100" gradientUnits="userSpaceOnUse" spreadMethod="reflect" gradientTransform="matrix(0.9483145,-0.9483145,0.9483145,0.9483145,-36.790528,30.877897)"/>
-    <linearGradient id="linearGradient6511">
-      <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop6513"/>
-      <stop style="stop-color:#393939;stop-opacity:1;" offset="1" id="stop6515"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient6511" id="linearGradient6517" x1="38.074299" y1="4.2695875" x2="38.074299" y2="-10.42289" gradientUnits="userSpaceOnUse"/>
-    <linearGradient id="linearGradient3916">
-      <stop style="stop-color:#d3d6d6;stop-opacity:1;" offset="0" id="stop3918"/>
-      <stop style="stop-color:#f7f7f7;stop-opacity:1;" offset="1" id="stop3921"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient3916" id="linearGradient3943" gradientUnits="userSpaceOnUse" x1="34.165016" y1="4.863008" x2="34.165016" y2="-14.006344"/>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient3904" id="linearGradient6112" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.1550511,0,0,1.1550511,-41.26484,21.101778)" x1="38.827515" y1="104.49192" x2="36.460194" y2="17.509802"/>
-    <filter inkscape:collect="always" x="-0.26177245" width="1.5235449" y="-0.075698018" height="1.151396" id="filter3838">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="0.41890191" id="feGaussianBlur3840"/>
-    </filter>
-    <filter inkscape:collect="always" x="-0.26177242" width="1.5235448" y="-0.075698018" height="1.151396" id="filter3834">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="0.41890191" id="feGaussianBlur3836"/>
-    </filter>
-    <clipPath clipPathUnits="userSpaceOnUse" id="clipPath3850">
-      <path id="path3852" d="M 5.6835937,-4 C 6.7672977,-0.13901249 7.6835937,4 7.6835937,8 C 7.6835937,25.92781 15.683594,26.507796 15.683594,8 C 15.683594,4 16.274299,-0.44557713 17.683594,-4 C 16.034701,-11.286281 10.22872,-24.562662 5.6835937,-4 z" style="opacity:1;fill:#b4b4b4;fill-opacity:1;stroke:none;stroke-width:0.47008219;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1" sodipodi:nodetypes="ccccc"/>
-    </clipPath>
-    <linearGradient id="linearGradient3904">
-      <stop style="stop-color:#141515;stop-opacity:1;" offset="0" id="stop3906"/>
-      <stop style="stop-color:#535557;stop-opacity:0;" offset="1" id="stop3908"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient3904" id="linearGradient6119" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.1550511,0,0,1.1550511,-40.633471,-152.2263)" x1="36.460194" y1="108.28275" x2="39.503891" y2="69.41713"/>
-    <linearGradient inkscape:collect="always" id="linearGradient3220">
-      <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop3222"/>
-      <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop3224"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient3220" id="linearGradient6122" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.6737798,0,0,1.4175761,-25.92314,-147.94457)" x1="36.460194" y1="89.611626" x2="36.460194" y2="17.509802"/>
-    <radialGradient gradientUnits="userSpaceOnUse" r="139.55859" cy="112.3047" cx="102" id="radialGradient9613">
-      <stop id="stop9615" style="stop-color:#535557" offset="0"/>
-      <stop id="stop9617" style="stop-color:#898A8C" offset="0.13804179"/>
-      <stop id="stop9619" style="stop-color:#ECECEC" offset="0.20296688"/>
-      <stop id="stop9621" style="stop-color:#FAFAFA" offset="0.33539036"/>
-      <stop id="stop9623" style="stop-color:#FFFFFF" offset="0.39464113"/>
-      <stop id="stop9625" style="stop-color:#FAFAFA" offset="0.5313"/>
-      <stop id="stop9627" style="stop-color:#EBECEC" offset="0.8449"/>
-      <stop id="stop9629" style="stop-color:#E1E2E3" offset="1"/>
-    </radialGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#radialGradient9613" id="linearGradient6125" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.8398488,-0.8398488,0.8167445,0.8167445,-15.712841,44.354581)" spreadMethod="reflect" x1="32.228344" y1="47.999996" x2="35.935673" y2="47.999996"/>
-    <filter inkscape:collect="always" id="filter4503">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="0.43775175" id="feGaussianBlur4505"/>
-    </filter>
-    <clipPath clipPathUnits="userSpaceOnUse" id="clipPath4092">
-      <path style="fill:#9c0f56" d="M 59.849,42.398 C 57.593,46.987 10.717,106.259 8.774,111.066 C 4.67,121.218 16.431,133.433 25.989,124.269 C 32.291,118.227 66.959,56.111 72.129,51.415 C 75.623,48.241 95.004,41.083 95.004,41.083 L 80.924,18.23 C 80.924,18.23 62.724,36.552 59.849,42.398 z" inkscape:r_cy="true" inkscape:r_cx="true" sodipodi:nodetypes="csssscc" id="path4094"/>
-    </clipPath>
-    <linearGradient id="XMLID_3_" gradientUnits="userSpaceOnUse" x1="11.9185" y1="119.0576" x2="98.418404" y2="44.057598">
-      <stop offset="0" style="stop-color:#C9C9C9" id="stop49"/>
-      <stop offset="0.0229" style="stop-color:#B2B2B2" id="stop51"/>
-      <stop offset="0.05" style="stop-color:#9F9F9F" id="stop53"/>
-      <stop offset="0.0819" style="stop-color:#929292" id="stop55"/>
-      <stop offset="0.1225" style="stop-color:#8A8A8A" id="stop57"/>
-      <stop offset="0.2012" style="stop-color:#888888" id="stop59"/>
-      <stop offset="1" style="stop-color:#686868;stop-opacity:1;" id="stop63"/>
-    </linearGradient>
-    <linearGradient id="XMLID_11_" gradientUnits="userSpaceOnUse" x1="31.4995" y1="80.0439" x2="32.347698" y2="80.671898" gradientTransform="translate(229.83849,405.96228)">
-      <stop offset="0" style="stop-color:#000000" id="stop183"/>
-      <stop offset="1" style="stop-color:#000000;stop-opacity:0;" id="stop185"/>
-    </linearGradient>
-    <linearGradient id="XMLID_10_" gradientUnits="userSpaceOnUse" x1="23.9844" y1="120.7646" x2="12.7283" y2="109.8655" gradientTransform="translate(229.83849,405.96228)">
-      <stop offset="0" style="stop-color:#EEEEEE" id="stop176"/>
-      <stop offset="1" style="stop-color:#535353;stop-opacity:1;" id="stop178"/>
-    </linearGradient>
-    <linearGradient id="XMLID_9_" gradientUnits="userSpaceOnUse" x1="18.776899" y1="129.5986" x2="18.776899" y2="114.6055" gradientTransform="translate(229.83849,405.96228)">
-      <stop offset="0" style="stop-color:#000000" id="stop169"/>
-      <stop offset="1" style="stop-color:#000000;stop-opacity:0;" id="stop171"/>
-    </linearGradient>
-    <radialGradient id="XMLID_8_" cx="64.988297" cy="15.9429" r="19.6182" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)">
-      <stop offset="0" style="stop-color:#FFFFFF" id="stop162"/>
-      <stop offset="1" style="stop-color:#888A85" id="stop164"/>
-    </radialGradient>
-    <linearGradient id="XMLID_7_" gradientUnits="userSpaceOnUse" x1="40.711899" y1="75.171898" x2="48.5495" y2="80.899803" gradientTransform="translate(229.83849,405.96228)">
-      <stop offset="0.213" style="stop-color:#555753" id="stop155"/>
-      <stop offset="1" style="stop-color:#000000" id="stop157"/>
-    </linearGradient>
-    <linearGradient id="path30758_1_" gradientUnits="userSpaceOnUse" x1="16.7803" y1="80.697304" x2="67.723602" y2="80.697304" gradientTransform="translate(229.83849,405.96228)">
-      <stop offset="0" style="stop-color:#888888" id="stop149"/>
-      <stop offset="0.8935" style="stop-color:#DDDDDD" id="stop151"/>
-    </linearGradient>
-    <linearGradient id="path34280_1_" gradientUnits="userSpaceOnUse" x1="93.023399" y1="39.3867" x2="93.023399" y2="25.928699" gradientTransform="translate(229.83849,405.96228)">
-      <stop offset="0" style="stop-color:#555555" id="stop141"/>
-      <stop offset="0.3965" style="stop-color:#888888" id="stop143"/>
-      <stop offset="1" style="stop-color:#555555" id="stop145"/>
-    </linearGradient>
-    <linearGradient id="rect22846_1_" gradientUnits="userSpaceOnUse" x1="247.60249" y1="-288.60791" x2="261.97269" y2="-288.60791" gradientTransform="matrix(0.9428,-0.2511,-0.2421,-0.9089,6.0921912,215.38258)">
-      <stop offset="0" style="stop-color:#888888" id="stop135"/>
-      <stop offset="1" style="stop-color:#555555" id="stop137"/>
-    </linearGradient>
-    <radialGradient id="rect14944_1_" cx="274.56641" cy="36.065399" r="6.8733001" gradientTransform="matrix(0.523,-0.2146,-2.627,-7.0521,27.4228,356.0237)" gradientUnits="userSpaceOnUse">
-      <stop offset="0" style="stop-color:#888A85" id="stop127"/>
-      <stop offset="0.6213" style="stop-color:#FFFFFF" id="stop129"/>
-      <stop offset="1" style="stop-color:#555753" id="stop131"/>
-    </radialGradient>
-    <radialGradient id="rect14938_1_" cx="290.8428" cy="36.069801" r="6.8736" gradientTransform="matrix(0.4892,-0.2059,-2.5913,-7.0931,29.692,361.6149)" gradientUnits="userSpaceOnUse">
-      <stop offset="0" style="stop-color:#888A85" id="stop119"/>
-      <stop offset="0.6213" style="stop-color:#FFFFFF" id="stop121"/>
-      <stop offset="1" style="stop-color:#555753" id="stop123"/>
-    </radialGradient>
-    <radialGradient id="rect10553_1_" cx="292.49219" cy="43.388699" r="6.8727999" gradientTransform="matrix(0.498,-0.2212,-2.9368,-8.3284,56.2613,466.2682)" gradientUnits="userSpaceOnUse">
-      <stop offset="0" style="stop-color:#888A85" id="stop111"/>
-      <stop offset="0.6213" style="stop-color:#FFFFFF" id="stop113"/>
-      <stop offset="1" style="stop-color:#555753" id="stop115"/>
-    </radialGradient>
-    <radialGradient id="rect14950_1_" cx="92.734398" cy="20.4307" r="4.1451998" gradientTransform="matrix(0.6131,-0.2916,-5.2659,-7.9645,125.0096,227.992)" gradientUnits="userSpaceOnUse">
-      <stop offset="0" style="stop-color:#FFFFFF" id="stop103"/>
-      <stop offset="0.5266" style="stop-color:#BABDB6" id="stop105"/>
-      <stop offset="1" style="stop-color:#888A85" id="stop107"/>
-    </radialGradient>
-    <radialGradient id="rect10551_3_" cx="78.776398" cy="44.608398" r="14.3205" gradientUnits="userSpaceOnUse">
-      <stop offset="0" style="stop-color:#2E3436" id="stop95"/>
-      <stop offset="0.72189999" style="stop-color:#000000;stop-opacity:1;" id="stop97"/>
-      <stop offset="1" style="stop-color:#2E3436" id="stop99"/>
-    </radialGradient>
-    <linearGradient id="rect10551_1_" gradientUnits="userSpaceOnUse" x1="77.216797" y1="44.765598" x2="73.449203" y2="30.555201">
-      <stop offset="0.7219" style="stop-color:#DDDDDD" id="stop89"/>
-      <stop offset="1" style="stop-color:#EEEEEC" id="stop91"/>
-    </linearGradient>
-    <radialGradient id="XMLID_6_" cx="77.004028" cy="13.140214" r="64.405701" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" fx="77.004028" fy="13.140214">
-      <stop offset="0" style="stop-color:#FFFFFF" id="stop82"/>
-      <stop id="stop13256" style="stop-color:#c3c4c2;stop-opacity:1;" offset="0.5"/>
-      <stop offset="1" style="stop-color:#000000;stop-opacity:1;" id="stop84"/>
-    </radialGradient>
-    <linearGradient id="XMLID_5_" gradientUnits="userSpaceOnUse" x1="15.7207" y1="125.7861" x2="24.9356" y2="108.3428" gradientTransform="translate(-80,0)">
-      <stop offset="0" style="stop-color:#000000" id="stop75"/>
-      <stop offset="0.8935" style="stop-color:#FFFFFF" id="stop77"/>
-    </linearGradient>
-    <linearGradient id="XMLID_4_" gradientUnits="userSpaceOnUse" x1="40.527802" y1="55.75" x2="52.981899" y2="64.646004" gradientTransform="translate(-80,0)">
-      <stop offset="0" style="stop-color:#ffffff;stop-opacity:0;" id="stop68"/>
-      <stop offset="0.8935" style="stop-color:#FFFFFF" id="stop70"/>
-    </linearGradient>
-    <linearGradient id="path2388_1_" gradientUnits="userSpaceOnUse" x1="14.9214" y1="124.6768" x2="107.7549" y2="-17.989599" gradientTransform="translate(229.83849,405.96228)">
-      <stop offset="0" style="stop-color:#DDDDDD" id="stop32"/>
-      <stop offset="0.6864" style="stop-color:#888888" id="stop34"/>
-      <stop offset="0.8935" style="stop-color:#DDDDDD" id="stop36"/>
-    </linearGradient>
-    <radialGradient id="path5936_1_" cx="172.123" cy="4.7476001" r="4.6967001" gradientTransform="matrix(6.7917,-1.4855,-1.2014,-5.506,-845.12621,725.19548)" gradientUnits="userSpaceOnUse">
-      <stop offset="0" style="stop-color:#FFFFFF" id="stop26"/>
-      <stop offset="1" style="stop-color:#3E3E3E" id="stop28"/>
-    </radialGradient>
-    <linearGradient id="XMLID_1_" gradientUnits="userSpaceOnUse" x1="92.627899" y1="26.589399" x2="104.5325" y2="31.2349" gradientTransform="translate(229.83849,405.96228)">
-      <stop offset="0" style="stop-color:#FFFFFF" id="stop19"/>
-      <stop offset="0.6391" style="stop-color:#888888" id="stop21"/>
-    </linearGradient>
-    <linearGradient id="rect25493_1_" gradientUnits="userSpaceOnUse" x1="258.88379" y1="-326.0903" x2="286.16019" y2="-287.6532" gradientTransform="matrix(0.9065,-0.2414,-0.2421,-0.9089,10.723991,214.40698)">
-      <stop offset="0" style="stop-color:#555555" id="stop5"/>
-      <stop offset="0.6864" style="stop-color:#888888" id="stop7"/>
-    </linearGradient>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_5_" id="linearGradient10549" gradientUnits="userSpaceOnUse" gradientTransform="translate(-80,0)" x1="15.7207" y1="125.7861" x2="24.9356" y2="108.3428"/>
-    <mask maskUnits="userSpaceOnUse" id="mask10545">
-      <path style="fill:url(#linearGradient10549)" id="path10547" d="M -0.051,18.554 L -0.847,9.66 C -0.847,9.66 8.141,4.482 10.38,3.193 C 3.985,-0.79 -3.654,1.07 -3.741,1.093 C -10.903,2.996 -15.908,8.865 -15.908,15.222 C -15.908,15.461 -15.901,15.701 -15.887,15.94 C -15.887,15.941 -15.887,15.941 -15.887,15.942 C -15.887,16.299 -16.25,36.73 -19.253,42.838 C -20.334,45.036 -30.401,58.18 -42.058,73.4 C -54.195,89.247 -69.3,108.968 -70.298,111.44 C -70.839,112.778 -71.079,114.126 -71.079,115.435 C -71.079,119.221 -69.06,122.663 -66.483,124.621 C -66.083,123.92 -65.655,123.178 -65.197,122.392 C -67.02,121.101 -68.463,119.074 -68.895,116.783 C -69.291,114.687 -68.831,112.48 -67.631,110.726 C -66.46,109.013 -64.659,107.855 -62.561,107.463 C -60.935,107.16 -59.182,107.593 -57.621,108.682 C -57.428,108.817 -57.245,108.966 -57.063,109.118 C -46.315,92.233 -27.938,65.35 3.195,23.824 C 1.323,20.784 -0.051,18.554 -0.051,18.554 z"/>
-    </mask>
-    <linearGradient inkscape:collect="always" xlink:href="#rect25493_1_" id="linearGradient11382" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.9065,-0.2414,-0.2421,-0.9089,10.723991,214.40698)" x1="258.88379" y1="-326.0903" x2="286.16019" y2="-287.6532"/>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_1_" id="linearGradient11384" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="92.627899" y1="26.589399" x2="104.5325" y2="31.2349"/>
-    <radialGradient inkscape:collect="always" xlink:href="#path5936_1_" id="radialGradient11386" gradientUnits="userSpaceOnUse" gradientTransform="matrix(6.7917,-1.4855,-1.2014,-5.506,-845.12621,725.19548)" cx="172.123" cy="4.7476001" r="4.6967001"/>
-    <linearGradient inkscape:collect="always" xlink:href="#path2388_1_" id="linearGradient11388" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="14.9214" y1="124.6768" x2="107.7549" y2="-17.989599"/>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_4_" id="linearGradient11390" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="77.040016" y1="14.124305" x2="92.612343" y2="4.8821697"/>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_4_" id="linearGradient11392" gradientUnits="userSpaceOnUse" gradientTransform="translate(-80,0)" x1="40.527802" y1="55.75" x2="52.981899" y2="64.646004"/>
-    <radialGradient inkscape:collect="always" xlink:href="#XMLID_6_" id="radialGradient11394" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4337031,0.4442839,-0.7150071,0.6987259,282.84098,375.70944)" cx="77.004028" cy="13.140214" fx="77.004028" fy="13.140214" r="64.405701"/>
-    <linearGradient inkscape:collect="always" xlink:href="#rect10551_1_" id="linearGradient11396" gradientUnits="userSpaceOnUse" x1="77.216797" y1="44.765598" x2="73.449203" y2="30.555201"/>
-    <radialGradient inkscape:collect="always" xlink:href="#rect10551_3_" id="radialGradient11398" gradientUnits="userSpaceOnUse" cx="78.776398" cy="44.608398" r="14.3205"/>
-    <radialGradient inkscape:collect="always" xlink:href="#rect14950_1_" id="radialGradient11400" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.6131,-0.2916,-5.2659,-7.9645,125.0096,227.992)" cx="92.734398" cy="20.4307" r="4.1451998"/>
-    <radialGradient inkscape:collect="always" xlink:href="#rect10553_1_" id="radialGradient11402" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.498,-0.2212,-2.9368,-8.3284,56.2613,466.2682)" cx="292.49219" cy="43.388699" r="6.8727999"/>
-    <radialGradient inkscape:collect="always" xlink:href="#rect14938_1_" id="radialGradient11404" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4892,-0.2059,-2.5913,-7.0931,29.692,361.6149)" cx="290.8428" cy="36.069801" r="6.8736"/>
-    <radialGradient inkscape:collect="always" xlink:href="#rect14944_1_" id="radialGradient11406" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.523,-0.2146,-2.627,-7.0521,27.4228,356.0237)" cx="274.56641" cy="36.065399" r="6.8733001"/>
-    <linearGradient inkscape:collect="always" xlink:href="#rect22846_1_" id="linearGradient11408" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.9428,-0.2511,-0.2421,-0.9089,6.0921912,215.38258)" x1="247.60249" y1="-288.60791" x2="261.97269" y2="-288.60791"/>
-    <linearGradient inkscape:collect="always" xlink:href="#path34280_1_" id="linearGradient11410" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="93.023399" y1="39.3867" x2="93.023399" y2="25.928699"/>
-    <linearGradient inkscape:collect="always" xlink:href="#path30758_1_" id="linearGradient11412" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="16.7803" y1="80.697304" x2="67.723602" y2="80.697304"/>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_7_" id="linearGradient11414" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="40.711899" y1="75.171898" x2="48.5495" y2="80.899803"/>
-    <radialGradient inkscape:collect="always" xlink:href="#XMLID_8_" id="radialGradient11416" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" cx="64.988297" cy="15.9429" r="19.6182"/>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_9_" id="linearGradient11418" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="18.776899" y1="129.5986" x2="18.776899" y2="114.6055"/>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_10_" id="linearGradient11420" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="17.509325" y1="123.23078" x2="18.875885" y2="107.20945"/>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_11_" id="linearGradient11422" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="31.4995" y1="80.0439" x2="32.347698" y2="80.671898"/>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_3_" id="linearGradient11424" gradientUnits="userSpaceOnUse" x1="11.9185" y1="119.0576" x2="98.418404" y2="44.057598"/>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4529" id="linearGradient11510" gradientUnits="userSpaceOnUse" x1="9.3031492" y1="133.25163" x2="-5.8540711" y2="130.59308"/>
-    <linearGradient inkscape:collect="always" xlink:href="#linearGradient4529" id="linearGradient11512" gradientUnits="userSpaceOnUse" x1="9.3031492" y1="133.25163" x2="-5.8540711" y2="130.59308"/>
-    <filter inkscape:collect="always" id="filter11957">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="2.339831" id="feGaussianBlur11959"/>
-    </filter>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_4_" id="linearGradient12019" gradientUnits="userSpaceOnUse" gradientTransform="translate(-80,0)" x1="40.527802" y1="55.75" x2="52.981899" y2="64.646004"/>
-    <linearGradient inkscape:collect="always" xlink:href="#path34280_1_" id="linearGradient12037" gradientUnits="userSpaceOnUse" gradientTransform="translate(229.83849,405.96228)" x1="93.023399" y1="39.3867" x2="93.023399" y2="25.928699"/>
-    <linearGradient inkscape:collect="always" xlink:href="#XMLID_3_" id="linearGradient12051" gradientUnits="userSpaceOnUse" x1="11.9185" y1="119.0576" x2="98.418404" y2="44.057598"/>
-    <filter inkscape:collect="always" id="filter12490">
-      <feGaussianBlur inkscape:collect="always" stdDeviation="2.3509538" id="feGaussianBlur12492"/>
-    </filter>
-  </defs>
-  <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1" inkscape:cx="13" inkscape:cy="18.5" inkscape:document-units="px" inkscape:current-layer="g11357" inkscape:window-width="1024" inkscape:window-height="697" inkscape:window-x="0" inkscape:window-y="0" height="128px" width="128px"/>
-  <metadata id="metadata5681">
-    <rdf:RDF>
-      <cc:Work rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g inkscape:label="Livello 1" inkscape:groupmode="layer" id="layer1">
-    <path style="fill:#000000;fill-opacity:1;filter:url(#filter12490);opacity:0.8" d="M 97.46875,6 C 97.18152,6.0094408 97.00831,6.0304757 97,6.03125 C 88.50154,6.7547259 81.81102,12.649899 80.96875,19.9375 C 80.96299,19.970198 76.86754,40.857308 72.875,46.3125 C 69.74177,50.594872 11.13376,102.7197 8.28125,107.28125 C 6.43475,110.23375 6.09196,113.64754 6.8125,116.75 C 6.81481,116.75995 6.81016,116.77131 6.8125,116.78125 C 7.27817,118.76618 8.16525,120.60725 9.40625,122.125 C 9.47154,122.20534 9.55786,122.26531 9.625,122.34375 C 9.73846,122.47566 9.85017,122.62373 9.96875,122.75 C 10.13123,122.9234 10.29696,123.08786 10.46875,123.25 C 10.78531,123.54834 11.12253,123.83716 11.46875,124.09375 C 11.51009,124.12442 11.55201,124.15746 11.59375,124.1875 C 11.75577,124.30387 11.92581,124.39345 12.09375,124.5 C 12.34901,124.66192 12.60676,124.83089 12.875,124.96875 C 12.90463,124.98396 12.93897,124.98509 12.96875,125 C 13.16389,125.09785 13.36099,125.19684 13.5625,125.28125 C 13.66656,125.32459 13.76932,125.36661 13.875,125.40625 C 13.96058,125.43847 14.03838,125.47026 14.125,125.5 C 14.26755,125.5489 14.41722,125.58297 14.5625,125.625 C 15.11282,125.78408 15.69527,125.91534 16.28125,125.96875 C 16.62585,125.99943 16.98844,126.00883 17.34375,126 C 17.49276,125.99631 17.6305,125.97967 17.78125,125.96875 C 18.30718,125.93117 18.83023,125.84877 19.375,125.71875 C 19.49773,125.68971 19.62642,125.65895 19.75,125.625 C 19.94658,125.5707 20.14518,125.50448 20.34375,125.4375 C 20.68974,125.32116 21.02361,125.18743 21.375,125.03125 C 21.51637,124.96837 21.67036,124.91327 21.8125,124.84375 C 22.01661,124.74364 22.23195,124.64533 22.4375,124.53125 C 22.50876,124.4917 22.58484,124.44751 22.65625,124.40625 C 22.93651,124.24411 23.21755,124.06393 23.5,123.875 C 23.72992,123.72139 24.01123,123.49888 24.3125,123.25 C 24.51715,123.08053 24.76474,122.86659 25,122.65625 C 25.31217,122.37641 25.73134,121.97195 26.09375,121.625 C 26.40496,121.32709 26.7476,121.00087 27.09375,120.65625 C 27.10095,120.64393 27.11785,120.63734 27.125,120.625 C 40.39609,107.39872 78.3196,61.213642 83.8125,57.75 C 87.95646,55.136652 109.0625,51.3125 109.0625,51.3125 C 113.21925,49.41573 118.90506,43.445638 121.3125,34.4375 C 121.72869,32.077134 121.4811,29.596922 121.375,30.03125 L 108.59375,35.78125 L 100.21875,29.0625 L 98.78125,25.40625 L 99.28125,19.21875 L 113.34375,13.96875 L 113.125,12.15625 C 107.67312,6.0868239 99.47934,5.9339145 97.46875,6 z M 17.8125,106.1875 C 21.2472,106.15572 24.40096,109.89596 24.375,114.15625 C 24.3535,117.67982 20.93573,121.18715 17.5,121.21875 C 14.06408,121.25138 10.73518,117.39784 10.6875,113.53125 C 10.68465,113.29896 10.66822,113.04283 10.6875,112.8125 C 10.70682,112.58223 10.74047,112.35167 10.78125,112.125 C 10.90349,111.44483 11.13404,110.80542 11.4375,110.1875 C 11.53867,109.98155 11.63003,109.78948 11.75,109.59375 C 12.94961,107.63625 15.09816,106.21329 17.8125,106.1875 z" id="path11963"/>
-    <g id="g11357" transform="matrix(1.0223499,0.1802679,-0.1801715,1.0218034,-142.50883,-466.04399)">
-      <path style="fill:url(#linearGradient11382)" d="M 322.52649,444.25728 C 326.15949,443.01428 332.35849,434.45128 332.98149,424.78428 C 333.00949,424.35428 333.65649,426.67828 333.65649,428.98828 C 332.87949,437.94128 328.47049,444.55028 324.84449,447.04628 L 322.52649,444.25728 z" inkscape:r_cy="true" inkscape:r_cx="true" sodipodi:nodetypes="csssc" id="rect25493"/>
-      <path style="fill:#888a85" d="M 332.98149,424.78428 L 321.82849,432.38828 L 312.74849,427.41628 C 312.08149,428.88428 315.95449,447.98028 320.22749,446.96228 C 328.04849,445.09828 332.16349,435.78528 332.98149,424.78428 z" inkscape:r_cy="true" inkscape:r_cx="true" sodipodi:nodetypes="cccsc" id="path3285"/>
-      <path style="fill:url(#linearGradient11384)" id="path23" d="M 322.07549,432.68428 L 323.06949,441.37828 L 324.97749,444.59028 C 326.91449,443.03428 328.49449,440.87628 329.72849,438.28428 C 331.33649,434.63428 332.30349,430.21428 332.65649,425.47228 L 322.07549,432.68428 z" enable-background="new    "/>
-      <path style="opacity:0.51380005;fill:url(#radialGradient11386)" d="M 313.59749,428.19228 C 313.59449,428.19728 313.57749,428.21928 313.57649,428.22628 C 313.57149,428.23928 313.56449,428.27228 313.56049,428.28828 C 313.04649,430.36728 316.00549,448.15728 320.19449,447.15928 C 321.12049,446.93828 322.00949,446.60928 322.83249,446.18928 L 320.58049,431.94628 L 313.59749,428.19228 z" enable-background="new    " inkscape:r_cy="true" inkscape:r_cx="true" id="path5936"/>
-      <path style="fill:url(#linearGradient11388)" d="M 305.84149,406.08928 C 297.90049,408.19828 292.53349,414.90528 292.95349,421.96328 C 292.95349,421.99528 292.56249,442.51428 289.68749,448.36028 C 287.43149,452.94928 240.55549,512.22128 238.61249,517.02828 C 234.50849,527.18028 246.26949,539.39528 255.82749,530.23128 C 262.12949,524.18928 296.79749,462.07328 301.96749,457.37728 C 305.46149,454.20328 324.84249,447.04528 324.84249,447.04528 L 310.76249,424.19228 L 310.04449,416.17028 L 322.15949,409.19128 C 315.08849,403.65028 305.90349,406.07228 305.84149,406.08928 z M 247.46049,514.40928 C 250.71349,513.80428 254.33749,516.82428 255.02549,520.87228 C 255.59449,524.22028 252.93349,528.13028 249.67949,528.73528 C 246.42549,529.34128 242.61749,526.22128 241.92549,522.55928 C 241.26149,519.04028 243.34849,515.17628 247.46049,514.40928 z" inkscape:r_cy="true" inkscape:r_cx="true" sodipodi:nodetypes="cccssssccccssssccssss" id="path2388"/>
-      <path transform="translate(309.83849,405.96228)" mask="url(#mask10545)" style="fill:url(#linearGradient11392)" id="path72" d="M -0.051,18.554 L -0.847,9.66 C -0.847,9.66 8.141,4.482 10.38,3.193 C 3.985,-0.79 -3.654,1.07 -3.741,1.093 C -10.903,2.996 -15.908,8.865 -15.908,15.222 C -15.908,15.461 -15.901,15.701 -15.887,15.94 C -15.887,15.941 -15.887,15.941 -15.887,15.942 C -15.887,16.299 -16.25,36.73 -19.253,42.838 C -20.334,45.036 -30.401,58.18 -42.058,73.4 C -54.195,89.247 -69.3,108.968 -70.298,111.44 C -70.839,112.778 -71.079,114.126 -71.079,115.435 C -71.079,119.221 -69.06,122.663 -66.483,124.621 C -66.083,123.92 -65.655,123.178 -65.197,122.392 C -67.02,121.101 -68.463,119.074 -68.895,116.783 C -69.291,114.687 -68.831,112.48 -67.631,110.726 C -66.46,109.013 -64.659,107.855 -62.561,107.463 C -60.935,107.16 -59.182,107.593 -57.621,108.682 C -57.428,108.817 -57.245,108.966 -57.063,109.118 C -46.315,92.233 -27.938,65.35 3.195,23.824 C 1.323,20.784 -0.051,18.554 -0.051,18.554 z"/>
-      <path style="fill:url(#radialGradient11394)" id="path86" d="M 310.76249,424.19228 L 310.04449,416.17028 L 322.15949,409.19128 C 320.21949,407.64028 317.84449,406.51628 315.23549,405.92928 C 312.04649,405.90828 308.79349,406.38428 306.47749,407.16528 C 298.74149,409.77428 294.69849,415.49528 294.85149,422.31128 L 303.63249,437.15128 L 306.31749,435.47228 L 312.56749,446.29728 L 310.37649,447.80128 L 313.73849,451.42828 L 324.84249,447.04628 L 310.76249,424.19228 z"/>
-      <polygon transform="translate(229.83849,405.96228)" style="fill:url(#linearGradient11396)" points="65.82,36.446 76.487,27.791 85.179,40.128 72.511,46.783 65.82,36.446 " inkscape:r_cy="true" inkscape:r_cx="true" id="rect10551_2_"/>
-      <polygon transform="translate(229.83849,405.96228)" style="fill:url(#radialGradient11398)" points="65.82,36.446 76.487,29.791 83.179,40.128 72.511,46.783 65.82,36.446 " inkscape:r_cy="true" inkscape:r_cx="true" id="rect10551"/>
-      <polygon transform="translate(229.83849,405.96228)" style="fill:url(#radialGradient11400)" points="68.311,35.653 74.616,32.078 80.237,40.809 73.932,44.384 68.311,35.653 " inkscape:r_cy="true" inkscape:r_cx="true" id="rect14950"/>
-      <polygon transform="translate(229.83849,405.96228)" style="fill:url(#radialGradient11402)" points="67.891,36.615 77.497,32.233 77.891,33.323 68.284,37.705 67.891,36.615 " inkscape:r_cy="true" inkscape:r_cx="true" id="rect10553"/>
-      <polygon transform="translate(229.83849,405.96228)" style="fill:url(#radialGradient11404)" points="72.212,42.972 81.653,38.899 82.001,39.827 72.56,43.9 72.212,42.972 " inkscape:r_cy="true" inkscape:r_cx="true" id="rect14938"/>
-      <polygon transform="translate(229.83849,405.96228)" style="fill:url(#radialGradient11406)" points="69.661,39.991 79.757,35.751 80.11,36.673 70.015,40.914 69.661,39.991 " inkscape:r_cy="true" inkscape:r_cx="true" id="rect14944"/>
-      <path style="fill:url(#linearGradient11410)" d="M 320.80249,431.89128 C 320.76149,432.16128 322.10049,439.91928 322.18149,440.18928 C 322.85449,444.45728 323.83149,444.59528 324.03549,445.34928 C 324.76349,444.93528 324.29249,445.39528 324.92349,444.84628 C 324.80849,444.48028 323.48549,441.99528 322.95849,441.11128 C 322.71249,438.97728 321.93149,433.00328 321.86449,432.43528 C 321.45549,432.21328 321.29849,432.12528 320.80249,431.89128 z" inkscape:r_cy="true" inkscape:r_cx="true" sodipodi:nodetypes="ccccccc" id="path34280"/>
-      <path style="fill:url(#linearGradient11412)" d="M 246.62049,511.92528 C 251.42949,510.02428 257.88249,515.30428 257.53849,521.11028 C 260.82449,517.31028 296.88449,460.33528 297.44649,457.74428 C 298.30649,453.77728 294.17949,450.82228 290.89849,452.88728 C 288.60949,454.32628 246.30749,512.04828 246.62049,511.92528 z" inkscape:r_cy="true" inkscape:r_cx="true" sodipodi:nodetypes="ccsss" id="path30758"/>
-      <path style="fill:url(#linearGradient11414);stroke:#000000" id="path159" d="M 292.02849,454.56028 C 289.53249,456.91828 266.85449,487.60628 250.66249,509.77928 C 252.02149,510.08228 253.37949,510.67028 254.63749,511.58128 C 256.37949,512.84228 257.66849,514.51428 258.50849,516.33428 C 267.27449,503.42428 294.06749,460.80328 295.50149,457.24628 C 295.53749,457.05828 295.56249,456.87128 295.56249,456.69028 C 295.56249,455.85828 295.18949,455.11828 294.50449,454.63828 C 293.74349,454.10528 292.82549,454.08928 292.02849,454.56028 z"/>
-      <path style="fill:url(#radialGradient11416)" id="path166" d="M 294.94349,422.46628 C 294.86849,425.66728 294.31649,443.48028 291.48249,449.24328 C 291.40649,449.39728 291.28449,449.60828 291.13649,449.84928 C 291.56049,449.26728 291.86549,448.81828 292.01449,448.54228 C 294.75749,443.48028 297.55549,430.48328 297.76449,427.23428 L 294.94349,422.46628 z"/>
-      <path style="opacity:0.5;fill:url(#linearGradient11418)" id="path173" d="M 258.69149,526.59428 C 259.24949,525.08628 259.45349,523.49328 259.17549,521.97428 C 258.59949,518.81928 256.61749,515.87328 253.87449,514.09028 C 251.69549,512.67428 249.24349,512.11128 246.97049,512.50528 C 244.03849,513.01528 241.52249,514.52228 239.88549,516.74928 C 238.45149,518.70028 237.78049,521.08528 237.96049,523.44028 C 239.33149,531.34628 248.26549,537.48228 255.82849,530.23128 C 256.49049,529.59728 257.46949,528.33628 258.69149,526.59428 z M 249.67949,528.73528 C 246.42549,529.34128 242.61749,526.22128 241.92549,522.55928 C 241.26049,519.03928 243.34749,515.17528 247.46049,514.40928 C 250.71349,513.80428 254.33749,516.82428 255.02549,520.87228 C 255.59449,524.22028 252.93349,528.13028 249.67949,528.73528 z"/>
-      <path style="fill:url(#linearGradient11420)" id="path180" d="M 256.01149,520.70428 C 255.59949,518.27928 254.18149,516.01528 252.21849,514.64428 C 250.65849,513.55528 248.90449,513.12328 247.27849,513.42528 C 245.18049,513.81728 243.38049,514.97528 242.20849,516.68828 C 241.00949,518.44128 240.54849,520.64928 240.94449,522.74528 C 241.75449,527.03328 246.08849,530.42228 249.86349,529.71928 C 253.62049,529.02028 256.66649,524.55528 256.01149,520.70428 z M 249.67949,528.73528 C 246.42549,529.34128 242.61749,526.22128 241.92549,522.55928 C 241.26049,519.03928 243.34749,515.17528 247.46049,514.40928 C 250.71349,513.80428 254.33749,516.82428 255.02549,520.87228 C 255.59449,524.22028 252.93349,528.13028 249.67949,528.73528 z"/>
-      <path style="opacity:0.4;fill:url(#linearGradient11422)" id="path187" d="M 285.39049,455.48028 C 285.64549,454.95828 285.88049,454.31028 286.09549,453.56728 C 274.64749,469.16528 240.27149,512.92628 238.61349,517.02828 C 238.29049,517.82728 238.07649,518.63728 237.94149,519.45128 C 242.96749,511.10428 283.36449,459.62828 285.39049,455.48028 z"/>
-      <path transform="translate(229.83849,405.96228)" clip-path="url(#clipPath4092)" style="fill:url(#linearGradient11424);filter:url(#filter4503)" id="path65" d="M 72.13,49.416 C 66.96,54.112 32.292,116.228 25.99,122.27 C 18.09,129.844 8.695,122.813 7.986,114.414 C 7.207,123.618 17.468,132.44 25.99,124.27 C 32.292,118.228 66.96,56.112 72.13,51.416 C 75.624,48.242 95.005,41.084 95.005,41.084 L 94.004,39.459 C 90.005,40.965 75.147,46.674 72.13,49.416 z"/>
-      <path style="fill:url(#linearGradient11408)" d="M 310.04449,416.17028 L 322.15949,409.19128 L 322.67749,410.88528 L 310.13349,418.26728 L 310.04449,416.17028 z" inkscape:r_cy="true" inkscape:r_cx="true" sodipodi:nodetypes="ccccc" id="rect22846"/>
-      <path style="fill:url(#linearGradient11390);fill-opacity:1" id="path46" d="M 310.21449,416.07228 L 322.15949,409.19128 C 321.63949,408.78428 321.10749,408.43228 320.56949,408.10728 L 310.04449,414.17028 L 310.21449,416.07228 z"/>
-    </g>
-    <path style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.47008219000000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998000000000;stroke-opacity:1;filter:url(#filter11957);opacity:0.80000000000000004" d="M 10.375,9 L 4.21875,15.46875 L 9.125,23.1875 C 13.08003,25.264868 17.14186,27.693549 20.375,30.75 L 69.625,77.3125 L 65.5625,81.5625 L 70.8125,86.53125 C 73.7103,86.859904 76.69384,88.078409 79.15625,90.40625 C 81.64614,92.760071 83.16605,95.732279 83.625,98.625 L 108.34375,122.03125 C 114.08456,127.45836 128.43479,112.52526 122.65625,107.0625 L 97.90625,83.6875 C 94.97813,83.378226 91.9274,82.010074 89.4375,79.65625 C 86.9751,77.328414 85.57063,74.424084 85.09375,71.5625 L 79.84375,66.59375 L 75.78125,70.84375 L 26.53125,24.28125 C 23.29811,21.224799 20.16307,17.382339 18.375,13.53125 L 10.375,9 z" id="path11428"/>
-    <g id="g10397" transform="matrix(0.9660937,-2.5302336e-2,2.3546854e-2,0.9608617,2.3338765,6.1294086)">
-      <path id="rect3006" d="M 1.750754,7.673054 L 6.651221,15.840499 C 10.689771,18.10883 14.818666,20.740966 18.085644,24.007944 L 103.30145,109.22375 L 109.83541,102.68979 L 24.6196,17.473988 C 21.352622,14.20701 18.204176,10.093654 16.452155,6.039565 L 8.28471,1.139098 L 1.750754,7.673054 z" style="fill:url(#linearGradient6125);fill-opacity:1;stroke:none;stroke-width:0.47008219;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1" sodipodi:nodetypes="ccccccccc"/>
-      <rect transform="matrix(0.7071068,-0.7071068,-0.7071068,-0.7071068,0,0)" style="fill:url(#linearGradient6122);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1" id="rect3912" width="1.1166428" height="98.671562" x="-1.357038" y="-123.11634"/>
-      <rect style="opacity:0.3857678;fill:url(#linearGradient6119);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1" id="rect4944" width="1.6020314" height="63.508739" x="0.89394951" y="-85.707031" transform="matrix(-0.7071068,0.7071068,-0.7071068,-0.7071068,0,0)"/>
-      <g transform="matrix(0.8167445,-0.8167445,0.8167445,0.8167445,5.2761549,23.749521)" clip-path="url(#clipPath3850)" id="g3842">
-        <path style="fill:#535557;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter3834)" d="M 4.296875,-4.12891 L 5.6640625,-4.12891 C 8.3203089,-0.31380448 8.5987355,3.8409896 7.6171875,8.17578 L 4.9804688,9.1523436 L 4.296875,-4.12891 z" id="path3726" sodipodi:nodetypes="ccccc"/>
-        <path sodipodi:nodetypes="ccccc" id="path3728" d="M 18.977324,-4.12891 L 17.610137,-4.12891 C 14.95389,-0.31380448 14.675464,3.8409896 15.657012,8.17578 L 18.293731,9.1523436 L 18.977324,-4.12891 z" style="fill:#535557;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter3838)"/>
-        <path style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter3838)" d="M 18.977324,-4.12891 L 18.231618,-4.0598566 C 16.117808,-1.3279433 15.743286,-1.0597872 15.864172,4.9302704 L 18.293731,9.1523436 L 18.977324,-4.12891 z" id="path3969" sodipodi:nodetypes="ccccc"/>
-      </g>
-      <rect transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,0,0)" y="41.331993" x="0.84851468" height="109.04897" width="1.9142449" id="rect3886" style="fill:url(#linearGradient6112);fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1"/>
-      <path transform="matrix(0.8167445,-0.8167445,0.8167445,0.8167445,-14.584136,43.609812)" id="path3925" d="M 32,-12 L 30,-4 C 34.143852,8.2009511 38.115959,5.0342786 42,-4 L 40,-12 L 32,-12 z" style="fill:url(#linearGradient3943);fill-opacity:1;stroke:url(#linearGradient6517);stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1" sodipodi:nodetypes="ccccc"/>
-      <path sodipodi:nodetypes="ccsccccsccc" id="rect3956" d="M 63.529919,78.09273 L 68.834311,83.397123 C 71.82354,83.817882 74.899226,85.18508 77.387407,87.673261 C 79.903365,90.189215 81.385477,93.328601 81.786903,96.34972 L 106.78156,121.34436 C 112.58247,127.14528 127.79361,112.01036 121.95458,106.17133 L 96.95993,81.176682 C 93.938823,80.775254 90.799446,79.29314 88.283481,76.777186 C 85.795299,74.289007 84.428105,71.213314 84.007344,68.22409 L 78.70295,62.919697 L 63.529919,78.09273 z" style="opacity:1;fill:url(#linearGradient4190);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1"/>
-      <path transform="matrix(0.9483145,-0.9483145,0.9483145,0.9483145,-6.4444639,0.531831)" clip-path="url(#clipPath4242)" sodipodi:nodetypes="cccccc" id="path4196" d="M -8,120 C 1.7462188,130.07566 10.00314,126.89342 16,120 L 12,136 L -16,128 L -20,112 L -8,120 z" style="fill:#ffa700;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4238)"/>
-      <rect transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,0,0)" y="100.16766" x="-10.297462" height="1.1132338" width="21.457907" id="rect4249" style="opacity:0.48689138;fill:#ffa500;fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1"/>
-      <path sodipodi:nodetypes="ccccccc" id="rect4320" d="M 72.972033,68.720893 L 75.892922,65.800004 L 81.066844,70.973925 C 80.921148,71.564914 80.822369,72.165286 81.579665,72.936868 L 79.073097,75.857759 C 78.372014,75.392484 77.997186,74.796708 78.21501,73.963871 L 72.972033,68.720893 z" style="opacity:0.83895126;fill:url(#linearGradient4346);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:1.08779998;stroke-opacity:1"/>
-      <path sodipodi:nodetypes="ccccc" id="rect4340" d="M 4.6713727,129.88196 L 7.2816355,129.49996 C 7.2464436,130.37087 7.2584731,130.8014 7.8438776,132.01123 L 5.1273299,132.01123 C 4.7973883,130.83537 4.6035939,130.49599 4.6713727,129.88196 z" style="opacity:0.74531836;fill:url(#linearGradient4342);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:1.08779998;stroke-opacity:1;filter:url(#filter4404)" transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,-4,-4)"/>
-      <rect transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,0,0)" y="126.0467" x="-0.6434837" height="0.390625" width="10.644531" id="rect4432" style="opacity:1;fill:url(#radialGradient4440);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1"/>
-      <path sodipodi:nodetypes="ccc" id="path4454" d="M 83.597656,68.53125 L 68.753906,82.984375 C 84.820174,88.576948 78.33289,74.329762 83.597656,68.53125 z" style="fill:url(#linearGradient4471);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4501)"/>
-      <path transform="matrix(-1,0,0,-1,169.63281,168.51104)" style="fill:url(#linearGradient4515);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4501)" d="M 87.597656,72.53125 L 72.753906,86.984375 C 88.820174,92.576948 82.33289,78.329762 87.597656,72.53125 z" id="path4505" sodipodi:nodetypes="ccc"/>
-      <rect transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,0,0)" ry="2.9279406" rx="2.9279406" y="132.02951" x="-7.5001087" height="29.279404" width="5.8558812" id="rect4517" style="opacity:0.83895126;fill:url(#linearGradient4525);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1"/>
-      <rect inkscape:transform-center-y="-5.5242717" inkscape:transform-center-x="-16.434708" transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,-4,-4)" ry="0.5577029" rx="2.9279406" y="130.97287" x="-1.1929667" height="1.1048541" width="11.60097" id="rect4527" style="opacity:0.83895126;fill:url(#linearGradient4537);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1;filter:url(#filter4551)"/>
-      <path transform="translate(50.492188,-4.0046875)" clip-path="url(#clipPath4588)" id="path4559" d="M 13.83125,81.09375 L 12.33125,82.59375 L 17.64375,87.90625 C 20.632979,88.327007 23.718069,89.699319 26.20625,92.1875 C 28.722207,94.703451 30.179824,97.822631 30.58125,100.84375 L 55.58125,125.84375 C 59.791769,130.05428 68.947177,123.22603 71.425,116.9375 C 68.058606,122.54366 60.345306,127.60781 56.58125,123.84375 L 31.58125,98.84375 C 31.179824,95.822631 29.722207,92.703451 27.20625,90.1875 C 24.718069,87.699319 21.632979,86.327007 18.64375,85.90625 L 13.83125,81.09375 z" style="opacity:1;fill:#996100;fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1;filter:url(#filter4584)"/>
-      <rect style="opacity:0.576779;fill:url(#radialGradient4602);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1" id="rect4596" width="10.644531" height="0.390625" x="-0.091056541" y="100.35886" transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,0,0)"/>
-      <rect clip-path="url(#clipPath4632)" style="opacity:0.576779;fill:url(#linearGradient4604);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1;filter:url(#filter4626)" id="rect4598" width="12.602244" height="4.0530515" x="-1.1929667" y="129.5918" rx="0" ry="0" transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,-21.221011,-22.313001)" inkscape:transform-center-x="-16.434708" inkscape:transform-center-y="-5.5242717"/>
-      <rect inkscape:transform-center-y="-5.5242717" inkscape:transform-center-x="-16.434708" transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,-21.321011,-22.413001)" ry="0" rx="0" y="130.07516" x="3.1573973" height="1.7051741" width="7.9066095" id="rect4638" style="opacity:0.576779;fill:url(#linearGradient4640);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1;filter:url(#filter4626)" clip-path="url(#clipPath4632)"/>
-      <path sodipodi:nodetypes="ccccc" style="fill:url(#linearGradient6930);fill-opacity:1;stroke:none;stroke-width:0.30655462;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1" d="M 2.9032773,7.9724105 L 7.1391831,15.032254 C 18.678358,20.720438 19.246981,15.680572 15.610994,6.5604419 L 8.5511516,2.3245361 L 2.9032773,7.9724105 z" id="path6537"/>
-      <rect style="opacity:0.83895126;fill:url(#linearGradient7698);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1" id="rect7696" width="5.8558812" height="29.279404" x="4.5207062" y="132.73663" rx="2.9279406" ry="2.9279406" transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,0,0)"/>
-      <rect style="opacity:0.95131088;fill:url(#linearGradient4338);fill-opacity:1;stroke:none;stroke-width:0.37;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1" id="rect4336" width="2.5833137" height="38.179485" x="0.94721299" y="126.14276" transform="matrix(0.7071068,-0.7071068,0.7071068,0.7071068,0,0)"/>
-    </g>
-  </g>
-</svg>
\ No newline at end of file
diff --git a/utils/nwztools/plattools/data/make_images.sh b/utils/nwztools/plattools/data/make_images.sh
deleted file mode 100755
index 7ac21dc..0000000
--- a/utils/nwztools/plattools/data/make_images.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/bash
-#
-# This script contains the code used to produce all the images.
-# Because of the variety of tools needed to achieve that, the result is also
-# included in the repository but this makes it easier to modify the data
-# to add more content
-#
-
-# path to root of repository
-ROOT_DIR=../../../../
-
-# final resolution
-NWZ_WIDTH=130
-NWZ_HEIGHT=130
-
-# path to rockbox icon
-RB_ICON_PATH=$ROOT_DIR/docs/logo/rockbox-icon.svg
-# path to tools icon (currently stolen from KDE Oxygen icon set)
-TOOL_ICON_PATH=Oxygen480-categories-preferences-system.svg
-
-# convert_svg width height input output
-function convert_svg
-{
-    local width="$1"
-    local height="$2"
-    local input="$3"
-    local output="$4"
-    TMP=tmp.png
-    # convert from SVG to PNG
-    inkscape -z -e $TMP -w $width -h $height $input
-    if [ "$?" != 0 ]; then
-        echo "SVG -> PNG conversion failed"
-        exit 1
-    fi
-    # convert from PNG to BMP, force using "version 3" because the OF don't like
-    # "recent" BMP
-    convert -channel RGB $TMP -define bmp:format=bmp3 ${output}_icon.bmp
-    if [ "$?" != 0 ]; then
-        rm -f $TMP
-        echo "PNG -> BMP conversion failed"
-        exit 1
-    fi
-    # remove temporary
-    rm -f $TMP
-}
-
-# start by creating the bitmap files from rockbox-icon.svg for all resolutions
-# we make a detour by svg because inkscape can only export to SVG
-# NOTE: we use image magick to convert to bmp but the OF tools don't like BMPv5
-# and contrary to what the documentation says, image magick tends to produce
-# those by default unless asked otherwise
-convert_svg $NWZ_WIDTH $NWZ_HEIGHT $RB_ICON_PATH rockbox
-convert_svg $NWZ_WIDTH $NWZ_HEIGHT $TOOL_ICON_PATH tools
diff --git a/utils/nwztools/plattools/dest_tool.c b/utils/nwztools/plattools/dest_tool.c
deleted file mode 100644
index 9fb075e..0000000
--- a/utils/nwztools/plattools/dest_tool.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2016 Amaury Pouly
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include <string.h>
-#include <stdlib.h>
-#include "nwz_plattools.h"
-
-static unsigned long read32(unsigned char *buf)
-{
-    return buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
-}
-
-static void write32(unsigned char *buf, unsigned long value)
-{
-    buf[0] = value & 0xff;
-    buf[1] = (value >> 8) & 0xff;
-    buf[2] = (value >> 16) & 0xff;
-    buf[3] = (value >> 24) & 0xff;
-}
-
-static struct
-{
-    unsigned long dest;
-    const char *name;
-} g_dest_list[] =
-{
-    { 0, "J" },
-    { 1, "U" },
-    { 0x101, "U2" },
-    { 0x201, "U3" },
-    { 0x301, "CA" },
-    { 2, "CEV" },
-    { 0x102, "CE7" },
-    { 3, "CEW" },
-    { 0x103, "CEW2" },
-    { 4, "CN" },
-    { 5, "KR" },
-    { 6, "E" },
-    { 0x106, "MX" },
-    { 0x206, "E2" },
-    { 0x306, "MX3" },
-    { 7, "TW" },
-};
-
-#define NR_DEST (sizeof(g_dest_list) / sizeof(g_dest_list[0]))
-
-static int get_dest_index(unsigned long dest)
-{
-    for(size_t i = 0; i < NR_DEST; i++)
-        if(g_dest_list[i].dest == dest)
-            return i;
-    return -1;
-}
-
-static const char *get_dest_name(unsigned long dest)
-{
-    int index = get_dest_index(dest);
-    return index < 0 ? "NG" : g_dest_list[index].name;
-}
-
-int NWZ_TOOL_MAIN(dest_tool)(int argc, char **argv)
-{
-    /* clear screen and display welcome message */
-    nwz_lcdmsg(true, 0, 0, "dest_tool");
-    /* open input device */
-    int input_fd = nwz_key_open();
-    if(input_fd < 0)
-    {
-        nwz_lcdmsg(false, 3, 4, "Cannot open input device");
-        sleep(2);
-        return 1;
-    }
-    unsigned long model_id = nwz_get_model_id();
-    if(model_id == 0)
-    {
-        nwz_key_close(input_fd);
-        nwz_lcdmsg(false, 3, 4, "Cannot get model ID");
-        sleep(2);
-        return 1;
-    }
-    const char *model_name = nwz_get_model_name();
-    if(model_name == NULL)
-        model_name = "Unknown";
-    const char *series_name = "Unknown";
-    bool ok_model = false;
-    if(nwz_get_series() != -1)
-    {
-        series_name = nwz_series[nwz_get_series()].name;
-        ok_model = true;
-    }
-    nwz_lcdmsgf(false, 0, 2, "Model ID: %#x", model_id);
-    nwz_lcdmsgf(false, 0, 3, "Model: %s", model_name);
-    nwz_lcdmsgf(false, 0, 4, "Series: %s", series_name);
-    nwz_lcdmsg(false, 0, 5, "BACK: quit");
-    nwz_lcdmsg(false, 0, 6, "LEFT/RIGHT: change dest");
-    nwz_lcdmsg(false, 0, 7, "PLAY/PAUSE: change sps");
-    /* display input state in a loop */
-    while(1)
-    {
-        unsigned char nvp_buf[32];
-        bool ok_nvp = false;
-        if(ok_model)
-        {
-            /* make sure node has the right size... */
-            if(nwz_nvp_read(NWZ_NVP_SHP, NULL) == sizeof(nvp_buf))
-            {
-                if(nwz_nvp_read(NWZ_NVP_SHP, nvp_buf) == sizeof(nvp_buf))
-                    ok_nvp = true;
-                else
-                    nwz_lcdmsg(false, 1, 9, "Cannot read NVP.\n");
-            }
-            else
-                nwz_lcdmsg(false, 1, 9, "NVP node has the wrong size.\n");
-        }
-        else
-        {
-            nwz_lcdmsg(false, 1, 9, "Your model is not supported.\n");
-            nwz_lcdmsg(false, 1, 10, "Please contact a developer.\n");
-        }
-        /* display information */
-        if(ok_nvp)
-        {
-            unsigned long dest = read32(nvp_buf);
-            unsigned long sps = read32(nvp_buf + 4);
-            const char *dest_name = get_dest_name(dest);
-            const char *sps_name = sps ? "ON" : "OFF";
-            nwz_lcdmsgf(false, 1, 9, "DEST: %s (%#x)     ", dest_name, dest);
-            nwz_lcdmsgf(false, 1, 10, "SPS: %s (%d)     ", sps_name, sps);
-        }
-        /* wait for event */
-        int ret = nwz_key_wait_event(input_fd, -1);
-        if(ret != 1)
-            continue;
-        struct input_event evt;
-        if(nwz_key_read_event(input_fd, &evt) != 1)
-            continue;
-        /* only act on release */
-        if(nwz_key_event_is_press(&evt))
-            continue;
-        int keycode = nwz_key_event_get_keycode(&evt);
-        if(keycode == NWZ_KEY_BACK)
-            break;
-        bool write_nvp = false;
-        if(keycode == NWZ_KEY_LEFT || keycode == NWZ_KEY_RIGHT)
-        {
-            int dest_idx = get_dest_index(read32(nvp_buf));
-            /* if destination is unknown, replace by the first one */
-            if(dest_idx == -1)
-                dest_idx = 0;
-            if(keycode == NWZ_KEY_LEFT)
-                dest_idx--;
-            else
-                dest_idx++;
-            dest_idx = (dest_idx + NR_DEST) % NR_DEST;
-            write32(nvp_buf, g_dest_list[dest_idx].dest);
-            write_nvp = true;
-        }
-        else if(keycode == NWZ_KEY_PLAY)
-        {
-            /* change 0 to 1 and anything nonzero to 0 */
-            write32(nvp_buf + 4, read32(nvp_buf + 4) == 0 ? 1 : 0);
-            write_nvp = true;
-        }
-        /* write nvp */
-        if(ok_nvp && write_nvp)
-        {
-            if(nwz_nvp_write(NWZ_NVP_SHP, nvp_buf) != 0)
-                nwz_lcdmsg(false, 1, 12, "Cannot write NVP.\n");
-        }
-    }
-    /* finish nicely */
-    nwz_key_close(input_fd);
-    return 0;
-}
diff --git a/utils/nwztools/plattools/dualboot.c b/utils/nwztools/plattools/dualboot.c
deleted file mode 100644
index c6d07c7..0000000
--- a/utils/nwztools/plattools/dualboot.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2011 by Amaury Pouly
- *
- * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
- * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_plattools.h"
-#include <time.h>
-#include <errno.h>
-
-/* all images must have the following size */
-#define ICON_WIDTH  130
-#define ICON_HEIGHT 130
-
-/* images */
-#include "data/rockbox_icon.h"
-#if BMPWIDTH_rockbox_icon != ICON_WIDTH || BMPHEIGHT_rockbox_icon != ICON_HEIGHT
-#error rockbox_icon has the wrong resolution
-#endif
-#include "data/tools_icon.h"
-#if BMPWIDTH_tools_icon != ICON_WIDTH || BMPHEIGHT_tools_icon != ICON_HEIGHT
-#error tools_icon has the wrong resolution
-#endif
-/* buffer for Sony image, filled from NVP */
-unsigned short sony_icon[ICON_WIDTH * ICON_HEIGHT];
-/* resolution */
-static int width, height, bpp;
-
-/* return icon y position (x is always centered) */
-int get_icon_y(void)
-{
-    /* adjust so that this contains the Sony logo and produces a nice logo
-     * when used with rockbox */
-    if(height == 320)
-        return 70;
-    else if(height == 320)
-        return 100;
-    else
-        return height / 2 - ICON_HEIGHT + 30; /* guess, probably won't work */
-}
-
-/* Sony logo extraction */
-bool extract_sony_logo(void)
-{
-    /* only support bpp of 16 */
-    if(bpp != 16)
-        return false;
-    /* load the entire image from the nvp */
-    int bti_size = nwz_nvp_read(NWZ_NVP_BTI, NULL);
-    if(bti_size < 0)
-        return false;
-    unsigned short *bti = malloc(bti_size);
-    if(nwz_nvp_read(NWZ_NVP_BTI, bti) != bti_size)
-        return false;
-    /* compute the offset in the image of the logo itself */
-    int x_off = (width - ICON_WIDTH) / 2; /* logo is centered horizontally */
-    int y_off = get_icon_y();
-    /* extract part of the image */
-    for(int y = 0; y < ICON_HEIGHT; y++)
-    {
-        memcpy(sony_icon + ICON_WIDTH * y,
-            bti + width * (y + y_off) + x_off, ICON_WIDTH * sizeof(unsigned short));
-    }
-    free(bti);
-    return true;
-}
-
-/* Important Note: this bootloader is carefully written so that in case of
- * error, the OF is run. This seems like the safest option since the OF is
- * always there and might do magic things. */
-
-enum boot_mode
-{
-    BOOT_ROCKBOX,
-    BOOT_TOOLS,
-    BOOT_OF
-};
-
-void draw_icon(int left, int top, const unsigned short *icon, unsigned short *fb_mmap)
-{
-    for(int y = 0; y < ICON_HEIGHT; y++)
-    {
-        memcpy(fb_mmap + width * (y + top) + left, icon + ICON_WIDTH * y,
-            ICON_WIDTH * sizeof(unsigned short));
-    }
-}
-
-enum boot_mode get_boot_mode(void)
-{
-    if(bpp != 16)
-    {
-        nwz_lcdmsg(true, 0, 2, "Unsupported bpp");
-        sleep(2);
-        return BOOT_OF;
-    }
-    /* open framebuffer */
-    int fb_fd = nwz_fb_open(true);
-    if(fb_fd < 0)
-    {
-        nwz_lcdmsg(true, 0, 2, "Cannot open input device");
-        sleep(2);
-        return BOOT_OF;
-    }
-    /* open input device */
-    int input_fd = nwz_key_open();
-    if(input_fd < 0)
-    {
-        nwz_fb_close(fb_fd);
-        nwz_lcdmsg(true, 0, 2, "Cannot open input device");
-        sleep(2);
-        return BOOT_OF;
-    }
-    int fb_size = width * height * bpp / 2;
-    void *fb_mmap = nwz_fb_mmap(fb_fd, 0, fb_size);
-    void *fb_mmap_p1 = nwz_fb_mmap(fb_fd, NWZ_FB_LCD_PAGE_OFFSET, fb_size);
-    if(fb_mmap == NULL || fb_mmap_p1 == NULL)
-    {
-        nwz_fb_close(fb_fd);
-        nwz_key_close(input_fd);
-        nwz_lcdmsg(true, 0, 2, "Cannot map framebuffer");
-        sleep(2);
-        return BOOT_OF;
-    }
-    /* wait for user action */
-    enum boot_mode mode = BOOT_OF;
-    /* NOTE on drawing: since screen is redrawn automatically, and we invoke
-     * external programs to draw, we can't hope to fit it in the frame time
-     * and it will flicker. To avoid this, we use the fact that all programs
-     * only write to page 0. So we setup the lcd to update from page 1. When
-     * we need to update the screen, we ask it to draw from page 0, then copy
-     * page 0 to page 1 and then switch back to page 1 */
-    memset(fb_mmap_p1, 0xff, fb_size); /* clear page 1 */
-    nwz_fb_set_page(fb_fd, 1);
-    bool redraw = true;
-    while(true)
-    {
-        if(redraw)
-        {
-            /* redraw screen on page 0: clear screen */
-            memset(fb_mmap, 0, fb_size);
-            /* display top text */
-            nwz_display_text_center(width, 0, true, NWZ_COLOR(255, 201, 0),
-                NWZ_COLOR(0, 0, 0), 0, "SELECT PLAYER");
-            /* display icon */
-            const unsigned short *icon = (mode == BOOT_OF) ? sony_icon :
-                (mode == BOOT_ROCKBOX) ? rockbox_icon : tools_icon;
-            draw_icon((width - ICON_WIDTH) / 2, get_icon_y(), icon, fb_mmap);
-            /* display bottom description */
-            const char *desc = (mode == BOOT_OF) ? "SONY" :
-                (mode == BOOT_ROCKBOX) ? "ROCKBOX" : "DEBUG TOOLS";
-            nwz_display_text_center(width, get_icon_y() + ICON_HEIGHT + 30, true,
-                NWZ_COLOR(255, 201, 0), NWZ_COLOR(0, 0, 0), 0, desc);
-            /* display arrows */
-            int arrow_y = get_icon_y() + ICON_HEIGHT / 2 - NWZ_FONT_H(true) / 2;
-            nwz_display_text(NWZ_FONT_W(true) / 2, arrow_y, true,
-                NWZ_COLOR(255, 201, 0), NWZ_COLOR(0, 0, 0), 0, "<");
-            nwz_display_text(width - 3 * NWZ_FONT_W(true) / 2, arrow_y, true,
-                NWZ_COLOR(255, 201, 0), NWZ_COLOR(0, 0, 0), 0, ">");
-            /* switch to page 1 */
-            nwz_fb_set_page(fb_fd, 0);
-            /* copy page 0 to page 1 */
-            memcpy(fb_mmap_p1, fb_mmap, fb_size);
-            /* switch back to page 1 */
-            nwz_fb_set_page(fb_fd, 1);
-
-            redraw = false;
-        }
-
-        /* wait for a key  */
-        int ret = nwz_key_wait_event(input_fd, -1);
-        if(ret != 1)
-            continue;
-        struct input_event evt;
-        if(nwz_key_read_event(input_fd, &evt) != 1)
-            continue;
-        /* only act on release */
-        if(nwz_key_event_is_press(&evt))
-            continue;
-        int key_code = nwz_key_event_get_keycode(&evt);
-        /* play -> stop loop and return mode */
-        if(key_code == NWZ_KEY_PLAY)
-            break;
-        /* left/right/up/down: change mode */
-        if(key_code == NWZ_KEY_LEFT || key_code == NWZ_KEY_DOWN)
-        {
-            if(mode == BOOT_ROCKBOX)
-                mode = BOOT_OF;
-            else if(mode == BOOT_OF)
-                mode = BOOT_TOOLS;
-            else
-                mode = BOOT_ROCKBOX;
-            redraw = true;
-        }
-        if(key_code == NWZ_KEY_RIGHT || key_code == NWZ_KEY_UP)
-        {
-            if(mode == BOOT_ROCKBOX)
-                mode = BOOT_TOOLS;
-            else if(mode == BOOT_OF)
-                mode = BOOT_ROCKBOX;
-            else
-                mode = BOOT_OF;
-            redraw = true;
-        }
-    }
-    /* switch back to page 0 */
-    nwz_fb_set_page(fb_fd, 0);
-    nwz_key_close(input_fd);
-    nwz_fb_close(fb_fd);
-    return mode;
-}
-
-static char *boot_rb_argv[] =
-{
-    "rockbox.sony",
-    NULL
-};
-
-int NWZ_TOOL_MAIN(all_tools)(int argc, char **argv);
-
-void error_screen(const char *msg)
-{
-    nwz_lcdmsg(true, 0, 0, msg);
-    sleep(3);
-}
-
-void create_sony_logo(void)
-{
-    for(int y = 0; y < ICON_HEIGHT; y++)
-        for(int x = 0; x < ICON_WIDTH; x++)
-            sony_icon[y * ICON_WIDTH + x] = 0xf81f;
-}
-
-int main(int argc, char **argv)
-{
-    /* make sure backlight is on and we are running the standard lcd mode */
-    int fb_fd = nwz_fb_open(true);
-    if(fb_fd >= 0)
-    {
-        struct nwz_fb_brightness bl;
-        nwz_fb_get_brightness(fb_fd, &bl);
-        bl.level = NWZ_FB_BL_MAX_LEVEL;
-        nwz_fb_set_brightness(fb_fd, &bl);
-        nwz_fb_set_standard_mode(fb_fd);
-        /* get resolution */
-        /* we also need to get the native resolution */
-        if(nwz_fb_get_resolution(fb_fd, &width, &height, &bpp) != 0)
-        {
-            /* safe one */
-            width = 240;
-            height = 320;
-            bpp = 16;
-        }
-        nwz_fb_close(fb_fd);
-    }
-    /* extract logo */
-    if(!extract_sony_logo())
-        create_sony_logo();
-    /* run all tools menu */
-    enum boot_mode mode = get_boot_mode();
-    if(mode == BOOT_TOOLS)
-    {
-        /* run tools and then run OF */
-        NWZ_TOOL_MAIN(all_tools)(argc, argv);
-    }
-    else if(mode == BOOT_ROCKBOX)
-    {
-        /* Rockbox expects /.rockbox to contain themes, rocks, etc, but we
-         * cannot easily create this symlink because the root filesystem is
-         * mounted read-only. Although we could remount it read-write temporarily,
-         * this is neededlessly complicated and we defer this job to the dualboot
-         * install script */
-        execvp("/contents/.rockbox/rockbox.sony", boot_rb_argv);
-        /* fallback to OF in case of failure */
-        error_screen("Cannot boot Rockbox");
-        sleep(5);
-    }
-    /* boot OF */
-    execvp("/usr/local/bin/SpiderApp.of", argv);
-    error_screen("Cannot boot OF");
-    sleep(5);
-    /* if we reach this point, everything failed, so return an error so that
-     * sysmgrd knows something is wrong */
-    return 1;
-}
diff --git a/utils/nwztools/plattools/nwz_lib.c b/utils/nwztools/plattools/nwz_lib.c
deleted file mode 100644
index a81d352..0000000
--- a/utils/nwztools/plattools/nwz_lib.c
+++ /dev/null
@@ -1,777 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2016 Amaury Pouly
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_db.h"
-
-int nwz_run(const char *file, const char *args[], bool wait)
-{
-    pid_t child_pid = fork();
-    if(child_pid != 0)
-    {
-        if(wait)
-        {
-            int status;
-            waitpid(child_pid, &status, 0);
-            return status;
-        }
-        else
-            return 0;
-    }
-    else
-    {
-        execvp(file, (char * const *)args);
-        _exit(1);
-    }
-}
-
-char *nwz_run_pipe(const char *file, const char *args[], int *status)
-{
-    int pipe_fds[2];
-    pipe(pipe_fds);
-    pid_t child_pid = fork();
-    if(child_pid == 0)
-    {
-        dup2(pipe_fds[1], 1); /* redirect stdout */
-        dup2(pipe_fds[1], 2); /* redirect stderr */
-        close(pipe_fds[0]); /* close reading */
-        close(pipe_fds[1]); /* close writing */
-        execvp(file, (char * const *)args);
-        _exit(1);
-    }
-    else
-    {
-        close(pipe_fds[1]); /* close writing */
-        char buffer[1024];
-        char *output = malloc(1);
-        ssize_t count;
-        size_t size = 0;
-        while((count = read(pipe_fds[0], buffer, sizeof(buffer))) > 0)
-        {
-            output = realloc(output, size + count + 1);
-            memcpy(output + size, buffer, count);
-            size += count;
-        }
-        close(pipe_fds[0]);
-        output[size] = 0;
-        waitpid(child_pid, status, 0);
-        return output;
-    }
-}
-
-void nwz_lcdmsg(bool clear, int x, int y, const char *msg)
-{
-    const char *path_lcdmsg = "/usr/local/bin/lcdmsg";
-    const char *args[16];
-    int index = 0;
-    char locate[32];
-    args[index++] = "lcdmsg";
-    if(clear)
-        args[index++] = "-c";
-    args[index++] = "-f";
-    args[index++] = "/usr/local/bin/font_08x12.bmp";
-    args[index++] = "-l";
-    sprintf(locate, "%d,%d", x, y);
-    args[index++] = locate;
-    args[index++] = msg;
-    args[index++] = NULL;
-    /* wait for lcdmsg to finish to avoid any race conditions in framebuffer
-     * accesses */
-    nwz_run(path_lcdmsg, args, true);
-}
-
-void nwz_lcdmsgf(bool clear, int x, int y, const char *format, ...)
-{
-    char buffer[1024];
-    va_list args;
-    va_start(args, format);
-    vsprintf(buffer, format, args);
-    va_end(args);
-    nwz_lcdmsg(clear, x, y, buffer);
-}
-
-#define NWZ_COLOR_RGB(col) \
-    NWZ_COLOR_RED(col), NWZ_COLOR_GREEN(col), NWZ_COLOR_BLUE(col)
-
-void nwz_display_clear(nwz_color_t color)
-{
-    const char *path_display = "/usr/local/bin/display";
-    const char *args[16];
-    int index = 0;
-    char col[32];
-    args[index++] = "display";
-    args[index++] = "lcd";
-    args[index++] = "clear";
-    sprintf(col, "%d,%d,%d", NWZ_COLOR_RGB(color));
-    args[index++] = col;
-    args[index++] = NULL;
-    /* wait for lcdmsg to finish to avoid any race conditions in framebuffer
-     * accesses */
-    nwz_run(path_display, args, true);
-}
-
-void nwz_display_text(int x, int y, bool big_font, nwz_color_t foreground_col,
-    nwz_color_t background_col, int alpha, const char *text)
-{
-    const char *path_display = "/usr/local/bin/display";
-    const char *args[16];
-    int index = 0;
-    char fg[32],bg[32], pos[32], transp[16];
-    args[index++] = "display";
-    args[index++] = "lcd";
-    args[index++] = "text";
-    sprintf(pos, "%d,%d", x, y);
-    args[index++] = pos;
-    if(big_font)
-        args[index++] = "/usr/local/bin/font_14x24.bmp";
-    else
-        args[index++] = "/usr/local/bin/font_08x12.bmp";
-    sprintf(fg, "%d,%d,%d", NWZ_COLOR_RGB(foreground_col));
-    args[index++] = fg;
-    sprintf(bg, "%d,%d,%d", NWZ_COLOR_RGB(background_col));
-    args[index++] = bg;
-    sprintf(transp, "%d", alpha);
-    args[index++] = transp;
-    args[index++] = text;
-    args[index++] = NULL;
-    /* wait for lcdmsg to finish to avoid any race conditions in framebuffer
-     * accesses */
-    nwz_run(path_display, args, true);
-}
-
-void nwz_display_text_center(int width, int y, bool big_font, nwz_color_t fg,
-    nwz_color_t bg, int alpha, const char *text)
-{
-    int txt_w = NWZ_FONT_W(big_font) * strlen(text);
-    nwz_display_text((width - txt_w) / 2, y, big_font, fg, bg, alpha, text);
-}
-
-void nwz_display_textf(int x, int y, bool big_font, nwz_color_t foreground_col,
-    nwz_color_t background_col, int alpha, const char *fmt, ...)
-{
-    char buffer[1024];
-    va_list args;
-    va_start(args, fmt);
-    vsprintf(buffer, fmt, args);
-    va_end(args);
-    nwz_display_text(x, y, big_font, foreground_col, background_col, alpha, buffer);
-}
-
-void nwz_display_textf_center(int width, int y, bool big_font, nwz_color_t fg,
-    nwz_color_t bg, int alpha, const char *fmt, ...)
-{
-    char buffer[1024];
-    va_list args;
-    va_start(args, fmt);
-    vsprintf(buffer, fmt, args);
-    va_end(args);
-    nwz_display_text_center(width, y, big_font, fg, bg, alpha, buffer);
-}
-
-void nwz_display_bitmap(int x, int y, const char *file, int left, int top,
-    int width, int height, nwz_color_t key_col, int bmp_alpha)
-{
-    const char *path_display = "/usr/local/bin/display";
-    const char *args[16];
-    int index = 0;
-    char pos[32], topleft[32], dim[32], key[32], transp[16];
-    args[index++] = "display";
-    args[index++] = "lcd";
-    args[index++] = "bitmap";
-    sprintf(pos, "%d,%d", x, y);
-    args[index++] = pos;
-    args[index++] = file;
-    sprintf(topleft, "%d,%d", left, top);
-    args[index++] = topleft;
-    sprintf(dim, "%d,%d", width, height);
-    args[index++] = dim;
-    if(key_col == NWZ_COLOR_NO_KEY)
-        sprintf(key, "no");
-    else
-        sprintf(key, "%d,%d,%d", NWZ_COLOR_RGB(key_col));
-    args[index++] = key;
-    sprintf(transp, "%d", bmp_alpha);
-    args[index++] = transp;
-    args[index++] = NULL;
-    /* wait for lcdmsg to finish to avoid any race conditions in framebuffer
-     * accesses */
-    nwz_run(path_display, args, true);
-}
-
-int nwz_input_open(const char *requested_name)
-{
-    /* try all /dev/input/eventX, there can't a lot of them */
-    for(int index = 0; index < 8; index++)
-    {
-        char buffer[32];
-        sprintf(buffer, "/dev/input/event%d", index);
-        int fd = open(buffer, O_RDWR);
-        if(fd < 0)
-            continue; /* try next one */
-        /* query name */
-        char name[256];
-        if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) >= 0 &&
-                strcmp(name, requested_name) == 0)
-            return fd;
-        close(fd);
-    }
-    return -1;
-}
-
-int nwz_key_open(void)
-{
-    return nwz_input_open(NWZ_KEY_NAME);
-}
-
-void nwz_key_close(int fd)
-{
-    close(fd);
-}
-
-int nwz_key_get_hold_status(int fd)
-{
-    unsigned long led_hold = 0;
-    if(ioctl(fd, EVIOCGLED(sizeof(led_hold)), &led_hold) < 0)
-        return -1;
-    return led_hold;
-}
-
-int nwz_key_wait_event(int fd, long tmo_us)
-{
-    return nwz_wait_fds(&fd, 1, tmo_us);
-}
-
-int nwz_key_read_event(int fd, struct input_event *evt)
-{
-    int ret = read(fd, evt, sizeof(struct input_event));
-    if(ret != sizeof(struct input_event))
-        return -1;
-    return 1;
-}
-
-int nwz_key_event_get_keycode(struct input_event *evt)
-{
-    return evt->code & NWZ_KEY_MASK;
-}
-
-bool nwz_key_event_is_press(struct input_event *evt)
-{
-    return evt->value == 0;
-}
-
-bool nwz_key_event_get_hold_status(struct input_event *evt)
-{
-    return !!(evt->code & NWZ_KEY_HOLD_MASK);
-}
-
-static const char *nwz_keyname[NWZ_KEY_MASK + 1] =
-{
-    [0 ... NWZ_KEY_MASK] = "unknown",
-    [NWZ_KEY_PLAY] = "PLAY",
-    [NWZ_KEY_RIGHT] = "RIGHT",
-    [NWZ_KEY_LEFT] = "LEFT",
-    [NWZ_KEY_UP] = "UP",
-    [NWZ_KEY_DOWN] = "DOWN",
-    [NWZ_KEY_ZAPPIN] = "ZAPPIN",
-    [NWZ_KEY_AD0_6] = "AD0_6",
-    [NWZ_KEY_AD0_7] = "AD0_7",
-    [NWZ_KEY_NONE] = "NONE",
-    [NWZ_KEY_VOL_DOWN] = "VOL DOWN",
-    [NWZ_KEY_VOL_UP] = "VOL UP",
-    [NWZ_KEY_BACK] = "BACK",
-    [NWZ_KEY_OPTION] = "OPTION",
-    [NWZ_KEY_BT] = "BT",
-    [NWZ_KEY_AD1_5] = "AD1_5",
-    [NWZ_KEY_AD1_6] = "AD1_6",
-    [NWZ_KEY_AD1_7] = "AD1_7",
-};
-
-const char *nwz_key_get_name(int keycode)
-{
-    if(keycode <0 || keycode > NWZ_KEY_MASK)
-        return "invalid";
-    else
-        return nwz_keyname[keycode];
-}
-
-int nwz_fb_open(bool lcd)
-{
-    return open(lcd ? NWZ_FB_LCD_DEV : NWZ_FB_TV_DEV, O_RDWR);
-}
-
-void nwz_fb_close(int fd)
-{
-    close(fd);
-}
-
-int nwz_fb_get_brightness(int fd, struct nwz_fb_brightness *bl)
-{
-    if(ioctl(fd, NWZ_FB_GET_BRIGHTNESS, bl) < 0)
-        return -1;
-    else
-        return 1;
-}
-
-int nwz_fb_set_brightness(int fd, struct nwz_fb_brightness *bl)
-{
-    if(ioctl(fd, NWZ_FB_SET_BRIGHTNESS, bl) < 0)
-        return -1;
-    else
-        return 1;
-}
-
-int nwz_fb_set_page(int fd, int page)
-{
-    /* set page mode to no transparency and no rotation */
-    struct nwz_fb_image_info mode_info;
-    mode_info.tc_enable = 0;
-    mode_info.t_color = 0;
-    mode_info.alpha = 0;
-    mode_info.rot = 0;
-    mode_info.page = page;
-    mode_info.update = NWZ_FB_ONLY_2D_MODE;
-    if(ioctl(fd, NWZ_FB_UPDATE, &mode_info) < 0)
-        return -2;
-    return 0;
-}
-
-int nwz_fb_set_standard_mode(int fd)
-{
-    /* disable timer (apparently useless with LCD) */
-    struct nwz_fb_update_timer update_timer;
-    update_timer.timerflag = NWZ_FB_TIMER_OFF;
-    update_timer.timeout = NWZ_FB_DEFAULT_TIMEOUT;
-    if(ioctl(fd, NWZ_FB_UPDATE_TIMER, &update_timer) < 0)
-        return -1;
-    return nwz_fb_set_page(fd, 0);
-}
-
-int nwz_fb_get_resolution(int fd, int *x, int *y, int *bpp)
-{
-    struct fb_var_screeninfo vinfo;
-    if(ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
-        return -1;
-    if(x)
-        *x = vinfo.xres;
-    if(y)
-        *y = vinfo.yres;
-    if(bpp)
-        *bpp = vinfo.bits_per_pixel;
-    return 0;
-}
-
-void *nwz_fb_mmap(int fd, int offset, int size)
-{
-    return mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)offset);
-}
-
-int nwz_adc_open(void)
-{
-    return open(NWZ_ADC_DEV, O_RDONLY);
-}
-
-void nwz_adc_close(int fd)
-{
-    close(fd);
-}
-
-static const char *nwz_adc_name[] =
-{
-    [NWZ_ADC_VCCBAT] = "VCCBAT",
-    [NWZ_ADC_VCCVBUS] = "VCCVBUS",
-    [NWZ_ADC_ADIN3] = "ADIN3",
-    [NWZ_ADC_ADIN4] = "ADIN4",
-    [NWZ_ADC_ADIN5] = "ADIN5",
-    [NWZ_ADC_ADIN6] = "ADIN6",
-    [NWZ_ADC_ADIN7] = "ADIN7",
-    [NWZ_ADC_ADIN8] = "ADIN8",
-};
-
-const char *nwz_adc_get_name(int ch)
-{
-    return nwz_adc_name[ch];
-}
-
-int nwz_adc_get_val(int fd, int ch)
-{
-    unsigned char val;
-    if(ioctl(fd, NWZ_ADC_GET_VAL(ch), &val) < 0)
-        return -1;
-    else
-        return val;
-}
-
-int nwz_ts_open(void)
-{
-    return nwz_input_open(NWZ_TS_NAME);
-}
-
-void nwz_ts_close(int fd)
-{
-    close(fd);
-}
-
-int nwz_ts_state_init(int fd, struct nwz_ts_state_t *state)
-{
-    memset(state, 0, sizeof(struct nwz_ts_state_t));
-    struct input_absinfo info;
-    if(ioctl(fd, EVIOCGABS(ABS_X), &info) < 0)
-        return -1;
-    state->max_x = info.maximum;
-    if(ioctl(fd, EVIOCGABS(ABS_Y), &info) < 0)
-        return -1;
-    state->max_y = info.maximum;
-    if(ioctl(fd, EVIOCGABS(ABS_PRESSURE), &info) < 0)
-        return -1;
-    state->max_pressure = info.maximum;
-    if(ioctl(fd, EVIOCGABS(ABS_TOOL_WIDTH), &info) < 0)
-        return -1;
-    state->max_tool_width = info.maximum;
-    return 1;
-}
-
-int nwz_ts_state_update(struct nwz_ts_state_t *state, struct input_event *evt)
-{
-    switch(evt->type)
-    {
-        case EV_SYN:
-            return 1;
-        case EV_REL:
-            if(evt->code == REL_RX)
-                state->flick_x = evt->value;
-            else if(evt->code == REL_RY)
-                state->flick_y = evt->value;
-            else
-                return -1;
-            state->flick = true;
-            break;
-        case EV_ABS:
-            if(evt->code == ABS_X)
-                state->x = evt->value;
-            else if(evt->code == ABS_Y)
-                state->y = evt->value;
-            else if(evt->code == ABS_PRESSURE)
-                state->pressure = evt->value;
-            else if(evt->code == ABS_TOOL_WIDTH)
-                state->tool_width = evt->value;
-            else
-                return -1;
-            break;
-        case EV_KEY:
-            if(evt->code == BTN_TOUCH)
-                state->touch = evt->value;
-            else
-                return -1;
-            break;
-        default:
-            return -1;
-    }
-    return 0;
-}
-
-int nwz_ts_state_post_syn(struct nwz_ts_state_t *state)
-{
-    state->flick = false;
-    return 1;
-}
-
-int nwz_ts_read_events(int fd, struct input_event *evts, int nr_evts)
-{
-    int ret = read(fd, evts, nr_evts * sizeof(struct input_event));
-    if(ret < 0)
-        return -1;
-    return ret / sizeof(struct input_event);
-}
-
-long nwz_wait_fds(int *fds, int nr_fds, long tmo_us)
-{
-    fd_set rfds;
-    struct timeval tv;
-    struct timeval *tv_ptr = NULL;
-    /* watch the input device */
-    FD_ZERO(&rfds);
-    int max_fd = 0;
-    for(int i = 0; i < nr_fds; i++)
-    {
-        FD_SET(fds[i], &rfds);
-        if(fds[i] > max_fd)
-            max_fd = fds[i];
-    }
-    /* setup timeout */
-    if(tmo_us >= 0)
-    {
-        tv.tv_sec = 0;
-        tv.tv_usec = tmo_us;
-        tv_ptr = &tv;
-    }
-    int ret = select(max_fd + 1, &rfds, NULL, NULL, tv_ptr);
-    if(ret <= 0)
-        return ret;
-    long bitmap = 0;
-    for(int i = 0; i < nr_fds; i++)
-        if(FD_ISSET(fds[i], &rfds))
-            bitmap |= 1 << i;
-    return bitmap;
-}
-
-int nwz_power_open(void)
-{
-    return open(NWZ_POWER_DEV, O_RDWR);
-}
-
-void nwz_power_close(int fd)
-{
-    close(fd);
-}
-
-int nwz_power_get_status(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_STATUS, &status) < 0)
-        return -1;
-    return status;
-}
-
-static int nwz_power_adval_to_mv(int adval, int ad_base)
-{
-    if(adval == -1)
-        return -1;
-    /* the AD base corresponds to the millivolt value if adval was 255 */
-    return (adval * ad_base) / 255;
-}
-
-int nwz_power_get_vbus_adval(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_VBUS_ADVAL, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_get_vbus_voltage(int fd)
-{
-    return nwz_power_adval_to_mv(nwz_power_get_vbus_adval(fd), NWZ_POWER_AD_BASE_VBUS);
-}
-
-int nwz_power_get_vbus_limit(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_VBUS_LIMIT, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_get_charge_switch(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_CHARGE_SWITCH, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_get_charge_current(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_CHARGE_CURRENT, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_get_battery_gauge(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_BAT_GAUGE, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_get_battery_adval(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_BAT_ADVAL, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_get_battery_voltage(int fd)
-{
-    return nwz_power_adval_to_mv(nwz_power_get_battery_adval(fd), NWZ_POWER_AD_BASE_VBAT);
-}
-
-int nwz_power_get_vbat_adval(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_VBAT_ADVAL, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_get_vbat_voltage(int fd)
-{
-    return nwz_power_adval_to_mv(nwz_power_get_vbat_adval(fd), NWZ_POWER_AD_BASE_VBAT);
-}
-
-int nwz_power_get_sample_count(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_SAMPLE_COUNT, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_get_vsys_adval(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_VSYS_ADVAL, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_get_vsys_voltage(int fd)
-{
-    return nwz_power_adval_to_mv(nwz_power_get_vsys_adval(fd), NWZ_POWER_AD_BASE_VSYS);
-}
-
-int nwz_power_get_acc_charge_mode(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_GET_ACCESSARY_CHARGE_MODE, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_power_is_fully_charged(int fd)
-{
-    int status;
-    if(ioctl(fd, NWZ_POWER_IS_FULLY_CHARGED, &status) < 0)
-        return -1;
-    return status;
-}
-
-int nwz_pminfo_open(void)
-{
-    return open(NWZ_PMINFO_DEV, O_RDONLY);
-}
-
-void nwz_pminfo_close(int fd)
-{
-    close(fd);
-}
-
-unsigned int nwz_pminfo_get_factor(int fd)
-{
-    unsigned int val;
-    if(ioctl(fd, NWZ_PMINFO_GET_FACTOR, &val) < 0)
-        return 0;
-    else
-        return val;
-}
-
-static unsigned long find_model_id(void)
-{
-    /* try with the environment variable */
-    const char *mid = getenv("ICX_MODEL_ID");
-    if(mid == NULL)
-        return 0;
-    char *end;
-    unsigned long v = strtoul(mid, &end, 0);
-    if(*end)
-        return 0;
-    else
-        return v;
-}
-
-unsigned long nwz_get_model_id(void)
-{
-    static unsigned long model_id = 0xffffffff;
-    if(model_id == 0xffffffff)
-        model_id = find_model_id();
-    return model_id;
-}
-
-const char *nwz_get_model_name()
-{
-    for(int i = 0; i < NWZ_MODEL_COUNT; i++)
-        if(nwz_model[i].mid == nwz_get_model_id())
-            return nwz_model[i].name;
-    return NULL;
-}
-
-static int find_series(void)
-{
-    for(int i = 0; i < NWZ_SERIES_COUNT; i++)
-        for(int j = 0; j < nwz_series[i].mid_count; j++)
-            if(nwz_series[i].mid[j] == nwz_get_model_id())
-                return i;
-    return -1;
-}
-
-int nwz_get_series(void)
-{
-    static int series = -2;
-    if(series == -2)
-        series = find_series();
-    return series;
-}
-
-static nwz_nvp_index_t *get_nvp_index(void)
-{
-    static nwz_nvp_index_t *index = 0;
-    if(index == 0)
-    {
-        int series = nwz_get_series();
-        index = series < 0 ? 0 : nwz_series[series].nvp_index;
-    }
-    return index;
-}
-
-int nwz_nvp_read(enum nwz_nvp_node_t node, void *data)
-{
-    int size = nwz_nvp[node].size;
-    if(data == 0)
-        return size;
-    nwz_nvp_index_t *index = get_nvp_index();
-    if(index == 0 || (*index)[node] == NWZ_NVP_INVALID)
-        return -1;
-    char nvp_path[32];
-    snprintf(nvp_path, sizeof(nvp_path), "/dev/icx_nvp/%03d", (*index)[node]);
-    int fd = open(nvp_path, O_RDONLY);
-    if(fd < 0)
-        return -1;
-    int cnt = read(fd, data, size);
-    close(fd);
-    return cnt == size ? size : -1;
-}
-
-int nwz_nvp_write(enum nwz_nvp_node_t node, void *data)
-{
-    int size = nwz_nvp[node].size;
-    nwz_nvp_index_t *index = get_nvp_index();
-    if(index == 0 || (*index)[node] == NWZ_NVP_INVALID)
-        return -1;
-    char nvp_path[32];
-    snprintf(nvp_path, sizeof(nvp_path), "/dev/icx_nvp/%03d", (*index)[node]);
-    int fd = open(nvp_path, O_WRONLY);
-    if(fd < 0)
-        return -1;
-    int cnt = write(fd, data, size);
-    close(fd);
-    return cnt == size ? 0 : -1;
-}
diff --git a/utils/nwztools/plattools/nwz_lib.h b/utils/nwztools/plattools/nwz_lib.h
deleted file mode 100644
index 23bb809..0000000
--- a/utils/nwztools/plattools/nwz_lib.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2016 Amaury Pouly
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#ifndef _NWZLIB_H_
-#define _NWZLIB_H_
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <linux/input.h>
-#include <linux/fb.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-
-#include "nwz_keys.h"
-#include "nwz_fb.h"
-#include "nwz_adc.h"
-#include "nwz_ts.h"
-#include "nwz_power.h"
-#include "nwz_db.h"
-
-/* get model ID, either from ICX_MODEL_ID env var or using nvpflag, return 0
- * in case of error; note that the result is cached so this function is only
- * expensive the first time it is called */
-unsigned long nwz_get_model_id(void);
-/* get series (index into nwz_series, or -1 on error) */
-int nwz_get_series(void);
-/* get model name, or null on error */
-const char *nwz_get_model_name(void);
-
-/* run a program and exit with nonzero status in case of error
- * argument list must be NULL terminated */
-int nwz_run(const char *file, const char *args[], bool wait);
-/* run a program and return program output */
-char *nwz_run_pipe(const char *file, const char *args[], int *status);
-
-/* invoke /usr/local/bin/lcdmsg to display a message using the small font, optionally
- * clearing the screen before */
-void nwz_lcdmsg(bool clear, int x, int y, const char *msg);
-void nwz_lcdmsgf(bool clear, int x, int y, const char *format, ...);
-/* invoke /usr/local/bin/display to do various things:
- * - clear screen
- * - display text
- * - display bitmap
- * Currently all operations are performed on the LCD only.
- * The small text font is 8x12 and the big one is 14x24 */
-typedef int nwz_color_t;
-#define NWZ_COLOR(r, g, b) /* each component between 0 and 255 */ \
-    ((r) <<  16 | (g) << 8 | (b))
-#define NWZ_COLOR_RED(col)      ((col) >> 16)
-#define NWZ_COLOR_GREEN(col)    (((col) >> 8) & 0xff)
-#define NWZ_COLOR_BLUE(col)    ((col) & 0xff)
-#define NWZ_COLOR_NO_KEY    (1 << 24)
-
-#define NWZ_FONT_W(big_font) ((big_font) ? 14 : 8)
-#define NWZ_FONT_H(big_font) ((big_font) ? 24 : 14)
-
-void nwz_display_clear(nwz_color_t color);
-void nwz_display_text(int x, int y, bool big_font, nwz_color_t foreground_col,
-    nwz_color_t background_col, int background_alpha, const char *text);
-void nwz_display_text_center(int width, int y, bool big_font, nwz_color_t foreground_col,
-    nwz_color_t background_col, int background_alpha, const char *text);
-void nwz_display_textf(int x, int y, bool big_font, nwz_color_t foreground_col,
-    nwz_color_t background_col, int background_alpha, const char *fmt, ...);
-void nwz_display_textf_center(int width, int y, bool big_font, nwz_color_t foreground_col,
-    nwz_color_t background_col, int background_alpha, const char *fmt, ...);
-void nwz_display_bitmap(int x, int y, const char *file, int left, int top,
-    int width, int height, nwz_color_t key, int bmp_alpha);
-
-/* open icx_key input device and return file descriptor */
-int nwz_key_open(void);
-void nwz_key_close(int fd);
-/* return HOLD status: 0 or 1, or -1 on error */
-int nwz_key_get_hold_status(int fd);
-/* wait for an input event (and return 1), or a timeout (return 0), or error (-1)
- * set the timeout to -1 to block */
-int nwz_key_wait_event(int fd, long tmo_us);
-/* read an event from the device (may block unless you waited for an event before),
- * return 1 on success, <0 on error */
-int nwz_key_read_event(int fd, struct input_event *evt);
-/* return keycode from event */
-int nwz_key_event_get_keycode(struct input_event *evt);
-/* return press/released status from event */
-bool nwz_key_event_is_press(struct input_event *evt);
-/* return HOLD status from event */
-bool nwz_key_event_get_hold_status(struct input_event *evt);
-/* get keycode name */
-const char *nwz_key_get_name(int keycode);
-
-/* open framebuffer device */
-int nwz_fb_open(bool lcd);
-/* close framebuffer device */
-void nwz_fb_close(int fb);
-/* get screen resolution, parameters are allowed to be NULL */
-int nwz_fb_get_resolution(int fd, int *x, int *y, int *bpp);
-/* get backlight brightness (return -1 on error, 1 on success) */
-int nwz_fb_get_brightness(int fd, struct nwz_fb_brightness *bl);
-/* set backlight brightness (return -1 on error, 1 on success) */
-int nwz_fb_set_brightness(int fd, struct nwz_fb_brightness *bl);
-/* setup framebuffer to its standard mode: LCD output, page 0, no transparency
- * and no rotation, 2D only updates */
-int nwz_fb_set_standard_mode(int fd);
-/* change framebuffer page and update screen */
-int nwz_fb_set_page(int fd, int page);
-/* map framebuffer */
-void *nwz_fb_mmap(int fd, int offset, int size);
-
-/* open adc device */
-int nwz_adc_open(void);
-/* close adc device */
-void nwz_adc_close(int fd);
-/* get channel name */
-const char *nwz_adc_get_name(int ch);
-/* read channel value, return -1 on error */
-int nwz_adc_get_val(int fd, int ch);
-
-/* open touchscreen device */
-int nwz_ts_open(void);
-/* close touchscreen device */
-void nwz_ts_close(int fd);
-/* structure to track touch state */
-struct nwz_ts_state_t
-{
-    int x, y; /* current position (valid is touch is true) */
-    int max_x, max_y; /* maximum possible values */
-    int pressure, tool_width; /* current pressure and tool width */
-    int max_pressure, max_tool_width; /* maximum possible values */
-    bool touch; /* is the user touching the screen? */
-    bool flick; /* was the action a flick? */
-    int flick_x, flick_y; /* if so, this is the flick direction */
-};
-/* get touchscreen information and init state, return -1 on error, 1 on success */
-int nwz_ts_state_init(int fd, struct nwz_ts_state_t *state);
-/* update state with an event, return -1 on unhandled event, >=0 on handled:
- * 1 if sync event, 0 otherwise */
-int nwz_ts_state_update(struct nwz_ts_state_t *state, struct input_event *evt);
-/* update state after a sync event to prepare for next round of events */
-int nwz_ts_state_post_syn(struct nwz_ts_state_t *state);
-/* read at most N events from touch screen, and return the number of events */
-int nwz_ts_read_events(int fd, struct input_event *evts, int nr_evts);
-
-/* wait for events on several file descriptors, return a bitmap of active ones
- * or 0 on timeout, the timeout can be -1 to block */
-long nwz_wait_fds(int *fds, int nr_fds, long timeout_us);
-
-/* open power device */
-int nwz_power_open(void);
-/* close power device */
-void nwz_power_close(int fd);
-/* get power status (return -1 on error, bitmap on success) */
-int nwz_power_get_status(int fd);
-/* get vbus adval (or -1 on error) */
-int nwz_power_get_vbus_adval(int fd);
-/* get vbus voltage in mV (or -1 on error) */
-int nwz_power_get_vbus_voltage(int fd);
-/* get vbus current limit (or -1 on error) */
-int nwz_power_get_vbus_limit(int fd);
-/* get charge switch (or -1 on error) */
-int nwz_power_get_charge_switch(int fd);
-/* get charge current (or -1 on error) */
-int nwz_power_get_charge_current(int fd);
-/* get battery gauge (or -1 on error) */
-int nwz_power_get_battery_gauge(int fd);
-/* get battery adval (or -1 on error) */
-int nwz_power_get_battery_adval(int fd);
-/* get battery voltage in mV (or -1 on error) */
-int nwz_power_get_battery_voltage(int fd);
-/* get vbat adval (or -1 on error) */
-int nwz_power_get_vbat_adval(int fd);
-/* get vbat voltage (or -1 on error) */
-int nwz_power_get_vbat_voltage(int fd);
-/* get sample count (or -1 on error) */
-int nwz_power_get_sample_count(int fd);
-/* get vsys adval (or -1 on error) */
-int nwz_power_get_vsys_adval(int fd);
-/* get vsys voltage in mV (or -1 on error) */
-int nwz_power_get_vsys_voltage(int fd);
-/* get accessory charge mode */
-int nwz_power_get_acc_charge_mode(int fd);
-/* is battery fully charged? (or -1 on error) */
-int nwz_power_is_fully_charged(int fd);
-
-/* open pminfo device */
-int nwz_pminfo_open(void);
-/* close pminfo device */
-void nwz_pminfo_close(int fd);
-/* get pminfo factor (or 0 on error) */
-unsigned int nwz_pminfo_get_factor(int fd);
-
-/* read a nvp node and return its size, if the data pointer is null, then simply
- * return the size, return -1 on error */
-int nwz_nvp_read(enum nwz_nvp_node_t node, void *data);
-/* write a nvp node, return 0 on success and -1 on error, the size of the buffer
- * must be the one returned by nwz_nvp_read */
-int nwz_nvp_write(enum nwz_nvp_node_t node, void *data);
-
-
-#endif /* _NWZLIB_H_ */
diff --git a/utils/nwztools/plattools/nwz_plattools.h b/utils/nwztools/plattools/nwz_plattools.h
deleted file mode 100644
index 56d584c..0000000
--- a/utils/nwztools/plattools/nwz_plattools.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2011 by Amaury Pouly
- *
- * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
- * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#ifndef __NWZ_PLATTOOLS_H__
-#define __NWZ_PLATTOOLS_H__
-
-/** Platform tools can be either built individually, or be included in a
- * single build (or even dualboot code) for easy testing. Thus, each tool must
- * use the following macros to support all scenarios. */
-
-#ifdef NWZ_EMBED_TOOLS
-#define NWZ_TOOL_MAIN(tool)  tool##_main
-#else
-#define NWZ_TOOL_MAIN(tool)  main
-#endif
-
-#endif /* __NWZ_PLATTOOLS_H__ */
diff --git a/utils/nwztools/plattools/test_adc.c b/utils/nwztools/plattools/test_adc.c
deleted file mode 100644
index 31b685c..0000000
--- a/utils/nwztools/plattools/test_adc.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2016 Amaury Pouly
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_plattools.h"
-
-int NWZ_TOOL_MAIN(test_adc)(int argc, char **argv)
-{
-    /* clear screen and display welcome message */
-    nwz_lcdmsg(true, 0, 0, "test_adc");
-    nwz_lcdmsg(false, 0, 2, "BACK: quit");
-    /* open input device */
-    int input_fd = nwz_key_open();
-    if(input_fd < 0)
-    {
-        nwz_lcdmsg(false, 3, 4, "Cannot open input device");
-        sleep(2);
-        return 1;
-    }
-    /* open adc device */
-    int adc_fd = nwz_adc_open();
-    if(adc_fd < 0)
-    {
-        nwz_key_close(input_fd);
-        nwz_lcdmsg(false, 3, 4, "Cannot open adc device");
-        sleep(2);
-        return 1;
-    }
-    /* display input state in a loop */
-    while(1)
-    {
-        /* print channels */
-        for(int i = NWZ_ADC_MIN_CHAN; i <= NWZ_ADC_MAX_CHAN; i++)
-            nwz_lcdmsgf(false, 1, 4 + i, "%s: %d    ", nwz_adc_get_name(i),
-                nwz_adc_get_val(adc_fd, i));
-        /* wait for event (10ms) */
-        int ret = nwz_key_wait_event(input_fd, 10000);
-        if(ret != 1)
-            continue;
-        struct input_event evt;
-        if(nwz_key_read_event(input_fd, &evt) != 1)
-            continue;
-        if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt))
-            break;
-    }
-    /* finish nicely */
-    nwz_key_close(input_fd);
-    nwz_adc_close(adc_fd);
-    return 0;
-}
diff --git a/utils/nwztools/plattools/test_bl.c b/utils/nwztools/plattools/test_bl.c
deleted file mode 100644
index 594cbbd..0000000
--- a/utils/nwztools/plattools/test_bl.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2016 Amaury Pouly
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_plattools.h"
-
-int NWZ_TOOL_MAIN(test_bl)(int argc, char **argv)
-{
-    /* clear screen and display welcome message */
-    nwz_lcdmsg(true, 0, 0, "test_bl");
-    nwz_lcdmsg(false, 0, 2, "LEFT/RIGHT: level");
-    nwz_lcdmsg(false, 0, 3, "UP/DOWN: step");
-    nwz_lcdmsg(false, 0, 4, "VOL UP/DOWN: period");
-    nwz_lcdmsg(false, 0, 5, "BACK: quit");
-    /* open input and framebuffer device */
-    int input_fd = nwz_key_open();
-    if(input_fd < 0)
-    {
-        nwz_lcdmsg(false, 3, 7, "Cannot open input device");
-        sleep(2);
-        return 1;
-    }
-    int fb_fd = nwz_fb_open(true);
-    if(fb_fd < 0)
-    {
-        nwz_key_close(input_fd);
-        nwz_lcdmsg(false, 3, 7, "Cannot open framebuffer device");
-        sleep(2);
-        return 1;
-    }
-    /* display input state in a loop */
-    while(1)
-    {
-        struct nwz_fb_brightness bl;
-        if(nwz_fb_get_brightness(fb_fd, &bl) == 1)
-        {
-            nwz_lcdmsgf(false, 1, 7, "level: %d   ", bl.level);
-            nwz_lcdmsgf(false, 1, 8, "step: %d   ", bl.step);
-            nwz_lcdmsgf(false, 1, 9, "period: %d   ", bl.period);
-        }
-        /* wait for event */
-        int ret = nwz_key_wait_event(input_fd, -1);
-        if(ret != 1)
-            continue;
-        struct input_event evt;
-        if(nwz_key_read_event(input_fd, &evt) != 1)
-            continue;
-        int code = nwz_key_event_get_keycode(&evt);
-        bool press = nwz_key_event_is_press(&evt);
-        /* only act on release */
-        if(press)
-            continue;
-        if(code == NWZ_KEY_BACK)
-            break; /* quit */
-        bool change_bl = false;
-        if(code == NWZ_KEY_RIGHT && bl.level < NWZ_FB_BL_MAX_LEVEL)
-        {
-            change_bl = true;
-            bl.level++;
-        }
-        else if(code == NWZ_KEY_LEFT && bl.level > NWZ_FB_BL_MIN_LEVEL)
-        {
-            change_bl = true;
-            bl.level--;
-        }
-        else if(code == NWZ_KEY_UP && bl.step < NWZ_FB_BL_MAX_STEP)
-        {
-            change_bl = true;
-            bl.step++;
-        }
-        else if(code == NWZ_KEY_DOWN && bl.step > NWZ_FB_BL_MIN_STEP)
-        {
-            change_bl = true;
-            bl.step--;
-        }
-        else if(code == NWZ_KEY_VOL_UP && bl.period < 100) /* artificial bound on period */
-        {
-            change_bl = true;
-            bl.period++;
-        }
-        else if(code == NWZ_KEY_VOL_DOWN && bl.period > NWZ_FB_BL_MIN_PERIOD)
-        {
-            change_bl = true;
-            bl.period--;
-        }
-        /* change bl */
-        if(change_bl)
-            nwz_fb_set_brightness(fb_fd, &bl);
-    }
-    /* close input device */
-    nwz_key_close(input_fd);
-    nwz_fb_close(fb_fd);
-    /* finish nicely */
-    return 0;
-}
diff --git a/utils/nwztools/plattools/test_display.c b/utils/nwztools/plattools/test_display.c
deleted file mode 100644
index b05b246..0000000
--- a/utils/nwztools/plattools/test_display.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2016 Amaury Pouly
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_plattools.h"
-
-int NWZ_TOOL_MAIN(test_display)(int argc, char **argv)
-{
-    /* clear screen and display welcome message */
-    nwz_display_clear(NWZ_COLOR(128, 128, 0));
-    nwz_display_text(0, 0, true, NWZ_COLOR(255, 0, 0), NWZ_COLOR(0, 0, 255), 0,
-        "Hello");
-    nwz_display_text(0, 30, false, NWZ_COLOR(255, 0, 0), NWZ_COLOR(0, 0, 255), 128,
-        "BACK: quit");
-    nwz_display_text(0, 50, false, NWZ_COLOR(255, 0, 0), NWZ_COLOR(0, 0, 255), 255,
-        "BACK: quit");
-    /* display /contents/display.bmp if any */
-    const char *bmp_fname = "/contents/display.bmp";
-    if(access(bmp_fname, R_OK) != -1)
-    {
-        nwz_display_bitmap(10, 70, bmp_fname, 0, 0, 200, 200, NWZ_COLOR_NO_KEY, 255);
-    }
-    else
-    {
-        nwz_display_text(0, 70, false, NWZ_COLOR(255, 0, 0), NWZ_COLOR(0, 0, 0), 0,
-            "Cannot find display.bmp");
-    }
-    /* wait for key */
-    int input_fd = nwz_key_open();
-    if(input_fd < 0)
-    {
-        sleep(2);
-        return 1;
-    }
-    while(1)
-    {
-        /* wait for event */
-        int ret = nwz_key_wait_event(input_fd, 1000000);
-        if(ret != 1)
-            continue;
-        struct input_event evt;
-        if(nwz_key_read_event(input_fd, &evt) != 1)
-            continue;
-        /* handle quit */
-        if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt))
-            break;
-    }
-    nwz_key_close(input_fd);
-    return 0;
-}
diff --git a/utils/nwztools/plattools/test_fb.c b/utils/nwztools/plattools/test_fb.c
deleted file mode 100644
index 77e8d4e..0000000
--- a/utils/nwztools/plattools/test_fb.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2011 by Amaury Pouly
- *
- * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
- * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_plattools.h"
-#include <linux/fb.h>
-#include <stdint.h>
-#include <sys/mman.h>
-
-static struct fb_fix_screeninfo finfo;
-static struct fb_var_screeninfo vinfo;
-static uint8_t *framebuffer;
-
-static inline uint32_t read32(uint8_t *p)
-{
-    return *p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24;
-}
-
-static inline void write32(uint8_t *p, uint32_t val)
-{
-    *p++ = val & 0xff; val >>= 8;
-    *p++ = val & 0xff; val >>= 8;
-    *p++ = val & 0xff; val >>= 8;
-    *p++ = val;
-}
-
-/* assume lsb and little-endian */
-static inline void put_pix_mask(uint8_t *location, int offset, int len, uint8_t pix)
-{
-    /* adjust pixel */
-    pix >>= 8 - len;
-    uint32_t mask = ((1 << len) - 1) << offset;
-    uint32_t val = read32(location);
-    val = ((val) & ~mask) | pix << offset;
-    write32(location, val);
-}
-
-static inline void put_pix(int x, int y, uint8_t r, uint8_t g, uint8_t b)
-{
-    x += vinfo.xoffset;
-    y += vinfo.yoffset;
-    uint8_t *location = framebuffer + x * (vinfo.bits_per_pixel / 8) + y * finfo.line_length;
-    put_pix_mask(location, vinfo.red.offset, vinfo.red.length, r);
-    put_pix_mask(location, vinfo.green.offset, vinfo.green.length, g);
-    put_pix_mask(location, vinfo.blue.offset, vinfo.blue.length, b);
-}
-
-static void dump_fb(FILE *out, const char *path)
-{
-    fprintf(out, "%s:\n", path);
-    int fd = open(path, O_RDWR);
-    if(fd < 0)
-    {
-        fprintf(out, "  cannot open");
-        return;
-    }
-    /* get fixed info */
-    if(ioctl(fd, FBIOGET_FSCREENINFO, &finfo) < 0)
-    {
-        fprintf(out, "  ioctl failed (fix info)");
-        close(fd);
-        return;
-    }
-    fprintf(out, "  identification: %s\n", finfo.id);
-    fprintf(out, "  type: %d\n", finfo.type);
-    fprintf(out, "  visual: %d\n", finfo.visual);
-    fprintf(out, "  accel: %d\n", finfo.accel);
-    fprintf(out, "  line length: %d\n", finfo.line_length);
-    fprintf(out, "  mem length: %d\n", finfo.smem_len);
-    /* get variable info */
-    if(ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
-    {
-        close(fd);
-        fprintf(out, "  ioctl failed (var info)");
-        return;
-    }
-    fprintf(out, "  xres: %d\n", vinfo.xres);
-    fprintf(out, "  yres: %d\n", vinfo.yres);
-    fprintf(out, "  xoff: %d\n", vinfo.xoffset);
-    fprintf(out, "  yoff: %d\n", vinfo.yoffset);
-    fprintf(out, "  bbp: %d\n", vinfo.bits_per_pixel);
-    fprintf(out, "  red: %d-%d\n", vinfo.red.offset + vinfo.red.length - 1, vinfo.red.offset);
-    fprintf(out, "  green: %d-%d\n", vinfo.green.offset + vinfo.green.length - 1, vinfo.green.offset);
-    fprintf(out, "  blue: %d-%d\n", vinfo.blue.offset + vinfo.blue.length - 1, vinfo.blue.offset);
-    /* get mode info */
-    struct nwz_fb_image_info mode_info;
-    nwz_fb_set_standard_mode(fd);
-    if(ioctl(fd, NWZ_FB_GET_MODE, &mode_info) < 0)
-    {
-        close(fd);
-        fprintf(out, "  ioctl failed (get mode)\n");
-        return;
-    }
-    fprintf(out, "  tc_enable: %d\n", mode_info.tc_enable);
-    fprintf(out, "  t_color: %d\n", mode_info.t_color);
-    fprintf(out, "  alpha: %d\n", mode_info.alpha);
-    fprintf(out, "  rot: %d\n", mode_info.rot);
-    fprintf(out, "  page: %d\n", mode_info.page);
-    fprintf(out, "  update: %d\n", mode_info.update);
-    /* mmap device (but avoid TV) */
-    if(vinfo.xres != 720)
-    {
-        long screensize = vinfo.yres_virtual * finfo.line_length;
-        framebuffer = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0);
-        if(framebuffer == 0)
-        {
-            close(fd);
-            fprintf(out, "  mmap failed");
-            return;
-        }
-        for(int y = 0; y < 10; y++)
-            for(int x = 0; x < 10; x++)
-            {
-                put_pix(x, y, 0xff, 0, 0);
-                put_pix(x + 10, y, 0, 0xff, 0);
-                put_pix(x + 20, y, 0, 0, 0xff);
-            }
-    }
-    sleep(3);
-    close(fd);
-}
-
-int NWZ_TOOL_MAIN(test_fb)(int argc, char **argv)
-{
-    FILE *f = fopen("/contents/fb.txt", "w");
-    if(!f)
-        f = stdout;
-    dump_fb(f, "/dev/fb/0");
-    if(f)
-        fclose(f);
-    return 0;
-}
diff --git a/utils/nwztools/plattools/test_keys.c b/utils/nwztools/plattools/test_keys.c
deleted file mode 100644
index 353864d..0000000
--- a/utils/nwztools/plattools/test_keys.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2016 Amaury Pouly
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_plattools.h"
-
-int NWZ_TOOL_MAIN(test_keys)(int argc, char **argv)
-{
-    /* clear screen and display welcome message */
-    nwz_lcdmsg(true, 0, 0, "test_keys");
-    nwz_lcdmsg(false, 0, 2, "BACK: hold 3 seconds to quit");
-    /* open input device */
-    int input_fd = nwz_key_open();
-    if(input_fd < 0)
-    {
-        nwz_lcdmsg(false, 3, 4, "Cannot open input device");
-        sleep(2);
-        return 1;
-    }
-    /* display input state in a loop */
-    int back_pressed = 0; /* 0 = no pressed, >0 = number of seconds pressed - 1 */
-#define FIRST_LINE  7
-#define LAST_LINE   17
-    int event_line = FIRST_LINE;
-    int prev_evt_line = -1;
-    while(1)
-    {
-        /* display HOLD status */
-        nwz_lcdmsgf(false, 2, 5, "HOLD: %d", nwz_key_get_hold_status(input_fd));
-        /* wait for event */
-        int ret = nwz_key_wait_event(input_fd, 1000000);
-        if(ret != 1)
-        {
-            if(back_pressed > 0)
-                back_pressed++;
-            if(back_pressed >= 4)
-                break;
-            continue;
-        }
-        struct input_event evt;
-        if(nwz_key_read_event(input_fd, &evt) != 1)
-            continue;
-        /* erase last '>' indicator */
-        if(prev_evt_line != -1)
-            nwz_lcdmsg(false, 0, prev_evt_line, "  ");
-        prev_evt_line = event_line;
-        char buffer[32];
-        int len = sprintf(buffer, "> %s %s (HOLD=%d)",
-            nwz_key_get_name(nwz_key_event_get_keycode(&evt)),
-            nwz_key_event_is_press(&evt) ? "pressed" : "released",
-            nwz_key_event_get_hold_status(&evt));
-        /* pad with spaces to erase old stuff */
-        while(len + 1 < sizeof(buffer))
-            buffer[len++] = ' ';
-        buffer[len] = 0;
-        /* print line */
-        nwz_lcdmsg(false, 0, event_line, buffer);
-        /* compute next line */
-        event_line++;
-        if(event_line == LAST_LINE)
-            event_line = FIRST_LINE;
-        /* handle quit */
-        if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && nwz_key_event_is_press(&evt))
-            back_pressed = 1;
-        else
-            back_pressed = 0;
-    }
-    /* wait until back is released, to avoid messing with all_tools (if embedded) */
-    nwz_lcdmsg(true, 0, 0, "test_keys");
-    nwz_lcdmsg(false, 0, 2, "BACK: release to quit");
-    while(1)
-    {
-        /* wait for event */
-        int ret = nwz_key_wait_event(input_fd, 1000000);
-        if(ret != 1)
-            continue;
-        struct input_event evt;
-        if(nwz_key_read_event(input_fd, &evt) != 1)
-            continue;
-        /* handle quit */
-        if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt))
-            break;
-    }
-    /* close input device */
-    nwz_key_close(input_fd);
-    /* finish nicely */
-    return 0;
-}
diff --git a/utils/nwztools/plattools/test_power.c b/utils/nwztools/plattools/test_power.c
deleted file mode 100644
index f0d374b..0000000
--- a/utils/nwztools/plattools/test_power.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2016 Amaury Pouly
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_plattools.h"
-
-static const char *charge_status_name(int chgstat)
-{
-    switch(chgstat)
-    {
-        case NWZ_POWER_STATUS_CHARGE_STATUS_CHARGING: return "charging";
-        case NWZ_POWER_STATUS_CHARGE_STATUS_SUSPEND: return "suspend";
-        case NWZ_POWER_STATUS_CHARGE_STATUS_TIMEOUT: return "timeout";
-        case NWZ_POWER_STATUS_CHARGE_STATUS_NORMAL: return "normal";
-        default: return "unknown";
-    }
-}
-
-static const char *get_batt_gauge_name(int gauge)
-{
-    switch(gauge)
-    {
-        case NWZ_POWER_BAT_NOBAT: return "no batt";
-        case NWZ_POWER_BAT_VERYLOW: return "very low";
-        case NWZ_POWER_BAT_LOW: return "low";
-        case NWZ_POWER_BAT_GAUGE0: return "____";
-        case NWZ_POWER_BAT_GAUGE1: return "O___";
-        case NWZ_POWER_BAT_GAUGE2: return "OO__";
-        case NWZ_POWER_BAT_GAUGE3: return "OOO_";
-        case NWZ_POWER_BAT_GAUGE4: return "OOOO";
-        default: return "unknown";
-    }
-}
-
-static const char *acc_charge_mode_name(int mode)
-{
-    switch(mode)
-    {
-        case NWZ_POWER_ACC_CHARGE_NONE: return "none";
-        case NWZ_POWER_ACC_CHARGE_VBAT: return "vbat";
-        case NWZ_POWER_ACC_CHARGE_VSYS: return "vsys";
-        default: return "unknown";
-    }
-}
-
-int NWZ_TOOL_MAIN(test_power)(int argc, char **argv)
-{
-    /* clear screen and display welcome message */
-    nwz_lcdmsg(true, 0, 0, "test_power");
-    nwz_lcdmsg(false, 0, 2, "BACK: quit");
-    /* open input device */
-    int input_fd = nwz_key_open();
-    if(input_fd < 0)
-    {
-        nwz_lcdmsg(false, 3, 4, "Cannot open input device");
-        sleep(2);
-        return 1;
-    }
-    /* open adc device */
-    int power_fd = nwz_power_open();
-    if(power_fd < 0)
-    {
-        nwz_key_close(input_fd);
-        nwz_lcdmsg(false, 3, 4, "Cannot open power device");
-        sleep(2);
-        return 1;
-    }
-    /* open pminfo device */
-    int pminfo_fd = nwz_pminfo_open();
-    if(pminfo_fd < 0)
-    {
-        nwz_key_close(power_fd);
-        nwz_key_close(input_fd);
-        nwz_lcdmsg(false, 3, 4, "Cannot open pminfo device");
-        sleep(2);
-        return 1;
-    }
-    /* display input state in a loop */
-    while(1)
-    {
-        /* print status */
-        int line = 4;
-        int status = nwz_power_get_status(power_fd);
-        int chgstat = status & NWZ_POWER_STATUS_CHARGE_STATUS;
-        int acc_chg_mode = nwz_power_get_acc_charge_mode(power_fd);
-        nwz_lcdmsgf(false, 0, line++, "ac detected: %s   ",
-            (status & NWZ_POWER_STATUS_AC_DET) ? "yes" : "no");
-        nwz_lcdmsgf(false, 0, line++, "vbus detected: %s   ",
-            (status & NWZ_POWER_STATUS_VBUS_DET) ? "yes" : "no");
-        nwz_lcdmsgf(false, 0, line++, "vbus voltage: %d mV (AD=%d)      ",
-            nwz_power_get_vbus_voltage(power_fd), nwz_power_get_vbus_adval(power_fd));
-        nwz_lcdmsgf(false, 0, line++, "vbus limit: %d mA      ",
-            nwz_power_get_vbus_limit(power_fd));
-        nwz_lcdmsgf(false, 0, line++, "vsys voltage: %d mV (AD=%d)      ",
-            nwz_power_get_vsys_voltage(power_fd), nwz_power_get_vsys_adval(power_fd));
-        nwz_lcdmsgf(false, 0, line++, "charge switch: %s       ",
-            nwz_power_get_charge_switch(power_fd) ? "on" : "off");
-        nwz_lcdmsgf(false, 0, line++, "full voltage: %s V      ",
-            (status & NWZ_POWER_STATUS_CHARGE_LOW) ? "4.1" : "4.2");
-        nwz_lcdmsgf(false, 0, line++, "current limit: %d mA     ",
-            nwz_power_get_charge_current(power_fd));
-        nwz_lcdmsgf(false, 0, line++, "charge status: %s (%x)     ",
-            charge_status_name(chgstat), chgstat);
-        nwz_lcdmsgf(false, 0, line++, "battery full: %s       ",
-            nwz_power_is_fully_charged(power_fd) ? "yes" : "no");
-        nwz_lcdmsgf(false, 0, line++, "bat gauge: %s (%d)       ",
-            get_batt_gauge_name(nwz_power_get_battery_gauge(power_fd)),
-            nwz_power_get_battery_gauge(power_fd));
-        nwz_lcdmsgf(false, 0, line++, "avg voltage: %d mV (AD=%d)      ",
-            nwz_power_get_battery_voltage(power_fd), nwz_power_get_battery_adval(power_fd));
-        nwz_lcdmsgf(false, 0, line++, "sample count: %d       ",
-            nwz_power_get_sample_count(power_fd));
-        nwz_lcdmsgf(false, 0, line++, "raw voltage: %d mV (AD=%d)      ",
-            nwz_power_get_vbat_voltage(power_fd), nwz_power_get_vbat_adval(power_fd));
-        nwz_lcdmsgf(false, 0, line++, "acc charge mode: %s (%d)     ",
-            acc_charge_mode_name(acc_chg_mode), acc_chg_mode);
-        /* pminfo */
-        line++;
-        nwz_lcdmsgf(false, 0, line++, "pminfo: %#x     ", nwz_pminfo_get_factor(pminfo_fd));
-        /* wait for event (1s) */
-        int ret = nwz_key_wait_event(input_fd, 1000000);
-        if(ret != 1)
-            continue;
-        struct input_event evt;
-        if(nwz_key_read_event(input_fd, &evt) != 1)
-            continue;
-        if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt))
-            break;
-    }
-    /* finish nicely */
-    nwz_key_close(power_fd);
-    nwz_key_close(input_fd);
-    nwz_pminfo_close(pminfo_fd);
-    return 0;
-}
diff --git a/utils/nwztools/plattools/test_ts.c b/utils/nwztools/plattools/test_ts.c
deleted file mode 100644
index b42d93b..0000000
--- a/utils/nwztools/plattools/test_ts.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2016 Amaury Pouly
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "nwz_lib.h"
-#include "nwz_plattools.h"
-
-int NWZ_TOOL_MAIN(test_ts)(int argc, char **argv)
-{
-    /* clear screen and display welcome message */
-    nwz_lcdmsg(true, 0, 0, "test_ts");
-    nwz_lcdmsg(false, 0, 2, "BACK: quit");
-    /* open input device */
-    int key_fd = nwz_key_open();
-    if(key_fd < 0)
-    {
-        nwz_lcdmsg(false, 3, 4, "Cannot open key device");
-        sleep(2);
-        return 1;
-    }
-    int ts_fd = nwz_ts_open();
-    if(ts_fd < 0)
-    {
-        nwz_key_close(key_fd);
-        nwz_lcdmsg(false, 3, 4, "Cannot open touch screen device");
-        sleep(2);
-        return 1;
-    }
-    /* init state and print maximum information */
-    struct nwz_ts_state_t ts_state;
-    if(nwz_ts_state_init(ts_fd, &ts_state) < 0)
-    {
-        nwz_key_close(key_fd);
-        nwz_ts_close(ts_fd);
-        nwz_lcdmsg(false, 3, 4, "Cannot init touch screen device");
-        sleep(2);
-        return 1;
-    }
-    /* display static information */
-    nwz_lcdmsgf(false, 1, 6, "size: %d, %d       ", ts_state.max_x, ts_state.max_y);
-    /* display input state in a loop */
-    while(1)
-    {
-        /* wait for event */
-        int fds[2] = {key_fd, ts_fd};
-        int ret = nwz_wait_fds(fds, 2, -1);
-        if(ret & 1) /* key_fd */
-        {
-            struct input_event evt;
-            if(nwz_key_read_event(key_fd, &evt) == 1)
-            {
-                if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK &&
-                        nwz_key_event_is_press(&evt))
-                    break; /* quit */
-            }
-        }
-        if(ret & 2) /* ts_fd */
-        {
-#define NR_TS_EVTS  16
-            struct input_event evts[NR_TS_EVTS];
-            int nr = nwz_ts_read_events(ts_fd, evts, NR_TS_EVTS);
-            for(int i = 0; i < nr; i++)
-                if(nwz_ts_state_update(&ts_state, &evts[i]) == 1)
-                {
-                    nwz_lcdmsgf(false, 1, 7, "touch: %s  ", ts_state.touch ? "yes" : "no");
-                    nwz_lcdmsgf(false, 1, 8, "pos: %d, %d       ", ts_state.x, ts_state.y);
-                    nwz_lcdmsgf(false, 1, 9, "pressure: %d     ", ts_state.pressure);
-                    nwz_lcdmsgf(false, 1, 10, "width: %d     ", ts_state.tool_width);
-                    nwz_lcdmsgf(false, 1, 11, "flick: %s ", ts_state.flick ? "yes" : "no");
-                    nwz_lcdmsgf(false, 1, 12, "flick vec: %d, %d    ", ts_state.flick_x, ts_state.flick_y);
-                    /* process touch */
-                    nwz_ts_state_post_syn(&ts_state);
-                }
-#undef NR_TS_EVTS
-        }
-    }
-    /* close input device */
-    nwz_key_close(key_fd);
-    nwz_ts_close(ts_fd);
-    /* finish nicely */
-    return 0;
-}
diff --git a/utils/nwztools/scripts/install_dualboot.sh b/utils/nwztools/scripts/install_dualboot.sh
index c134929..2e2bd05 100644
--- a/utils/nwztools/scripts/install_dualboot.sh
+++ b/utils/nwztools/scripts/install_dualboot.sh
@@ -36,8 +36,6 @@
 . /install_script/constant.txt
 _UPDATE_FN_=`nvpstr ufn`
 ROOTFS_TMP_DIR=/tmp/rootfs
-ROCKBOX_NAME=Rockbox
-ROCKBOX_PATH=$ROOTFS_TMP_DIR/usr/local/bin/$ROCKBOX_NAME
 SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp
 
 # mount root partition
@@ -51,8 +49,12 @@
 
 # NOTE some platforms use ext4 with a custom mount program
 # (/usr/local/bin/icx_mount.ext4), some probably use an mtd too
+# try ext3 and if it fails, try ext2
 mount -t ext3 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
 if [ "$?" != 0 ]; then
+    mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
+fi
+if [ "$?" != 0 ]; then
     lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: mount failed"
     sleep 3
     exit 0
diff --git a/utils/nwztools/scsitools/Makefile b/utils/nwztools/scsitools/Makefile
index 6b2d7a8..53b9014 100644
--- a/utils/nwztools/scsitools/Makefile
+++ b/utils/nwztools/scsitools/Makefile
@@ -3,7 +3,7 @@
 PREFIX?=
 CC=$(PREFIX)gcc
 LD=$(PREFIX)gcc
-NWZ_DB_DIR=../database
+NWZ_DB_DIR=../../../firmware/target/hosted/sonynwz
 INCLUDES=-I$(NWZ_DB_DIR) -I$(SCSI_DIR)
 CFLAGS=-std=c99 -Wall $(DEFINES) $(INCLUDES)
 LDFLAGS=-L$(SCSI_DIR) -lrbscsi
@@ -11,7 +11,7 @@
 
 all: $(BINS)
 
-scsitool: scsitool.c misc.c para_noise.c $(NWZ_DB_DIR)/nwz_db.c
+scsitool: scsitool.c misc.c para_noise.c $(NWZ_DB_DIR)/nwz-db.c
 	$(MAKE) -C $(SCSI_DIR)
 	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
 
diff --git a/utils/nwztools/scsitools/scsitool.c b/utils/nwztools/scsitools/scsitool.c
index 7b8ffd5..63a23c4 100644
--- a/utils/nwztools/scsitools/scsitool.c
+++ b/utils/nwztools/scsitools/scsitool.c
@@ -34,7 +34,7 @@
 #include "rbscsi.h"
 #include "misc.h"
 #include "para_noise.h"
-#include "nwz_db.h"
+#include "nwz-db.h"
 
 bool g_debug = false;
 const char *g_force_series = NULL;