Add support for the NWZ-A860

Change-Id: Ibf0c5168ac31d4ba2aeaa86cbeca37a1011b75fa
diff --git a/apps/SOURCES b/apps/SOURCES
index 521b920..666bf69 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -305,6 +305,8 @@
 keymaps/keymap-ma.c
 #elif CONFIG_KEYPAD == SONY_NWZ_PAD
 keymaps/keymap-nwz.c
+#elif CONFIG_KEYPAD == SONY_NWZA860_PAD
+keymaps/keymap-nwza860.c
 #elif CONFIG_KEYPAD == SAMSUNG_YPZ5_PAD
 keymaps/keymap-ypz5.c
 #elif CONFIG_KEYPAD == IHIFI_PAD
diff --git a/apps/keymaps/keymap-nwza860.c b/apps/keymaps/keymap-nwza860.c
new file mode 100644
index 0000000..f1a3bb6
--- /dev/null
+++ b/apps/keymaps/keymap-nwza860.c
@@ -0,0 +1,289 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright © Amaury Pouly 2017
+ *
+ * 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 "action.h"
+#include "button.h"
+#include "settings.h"
+
+/* {Action Code,    Button code,    Prereq button code } */
+
+/*
+ * The format of the list is as follows
+ * { Action Code,   Button code,    Prereq button code }
+ * if there's no need to check the previous button's value, use BUTTON_NONE
+ * Insert LAST_ITEM_IN_LIST at the end of each mapping
+ */
+static const struct button_mapping button_context_standard[]  = {
+    { ACTION_STD_PREV,                  BUTTON_FF,                         BUTTON_NONE },
+    { ACTION_STD_PREVREPEAT,            BUTTON_FF|BUTTON_REPEAT,           BUTTON_NONE },
+    { ACTION_STD_NEXT,                  BUTTON_REW,                        BUTTON_NONE },
+    { ACTION_STD_NEXTREPEAT,            BUTTON_REW|BUTTON_REPEAT,          BUTTON_NONE },
+
+    { ACTION_STD_CONTEXT,               BUTTON_PLAY|BUTTON_REPEAT,         BUTTON_PLAY },
+
+    { ACTION_STD_MENU,                  BUTTON_BACK,                       BUTTON_NONE },
+    { ACTION_STD_MENU,                  BUTTON_BACK|BUTTON_REPEAT,         BUTTON_NONE },
+    { ACTION_STD_OK,                    BUTTON_PLAY|BUTTON_REL,            BUTTON_PLAY },
+
+    LAST_ITEM_IN_LIST
+}; /* button_context_standard */
+
+static const struct button_mapping button_context_wps[]  = {
+    { ACTION_WPS_PLAY,                  BUTTON_PLAY|BUTTON_REL,            BUTTON_PLAY },
+    { ACTION_WPS_STOP,                  BUTTON_PLAY|BUTTON_REPEAT,         BUTTON_NONE },
+
+    { ACTION_WPS_SKIPNEXT,              BUTTON_FF|BUTTON_REL,              BUTTON_RIGHT },
+    { ACTION_WPS_SEEKFWD,               BUTTON_FF|BUTTON_REPEAT,           BUTTON_NONE },
+    { ACTION_WPS_SKIPPREV,              BUTTON_REW|BUTTON_REL,             BUTTON_LEFT },
+    { ACTION_WPS_SEEKBACK,              BUTTON_REW|BUTTON_REPEAT,          BUTTON_NONE },
+    { ACTION_WPS_STOPSEEK,              BUTTON_REW|BUTTON_REL,             BUTTON_REW|BUTTON_REPEAT },
+    { ACTION_WPS_STOPSEEK,              BUTTON_FF|BUTTON_REL,              BUTTON_FF|BUTTON_REPEAT },
+
+    { ACTION_WPS_VOLUP,                 BUTTON_VOL_UP,                     BUTTON_NONE },
+    { ACTION_WPS_VOLUP,                 BUTTON_VOL_UP|BUTTON_REPEAT,       BUTTON_NONE },
+    { ACTION_WPS_VOLDOWN,               BUTTON_VOL_DOWN,                   BUTTON_NONE },
+    { ACTION_WPS_VOLDOWN,               BUTTON_VOL_DOWN|BUTTON_REPEAT,     BUTTON_NONE },
+
+    { ACTION_WPS_MENU,                  BUTTON_BACK|BUTTON_REPEAT,         BUTTON_NONE },
+    { ACTION_WPS_BROWSE,                BUTTON_BACK|BUTTON_REL,            BUTTON_BACK },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_wps */
+
+static const struct button_mapping button_context_keyboard[]  = {
+    LAST_ITEM_IN_LIST
+}; /* button_context_keyboard */
+
+static const struct button_mapping button_context_quickscreen[]  = {
+    { ACTION_STD_CANCEL,                BUTTON_PLAY,                       BUTTON_NONE },
+    { ACTION_STD_CANCEL,                BUTTON_BACK,                       BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST
+}; /* button_context_quickscreen */
+
+static const struct button_mapping button_context_tree[]  = {
+    { ACTION_TREE_WPS,                  BUTTON_PLAY|BUTTON_REL,            BUTTON_PLAY },
+    { ACTION_TREE_STOP,                 BUTTON_PLAY|BUTTON_REPEAT,         BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST)
+}; /* button_context_tree */
+
+static const struct button_mapping button_context_list[]  = {
+    { ACTION_LIST_VOLUP,                BUTTON_VOL_UP,                     BUTTON_NONE },
+    { ACTION_LIST_VOLUP,                BUTTON_VOL_UP|BUTTON_REPEAT,       BUTTON_NONE },
+    { ACTION_LIST_VOLDOWN,              BUTTON_VOL_DOWN,                   BUTTON_NONE },
+    { ACTION_LIST_VOLDOWN,              BUTTON_VOL_DOWN|BUTTON_REPEAT,     BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_list */
+
+#ifdef CONFIG_TUNER
+static const struct button_mapping button_context_radio[]  = {
+    { ACTION_FM_PLAY,                  BUTTON_PLAY|BUTTON_REL,           BUTTON_PLAY },
+    { ACTION_FM_STOP,                  BUTTON_PLAY|BUTTON_REPEAT,        BUTTON_NONE },
+
+    { ACTION_FM_EXIT,                  BUTTON_BACK,                      BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
+}; /* button_context_radio */
+#endif
+
+#ifdef HAVE_RECORDING
+static const struct button_mapping button_context_recscreen[]  = {
+    { ACTION_REC_PAUSE,                BUTTON_PLAY,                        BUTTON_NONE },
+    { ACTION_SETTINGS_INC,             BUTTON_FF,                          BUTTON_NONE },
+    { ACTION_SETTINGS_INCREPEAT,       BUTTON_FF|BUTTON_REPEAT,            BUTTON_NONE },
+    { ACTION_SETTINGS_DEC,             BUTTON_REW,                        BUTTON_NONE },
+    { ACTION_SETTINGS_DECREPEAT,       BUTTON_REW|BUTTON_REPEAT,          BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_recscreen */
+#endif
+
+static const struct button_mapping button_context_settings[]  = {
+    { ACTION_SETTINGS_INC,              BUTTON_VOL_UP,                     BUTTON_NONE },
+    { ACTION_SETTINGS_INCREPEAT,        BUTTON_VOL_UP|BUTTON_REPEAT,       BUTTON_NONE },
+    { ACTION_SETTINGS_DEC,              BUTTON_VOL_DOWN,                   BUTTON_NONE },
+    { ACTION_SETTINGS_DECREPEAT,        BUTTON_VOL_DOWN|BUTTON_REPEAT,     BUTTON_NONE },
+
+    { ACTION_SETTINGS_RESET,            BUTTON_PLAY|BUTTON_REPEAT,         BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_settings */
+
+static const struct button_mapping button_context_settings_right_is_inc[]  = {
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
+}; /* button_context_settings */
+
+static const struct button_mapping button_context_time[]  = {
+
+    { ACTION_STD_CANCEL,               BUTTON_BACK,                        BUTTON_NONE },
+    { ACTION_STD_OK,                   BUTTON_PLAY,                        BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
+}; /* button_context_time */
+
+static const struct button_mapping button_context_colorchooser[]  = {
+    { ACTION_STD_OK,                    BUTTON_PLAY|BUTTON_REL,            BUTTON_PLAY },
+    { ACTION_STD_CANCEL,                BUTTON_BACK,                       BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_SETTINGS),
+}; /* 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),
+}; /* button_context_eq */
+
+/* Bookmark Screen */
+static const struct button_mapping button_context_bmark[]  = {
+    { ACTION_BMS_DELETE,                BUTTON_PLAY|BUTTON_REPEAT,         BUTTON_PLAY },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST),
+}; /* button_context_bmark */
+
+static const struct button_mapping button_context_pitchscreen[]  = {
+    { ACTION_PS_RESET,          BUTTON_PLAY,                               BUTTON_NONE },
+    { ACTION_PS_EXIT,           BUTTON_BACK,                               BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST
+}; /* button_context_pitchcreen */
+
+static const struct button_mapping button_context_yesno[]  = {
+    { ACTION_YESNO_ACCEPT,              BUTTON_PLAY,                     BUTTON_NONE },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_yesno */
+
+#ifdef USB_ENABLE_HID
+static const struct button_mapping button_context_usb_hid[] = {
+
+    LAST_ITEM_IN_LIST
+}; /* button_context_usb_hid */
+
+static const struct button_mapping button_context_usb_hid_mode_multimedia[] = {
+
+    { ACTION_USB_HID_MULTIMEDIA_VOLUME_DOWN,         BUTTON_VOL_DOWN,               BUTTON_NONE },
+    { ACTION_USB_HID_MULTIMEDIA_VOLUME_DOWN,         BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
+    { ACTION_USB_HID_MULTIMEDIA_VOLUME_UP,           BUTTON_VOL_UP,                 BUTTON_NONE },
+    { ACTION_USB_HID_MULTIMEDIA_VOLUME_UP,           BUTTON_VOL_UP|BUTTON_REPEAT,   BUTTON_NONE },
+    { ACTION_USB_HID_MULTIMEDIA_VOLUME_MUTE,         BUTTON_BACK|BUTTON_REL,        BUTTON_BACK },
+    { ACTION_USB_HID_MULTIMEDIA_PLAYBACK_PLAY_PAUSE, BUTTON_PLAY|BUTTON_REL,        BUTTON_PLAY },
+    { ACTION_USB_HID_MULTIMEDIA_PLAYBACK_STOP,       BUTTON_PLAY|BUTTON_REPEAT,     BUTTON_PLAY },
+    { ACTION_USB_HID_MULTIMEDIA_PLAYBACK_TRACK_PREV, BUTTON_REW|BUTTON_REL,         BUTTON_LEFT },
+    { ACTION_USB_HID_MULTIMEDIA_PLAYBACK_TRACK_NEXT, BUTTON_FF|BUTTON_REL,          BUTTON_RIGHT },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID)
+}; /* button_context_usb_hid_mode_multimedia */
+
+static const struct button_mapping button_context_usb_hid_mode_presentation[] = {
+    { ACTION_USB_HID_PRESENTATION_SLIDESHOW_START, BUTTON_PLAY|BUTTON_REL,          BUTTON_PLAY },
+    { ACTION_USB_HID_PRESENTATION_SLIDESHOW_LEAVE, BUTTON_PLAY|BUTTON_REPEAT,       BUTTON_PLAY },
+    { ACTION_USB_HID_PRESENTATION_SLIDE_PREV,      BUTTON_REW|BUTTON_REL,           BUTTON_REW },
+    { ACTION_USB_HID_PRESENTATION_SLIDE_NEXT,      BUTTON_FF|BUTTON_REL,            BUTTON_FF },
+    { ACTION_USB_HID_PRESENTATION_SLIDE_FIRST,     BUTTON_REW|BUTTON_REPEAT,        BUTTON_NONE },
+    { ACTION_USB_HID_PRESENTATION_SLIDE_LAST,      BUTTON_FF|BUTTON_REPEAT,         BUTTON_NONE },
+    { ACTION_USB_HID_PRESENTATION_MOUSE_CLICK,     BUTTON_PLAY,                     BUTTON_PLAY },
+    { ACTION_USB_HID_PRESENTATION_MOUSE_OVER,      BUTTON_PLAY|BUTTON_REPEAT,       BUTTON_PLAY },
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID)
+}; /* button_context_usb_hid_mode_presentation */
+
+static const struct button_mapping button_context_usb_hid_mode_browser[] = {
+
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID)
+}; /* button_context_usb_hid_mode_browser */
+
+#ifdef HAVE_USB_HID_MOUSE
+static const struct button_mapping button_context_usb_hid_mode_mouse[] = {
+    LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID)
+}; /* button_context_usb_hid_mode_mouse */
+#endif
+#endif
+
+const struct button_mapping* target_get_context_mapping(int context)
+{
+    switch (context)
+    {
+        case CONTEXT_STD:
+            return button_context_standard;
+        case CONTEXT_MAINMENU:
+            return button_context_tree;
+        case CONTEXT_SETTINGS:
+            return button_context_settings;
+        case CONTEXT_WPS:
+            return button_context_wps; 
+        case CONTEXT_YESNOSCREEN:
+            return button_context_yesno;
+        case CONTEXT_SETTINGS_TIME:
+            return button_context_time;
+        case CONTEXT_KEYBOARD:
+        case CONTEXT_MORSE_INPUT:
+            return button_context_keyboard;
+#ifdef CONFIG_TUNER
+        case CONTEXT_FM:
+             return button_context_radio;
+#endif
+        case CONTEXT_LIST:
+            return button_context_list;
+        case CONTEXT_TREE:
+            return button_context_tree;
+        case CONTEXT_SETTINGS_EQ:
+            return button_context_eq;
+#ifdef HAVE_RECORDING
+        case CONTEXT_RECSCREEN:
+            return button_context_recscreen;
+#endif
+        case CONTEXT_QUICKSCREEN:
+            return button_context_quickscreen;
+        case CONTEXT_BOOKMARKSCREEN:
+            return button_context_bmark;
+        case CONTEXT_PITCHSCREEN:
+            return button_context_pitchscreen;
+        case CONTEXT_SETTINGS_COLOURCHOOSER:
+            return button_context_colorchooser;
+        case CONTEXT_SETTINGS_RECTRIGGER:
+            return button_context_settings_right_is_inc;
+    case CONTEXT_CUSTOM|CONTEXT_SETTINGS:
+            return button_context_settings_right_is_inc;
+#ifdef USB_ENABLE_HID
+        case CONTEXT_USB_HID:
+            return button_context_usb_hid;
+        case CONTEXT_USB_HID_MODE_MULTIMEDIA:
+            return button_context_usb_hid_mode_multimedia;
+        case CONTEXT_USB_HID_MODE_PRESENTATION:
+            return button_context_usb_hid_mode_presentation;
+        case CONTEXT_USB_HID_MODE_BROWSER:
+            return button_context_usb_hid_mode_browser;
+#ifdef HAVE_USB_HID_MOUSE
+        case CONTEXT_USB_HID_MODE_MOUSE:
+            return button_context_usb_hid_mode_mouse;
+#endif
+#endif
+        default:
+            return button_context_standard;
+    } 
+    return button_context_standard;
+}
diff --git a/bootloader/nwz_linux.c b/bootloader/nwz_linux.c
index 7fe635b..cac9909 100644
--- a/bootloader/nwz_linux.c
+++ b/bootloader/nwz_linux.c
@@ -63,6 +63,15 @@
 #error toolsicon has the wrong resolution
 #endif
 
+/* the A860 does not have left/right/up/down but it has rew/ff so pretend we
+ * always have rew/ff */
+#ifndef BUTTON_REW
+#define BUTTON_REW  BUTTON_LEFT
+#endif
+#ifndef BUTTON_FF
+#define BUTTON_FF   BUTTON_RIGHT
+#endif
+
 /* buffer for Sony image, filled from NVP */
 unsigned short sonyicon[ICON_WIDTH * ICON_HEIGHT];
 const struct bitmap bm_sonyicon =
@@ -257,9 +266,9 @@
         if(btn == BUTTON_PLAY)
             break;
         /* left/right/up/down: change mode */
-        if(btn == BUTTON_LEFT || btn == BUTTON_DOWN)
+        if(btn == BUTTON_LEFT || btn == BUTTON_DOWN || btn == BUTTON_REW)
             mode = (mode + BOOT_COUNT - 1) % BOOT_COUNT;
-        if(btn == BUTTON_RIGHT || btn == BUTTON_UP)
+        if(btn == BUTTON_RIGHT || btn == BUTTON_UP || btn == BUTTON_FF)
             mode = (mode + 1) % BOOT_COUNT;
     }
 
@@ -340,9 +349,9 @@
             return btn == BUTTON_PLAY ? choice : -1;
         }
         /* left/right/up/down: change mode */
-        if(btn == BUTTON_LEFT || btn == BUTTON_UP)
+        if(btn == BUTTON_LEFT || btn == BUTTON_UP || btn == BUTTON_REW)
             choice = (choice + nr_choices - 1) % nr_choices;
-        if(btn == BUTTON_RIGHT || btn == BUTTON_DOWN)
+        if(btn == BUTTON_RIGHT || btn == BUTTON_DOWN || btn == BUTTON_FF)
             choice = (choice + 1) % nr_choices;
     }
 }
diff --git a/firmware/export/config.h b/firmware/export/config.h
index f98ccbd..abe815d 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -165,6 +165,7 @@
 #define SAMSUNG_YPR1_PAD  61
 #define SAMSUNG_YH92X_PAD  62
 #define DX50_PAD           63
+#define SONY_NWZA860_PAD   64 /* The NWZ-A860 is too different (touchscreen) */
 
 /* CONFIG_REMOTE_KEYPAD */
 #define H100_REMOTE   1
@@ -594,6 +595,8 @@
 #include "config/sonynwa20.h"
 #elif defined(SONY_NWZE470)
 #include "config/sonynwze470.h"
+#elif defined(SONY_NWZA860)
+#include "config/sonynwza860.h"
 #else
 /* no known platform */
 #endif
diff --git a/firmware/export/config/sonynwza860.h b/firmware/export/config/sonynwza860.h
new file mode 100644
index 0000000..f61dd7a
--- /dev/null
+++ b/firmware/export/config/sonynwza860.h
@@ -0,0 +1,24 @@
+/*
+ * This config file is for the Sony NWZ-A860 series
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 107
+
+#define MODEL_NAME   "Sony NWZ-A860 Series"
+
+/* LCD dimensions */
+#define LCD_WIDTH  240
+#define LCD_HEIGHT 400
+/* sqrt(240^2 + 400^2) / 2.8 = 166 */
+#define LCD_DPI 166
+
+/* this device has a touchscreen */
+#define HAVE_TOUCHSCREEN
+#define HAVE_BUTTON_DATA
+
+#include "sonynwzlinux.h"
+
+/* override keypad */
+#undef CONFIG_KEYPAD
+#define CONFIG_KEYPAD SONY_NWZA860_PAD
diff --git a/firmware/target/hosted/sonynwz/button-nwz.c b/firmware/target/hosted/sonynwz/button-nwz.c
index 3be74fc..2fb23e1 100644
--- a/firmware/target/hosted/sonynwz/button-nwz.c
+++ b/firmware/target/hosted/sonynwz/button-nwz.c
@@ -18,7 +18,7 @@
  *
  ****************************************************************************/
 #include "button.h"
-#define LOGF_ENABLE
+//#define LOGF_ENABLE
 #include "logf.h"
 #include "panic.h"
 #include "backlight.h"
@@ -192,6 +192,19 @@
     poll_nfds++;
 }
 
+#if defined(SONY_NWZA860)
+/* 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_FF,
+    [NWZ_KEY_LEFT] = BUTTON_REW,
+    [NWZ_KEY_VOL_DOWN] = BUTTON_VOL_DOWN,
+    [NWZ_KEY_VOL_UP] = BUTTON_VOL_UP,
+    [NWZ_KEY_BACK] = BUTTON_BACK,
+};
+#else /* SONY_NWZA860 */
 /* keycode -> rockbox button mapping */
 static int button_map[NWZ_KEY_MASK + 1] =
 {
@@ -214,6 +227,7 @@
     [NWZ_KEY_AD1_6] = 0,
     [NWZ_KEY_AD1_7] = 0,
 };
+#endif /* SONY_NWZA860 */
 
 static void handle_key(struct input_event evt)
 {
@@ -296,11 +310,16 @@
 #endif
         }
     }
+    int btns = button_bitmap;
 #ifdef HAVE_TOUCHSCREEN
+    /* WARNING we must call touchscreen_to_pixels even if there is no touch,
+     * otherwsise *data is not filled with the last position and it breaks
+     * everything */
+    int touch_bitmap = touchscreen_to_pixels(touch_x, touch_y, data);
     if(touch_detect)
-        button_bitmap |= touchscreen_to_pixels(touch_x, touch_y, data);
+        btns |= touch_bitmap;
 #endif
-    return hold_status ? 0 : button_bitmap;
+    return hold_status ? 0 : btns;
 }
 
 void nwz_button_reload_after_suspend(void)
diff --git a/firmware/target/hosted/sonynwz/button-target.h b/firmware/target/hosted/sonynwz/button-target.h
index 6cf915b..5070728 100644
--- a/firmware/target/hosted/sonynwz/button-target.h
+++ b/firmware/target/hosted/sonynwz/button-target.h
@@ -24,6 +24,40 @@
 #include <stdbool.h>
 #include "config.h"
 
+/* The NWZ-A860 is completely different, it has a touchscreen and some but not
+ * all keys of the other others */
+#if defined(SONY_NWZA860)
+
+/* Main unit's buttons */
+#define BUTTON_BACK                 0x00000001 /* HOME */
+#define BUTTON_PLAY                 0x00000002
+#define BUTTON_REW                  0x00000004
+#define BUTTON_FF                   0x00000008
+#define BUTTON_VOL_DOWN             0x00000010
+#define BUTTON_VOL_UP               0x00000020
+/* For compatibility */
+#define BUTTON_LEFT                 BUTTON_MIDLEFT
+#define BUTTON_RIGHT                BUTTON_MIDRIGHT
+#define BUTTON_UP                   BUTTON_TOPMIDDLE
+#define BUTTON_DOWN                 BUTTON_BOTTOMMIDDLE
+
+/* Touch Screen Area Buttons */
+#define BUTTON_TOPLEFT              0x00000040
+#define BUTTON_TOPMIDDLE            0x00000080
+#define BUTTON_TOPRIGHT             0x00000100
+#define BUTTON_MIDLEFT              0x00000200
+#define BUTTON_CENTER               0x00000400
+#define BUTTON_MIDRIGHT             0x00000800
+#define BUTTON_BOTTOMLEFT           0x00001000
+#define BUTTON_BOTTOMMIDDLE         0x00002000
+#define BUTTON_BOTTOMRIGHT          0x00004000
+
+#define BUTTON_MAIN 0x7fff
+
+#define POWEROFF_BUTTON             BUTTON_BACK
+
+#else /* SONY_NWZA860 */
+
 /* Main unit's buttons */
 #define BUTTON_POWER                0x00000001
 #define BUTTON_BACK                 0x00000002
@@ -37,8 +71,11 @@
 
 #define BUTTON_MAIN                 0x000001ff
 
+#define POWEROFF_BUTTON             BUTTON_POWER
+
+#endif /* SONY_NWZA860 */
+
 /* Software power-off */
-#define POWEROFF_BUTTON BUTTON_POWER
 #define POWEROFF_COUNT 10
 
 /* force driver to reload button state (useful after suspend) */
diff --git a/rbutil/mknwzboot/mknwzboot.c b/rbutil/mknwzboot/mknwzboot.c
index 6fd20b2..73792c3 100644
--- a/rbutil/mknwzboot/mknwzboot.c
+++ b/rbutil/mknwzboot/mknwzboot.c
@@ -50,6 +50,7 @@
     { "Sony NWZ-E580 Series", "e580", 102, "nwz-e580" },
     { "Sony NWZ-A10 Series", "a10", 104, "nwz-a10" },
     { "Sony NW-A20 Series", "a20", 106, "nw-a20" },
+    { "Sony NWZ-A860 Series", "a860", 107, "nwz-a860" },
 };
 
 #define NR_NWZ_MODELS     (sizeof(nwz_models) / sizeof(nwz_models[0]))
diff --git a/tools/configure b/tools/configure
index bfc581f..52eef68 100755
--- a/tools/configure
+++ b/tools/configure
@@ -1512,7 +1512,7 @@
  208) Samsung YP-R1       231) 960               225) NWZ-E580 series
                                                  226) NWZ-A10 series
  ==iBasso==                                      227) NW-A20 series
- 232) DX50
+ 232) DX50                                       228) NWZ-A860 series
  233) DX90
 
 EOF
@@ -4007,6 +4007,29 @@
     sonynwzcc
     ;;
 
+   228|sonynwza860)
+    application="yes"
+    target_id=103
+    modelname="sonynwza860"
+    target="SONY_NWZA860"
+    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=a860"
+    bootoutput="bootloader-nwza860.sony"
+    appextra="gui:recorder"
+    plugins=""
+    swcodec="yes"
+    toolset=$genericbitmaptools
+    t_cpu="hosted"
+    t_manufacturer="sonynwz"
+    t_model="nwza860"
+    uname=`uname`
+    sonynwzcc
+    ;;
+
    230|ihifi760)
     target_id=92
     modelname="ihifi760"
diff --git a/tools/scramble.c b/tools/scramble.c
index 935eae0..5ff45b3 100644
--- a/tools/scramble.c
+++ b/tools/scramble.c
@@ -130,7 +130,7 @@
            "\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, e450, e460,\n"
-           "\t                   e470,e580,a10,a20)\n");
+           "\t                   e470,e580,a10,a20,a860)\n");
     printf("\nNo option results in Archos standard player/recorder format.\n");
 
     exit(1);
@@ -395,6 +395,8 @@
             modelnum = 104;
         else if (!strcmp(&argv[1][5], "a20")) /* Sony NW-A20 series */
             modelnum = 106;
+        else if (!strcmp(&argv[1][5], "a860")) /* Sony NWZ-A860 series */
+            modelnum = 107;
         else {
             fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
             return 2;