Sandisk Sansa Connect port (FS #12363)

Included are drivers for buttons, backlight, lcd, audio and storage.



git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31000 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/SOURCES b/apps/SOURCES
index 7ef81a1..34dc202 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -330,5 +330,7 @@
 keymaps/keymap-hm60x.c
 #elif CONFIG_KEYPAD == HM801_PAD
 keymaps/keymap-hm801.c
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+keymaps/keymap-sansa-connect.c
 #endif
 
diff --git a/apps/keymaps/keymap-sansa-connect.c b/apps/keymaps/keymap-sansa-connect.c
new file mode 100644
index 0000000..6f8a584
--- /dev/null
+++ b/apps/keymaps/keymap-sansa-connect.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* Button Code Definitions for Sandisk Sansa Connect target */
+
+#include "config.h"
+#include "action.h"
+#include "button.h"
+
+/* 
+ * 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_SCROLL_BACK,               BUTTON_NONE},
+  {ACTION_STD_PREVREPEAT, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE},
+  {ACTION_STD_NEXT,       BUTTON_SCROLL_FWD,                BUTTON_NONE},
+  {ACTION_STD_NEXTREPEAT, BUTTON_SCROLL_FWD|BUTTON_REPEAT,  BUTTON_NONE},
+  {ACTION_STD_OK,         BUTTON_SELECT|BUTTON_REL,         BUTTON_SELECT},
+  {ACTION_STD_OK,         BUTTON_RIGHT,                     BUTTON_NONE},
+  {ACTION_STD_CANCEL,     BUTTON_LEFT,                      BUTTON_NONE},
+  {ACTION_STD_CONTEXT,    BUTTON_SELECT|BUTTON_REPEAT,      BUTTON_NONE},
+  {ACTION_STD_MENU,       BUTTON_DOWN|BUTTON_REL,           BUTTON_DOWN},
+  {ACTION_STD_QUICKSCREEN,BUTTON_DOWN|BUTTON_REL,           BUTTON_DOWN},
+  {ACTION_STD_HOTKEY,     BUTTON_UP|BUTTON_REL,             BUTTON_UP},
+  LAST_ITEM_IN_LIST
+}; /* button_context_standard */
+
+static const struct button_mapping button_context_wps[]  = {
+  {ACTION_WPS_PLAY,       BUTTON_DOWN|BUTTON_REL,           BUTTON_DOWN},
+  {ACTION_WPS_SEEKBACK,   BUTTON_LEFT|BUTTON_REPEAT,        BUTTON_NONE},
+  {ACTION_WPS_SEEKFWD,    BUTTON_RIGHT|BUTTON_REPEAT,       BUTTON_NONE},
+  {ACTION_WPS_STOPSEEK,   BUTTON_LEFT|BUTTON_REL,           BUTTON_LEFT|BUTTON_REPEAT},
+  {ACTION_WPS_SKIPNEXT,   BUTTON_NEXT,                      BUTTON_NONE},
+  {ACTION_WPS_SKIPPREV,   BUTTON_PREV,                      BUTTON_NONE},
+  {ACTION_WPS_STOP,       BUTTON_POWER,          BUTTON_NONE},
+  {ACTION_WPS_VOLDOWN,    BUTTON_VOL_DOWN,                  BUTTON_NONE},
+  {ACTION_WPS_VOLDOWN,    BUTTON_VOL_DOWN|BUTTON_REPEAT,    BUTTON_NONE},
+  {ACTION_WPS_VOLUP,      BUTTON_VOL_UP,                    BUTTON_NONE},
+  {ACTION_WPS_VOLUP,      BUTTON_VOL_UP|BUTTON_REPEAT,      BUTTON_NONE},
+  {ACTION_WPS_BROWSE,     BUTTON_SELECT|BUTTON_REL,         BUTTON_SELECT},
+  {ACTION_WPS_CONTEXT,    BUTTON_SELECT|BUTTON_REPEAT,      BUTTON_SELECT},
+  {ACTION_WPS_MENU,       BUTTON_DOWN|BUTTON_REL,           BUTTON_DOWN},
+  {ACTION_WPS_ABSETA_PREVDIR, BUTTON_POWER|BUTTON_RIGHT,    BUTTON_POWER},
+  {ACTION_WPS_ABSETB_NEXTDIR, BUTTON_POWER|BUTTON_LEFT,     BUTTON_POWER},
+  {ACTION_WPS_ABRESET,    BUTTON_POWER|BUTTON_UP,           BUTTON_POWER},
+  {ACTION_WPS_HOTKEY,     BUTTON_UP|BUTTON_REL,             BUTTON_UP},
+    LAST_ITEM_IN_LIST
+}; /* button_context_wps */
+
+
+
+/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
+const struct button_mapping* get_context_mapping(int context)
+{
+    switch (context)
+    {
+        case CONTEXT_STD:
+            return button_context_standard;
+        case CONTEXT_WPS:
+            return button_context_wps;
+            
+        case CONTEXT_TREE:
+        case CONTEXT_LIST:
+        case CONTEXT_MAINMENU:
+            
+        case CONTEXT_SETTINGS:
+        case CONTEXT_SETTINGS|CONTEXT_REMOTE:
+        default:
+            return button_context_standard;
+    } 
+    return button_context_standard;
+}
diff --git a/apps/plugins/battery_bench.c b/apps/plugins/battery_bench.c
index 1adc302..b88c4dc 100644
--- a/apps/plugins/battery_bench.c
+++ b/apps/plugins/battery_bench.c
@@ -235,6 +235,12 @@
 #define BATTERY_ON_TXT  "PLAYPAUSE - start"
 #define BATTERY_OFF_TXT "POWER"
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define BATTERY_ON BUTTON_SELECT
+#define BATTERY_OFF BUTTON_POWER
+#define BATTERY_ON_TXT  "SELECT - start"
+#define BATTERY_OFF_TXT "POWER"
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/blackjack.c b/apps/plugins/blackjack.c
index 5781368..0c35306 100644
--- a/apps/plugins/blackjack.c
+++ b/apps/plugins/blackjack.c
@@ -166,7 +166,8 @@
 #define BJACK_RIGHT         BUTTON_RIGHT
 #define BJACK_LEFT          BUTTON_LEFT
 
-#elif CONFIG_KEYPAD == SANSA_E200_PAD
+#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define BJACK_SELECT_NAME    "SELECT"
 #define BJACK_STAY_NAME     "RIGHT"
 #define BJACK_QUIT_NAME     "POWER"
@@ -1032,7 +1033,8 @@
       (CONFIG_KEYPAD == IPOD_3G_PAD) || \
       (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
       (CONFIG_KEYPAD == SANSA_E200_PAD) || \
-      (CONFIG_KEYPAD == SANSA_FUZE_PAD)
+      (CONFIG_KEYPAD == SANSA_FUZE_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
     rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - h-2, " >>|:     +1");
     rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 - 1, " |<<:     -1");
     rb->lcd_putsxy(LCD_WIDTH/2 - 9*w, LCD_HEIGHT/2 + h, "SCROLL+: +10");
diff --git a/apps/plugins/bounce.c b/apps/plugins/bounce.c
index c3a0dc9..6880e26 100644
--- a/apps/plugins/bounce.c
+++ b/apps/plugins/bounce.c
@@ -110,7 +110,8 @@
 
 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
       CONFIG_KEYPAD == SANSA_CLIP_PAD || \
-      CONFIG_KEYPAD == SANSA_M200_PAD
+      CONFIG_KEYPAD == SANSA_M200_PAD || \
+      CONFIG_KEYPAD == SANSA_CONNECT_PAD
 #define BOUNCE_LEFT BUTTON_LEFT
 #define BOUNCE_RIGHT BUTTON_RIGHT
 #define BOUNCE_UP   BUTTON_UP
diff --git a/apps/plugins/brickmania.c b/apps/plugins/brickmania.c
index 993a3c4..c362ffe 100644
--- a/apps/plugins/brickmania.c
+++ b/apps/plugins/brickmania.c
@@ -139,7 +139,8 @@
 
 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
-CONFIG_KEYPAD == SANSA_M200_PAD
+CONFIG_KEYPAD == SANSA_M200_PAD || \
+CONFIG_KEYPAD == SANSA_CONNECT_PAD
 #define QUIT     BUTTON_POWER
 #define LEFT     BUTTON_LEFT
 #define RIGHT    BUTTON_RIGHT
diff --git a/apps/plugins/calculator.c b/apps/plugins/calculator.c
index 994b066..8288f34 100644
--- a/apps/plugins/calculator.c
+++ b/apps/plugins/calculator.c
@@ -418,6 +418,19 @@
 #define CALCULATOR_CALC  BUTTON_PLAYPAUSE
 #define CALCULATOR_CLEAR BUTTON_BACK
 
+#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
+#define CALCULATOR_LEFT      BUTTON_LEFT
+#define CALCULATOR_RIGHT     BUTTON_RIGHT
+#define CALCULATOR_UP        BUTTON_UP
+#define CALCULATOR_DOWN      BUTTON_DOWN
+#define CALCULATOR_UP_W_SHIFT   BUTTON_SCROLL_BACK
+#define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
+#define CALCULATOR_QUIT      BUTTON_POWER
+#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
+#define CALCULATOR_INPUT     (BUTTON_SELECT|BUTTON_REL)
+#define CALCULATOR_CALC      BUTTON_NEXT
+#define CALCULATOR_CLEAR     BUTTON_PREV
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/calendar.c b/apps/plugins/calendar.c
index 0a94dfc..d8d8f1a 100644
--- a/apps/plugins/calendar.c
+++ b/apps/plugins/calendar.c
@@ -298,6 +298,16 @@
 #define CALENDAR_NEXT_MONTH BUTTON_PLAYPAUSE
 #define CALENDAR_PREV_MONTH BUTTON_BACK
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define CALENDAR_QUIT       BUTTON_POWER
+#define CALENDAR_SELECT     BUTTON_SELECT
+#define CALENDAR_NEXT_WEEK  BUTTON_RIGHT
+#define CALENDAR_PREV_WEEK  BUTTON_LEFT
+#define CALENDAR_NEXT_DAY   BUTTON_UP
+#define CALENDAR_PREV_DAY   BUTTON_DOWN
+#define CALENDAR_NEXT_MONTH BUTTON_NEXT
+#define CALENDAR_PREV_MONTH BUTTON_PREV
+
 #else
 #error "No keypad setting."
 #endif
diff --git a/apps/plugins/chessbox/chessbox_pgn.h b/apps/plugins/chessbox/chessbox_pgn.h
index 9f25eb9..1627426 100644
--- a/apps/plugins/chessbox/chessbox_pgn.h
+++ b/apps/plugins/chessbox/chessbox_pgn.h
@@ -406,6 +406,22 @@
 #define CB_LEVEL   BUTTON_BACK
 #define CB_MENU    (BUTTON_PLAYPAUSE | BUTTON_REPEAT)
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define CB_SELECT  BUTTON_SELECT
+#define CB_UP      BUTTON_UP
+#define CB_DOWN    BUTTON_DOWN
+#define CB_LEFT    BUTTON_LEFT
+#define CB_RIGHT   BUTTON_RIGHT
+#define CB_PLAY    BUTTON_NEXT
+#define CB_LEVEL   BUTTON_VOL_DOWN
+#define CB_RESTART BUTTON_PREV
+#define CB_MENU    BUTTON_POWER
+
+#define CB_SCROLL_UP     (BUTTON_SCROLL_UP|BUTTON_REPEAT)
+#define CB_SCROLL_DOWN   (BUTTON_SCROLL_DOWN|BUTTON_REPEAT)
+#define CB_SCROLL_LEFT   (BUTTON_LEFT|BUTTON_REPEAT)
+#define CB_SCROLL_RIGHT  (BUTTON_RIGHT|BUTTON_REPEAT)
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/chessclock.c b/apps/plugins/chessclock.c
index b05e849..dca5c40 100644
--- a/apps/plugins/chessclock.c
+++ b/apps/plugins/chessclock.c
@@ -316,6 +316,16 @@
 #define CHC_SETTINGS_OK BUTTON_SELECT
 #define CHC_SETTINGS_CANCEL BUTTON_BACK
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define CHC_QUIT BUTTON_POWER
+#define CHC_STARTSTOP BUTTON_NEXT
+#define CHC_RESET BUTTON_PREV
+#define CHC_MENU BUTTON_SELECT
+#define CHC_SETTINGS_INC BUTTON_VOL_UP
+#define CHC_SETTINGS_DEC BUTTON_VOL_DOWN
+#define CHC_SETTINGS_OK BUTTON_SELECT
+#define CHC_SETTINGS_CANCEL BUTTON_LEFT
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/chip8.c b/apps/plugins/chip8.c
index 71024b2..97d8351 100644
--- a/apps/plugins/chip8.c
+++ b/apps/plugins/chip8.c
@@ -1180,6 +1180,19 @@
 #define CHIP8_KEY8 BUTTON_VOL_DOWN
 #define CHIP8_KEY9 BUTTON_VOL_UP
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+
+#define CHIP8_OFF  BUTTON_POWER
+#define CHIP8_KEY1 BUTTON_LEFT
+#define CHIP8_KEY2 BUTTON_UP
+#define CHIP8_KEY3 BUTTON_RIGHT
+#define CHIP8_KEY4 BUTTON_DOWN
+#define CHIP8_KEY5 BUTTON_NEXT
+#define CHIP8_KEY6 BUTTON_PREV
+#define CHIP8_KEY7 BUTTON_SELECT
+#define CHIP8_KEY8 BUTTON_VOL_DOWN
+#define CHIP8_KEY9 BUTTON_VOL_UP
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/chopper.c b/apps/plugins/chopper.c
index ef1f8aa..71ea8f8 100644
--- a/apps/plugins/chopper.c
+++ b/apps/plugins/chopper.c
@@ -70,7 +70,8 @@
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
       (CONFIG_KEYPAD == SANSA_C200_PAD) || \
       (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
-      (CONFIG_KEYPAD == SANSA_M200_PAD)
+      (CONFIG_KEYPAD == SANSA_M200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define QUIT BUTTON_POWER
 #define ACTION BUTTON_SELECT
 #define ACTIONTEXT "SELECT"
diff --git a/apps/plugins/clix.c b/apps/plugins/clix.c
index 14a758f..378e981 100644
--- a/apps/plugins/clix.c
+++ b/apps/plugins/clix.c
@@ -24,7 +24,8 @@
 
 
 
-#if (CONFIG_KEYPAD == SANSA_E200_PAD)
+#if (CONFIG_KEYPAD == SANSA_E200_PAD) || \
+    (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define CLIX_BUTTON_QUIT        BUTTON_POWER
 #define CLIX_BUTTON_UP          BUTTON_UP
 #define CLIX_BUTTON_DOWN        BUTTON_DOWN
diff --git a/apps/plugins/cube.c b/apps/plugins/cube.c
index 5f4a0f6..7e97eaf 100644
--- a/apps/plugins/cube.c
+++ b/apps/plugins/cube.c
@@ -319,6 +319,16 @@
 #define CUBE_PAUSE         BUTTON_PLAYPAUSE
 #define CUBE_HIGHSPEED     BUTTON_BACK
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define CUBE_QUIT          BUTTON_POWER
+#define CUBE_NEXT          BUTTON_NEXT
+#define CUBE_PREV          BUTTON_PREV
+#define CUBE_INC           BUTTON_VOL_UP
+#define CUBE_DEC           BUTTON_VOL_DOWN
+#define CUBE_MODE          BUTTON_SELECT
+#define CUBE_PAUSE         BUTTON_DOWN
+#define CUBE_HIGHSPEED     BUTTON_LEFT
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/doom/i_video.c b/apps/plugins/doom/i_video.c
index 473ce49..d12799c 100644
--- a/apps/plugins/doom/i_video.c
+++ b/apps/plugins/doom/i_video.c
@@ -413,6 +413,16 @@
 #define DOOMBUTTON_ESC     BUTTON_BACK
 #define DOOMBUTTON_ENTER   (BUTTON_PLAYPAUSE|BUTTON_REPEAT)
 #define DOOMBUTTON_WEAPON  (BUTTON_SELECT|BUTTON_REPEAT)
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define DOOMBUTTON_UP      BUTTON_UP
+#define DOOMBUTTON_DOWN    BUTTON_DOWN
+#define DOOMBUTTON_LEFT    BUTTON_LEFT
+#define DOOMBUTTON_RIGHT   BUTTON_RIGHT
+#define DOOMBUTTON_SHOOT   BUTTON_SELECT
+#define DOOMBUTTON_OPEN    BUTTON_VOL_DOWN
+#define DOOMBUTTON_ESC     BUTTON_VOL_UP
+#define DOOMBUTTON_ENTER   BUTTON_NEXT
+#define DOOMBUTTON_WEAPON  BUTTON_PREV
 
 #else
 #error Keymap not defined!
diff --git a/apps/plugins/fft/fft.c b/apps/plugins/fft/fft.c
index fa08848..11bdfc8 100644
--- a/apps/plugins/fft/fft.c
+++ b/apps/plugins/fft/fft.c
@@ -248,6 +248,15 @@
 #   define FFT_AMP_SCALE    BUTTON_PLAYPAUSE
 #   define FFT_QUIT         BUTTON_POWER
 
+#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
+#   define FFT_PREV_GRAPH   BUTTON_LEFT
+#   define FFT_NEXT_GRAPH   BUTTON_RIGHT
+#   define FFT_ORIENTATION  BUTTON_SELECT
+#   define FFT_WINDOW       BUTTON_VOL_DOWN
+#   define FFT_AMP_SCALE    BUTTON_UP
+#   define FFT_FREQ_SCALE   BUTTON_DOWN
+#   define FFT_QUIT         BUTTON_POWER
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/fireworks.c b/apps/plugins/fireworks.c
index 69c7be0..e3a3910 100644
--- a/apps/plugins/fireworks.c
+++ b/apps/plugins/fireworks.c
@@ -68,7 +68,8 @@
 #define BTN_FIRE BUTTON_SELECT
 
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
-      (CONFIG_KEYPAD == SANSA_C200_PAD)
+      (CONFIG_KEYPAD == SANSA_C200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define BTN_MENU BUTTON_POWER
 #define BTN_FIRE BUTTON_SELECT
 
diff --git a/apps/plugins/flipit.c b/apps/plugins/flipit.c
index 70d35ec..ffc691c 100644
--- a/apps/plugins/flipit.c
+++ b/apps/plugins/flipit.c
@@ -368,6 +368,18 @@
 #define FLIPIT_STEP_BY_STEP (BUTTON_BACK|BUTTON_PLAYPAUSE)
 #define FLIPIT_TOGGLE       BUTTON_SELECT
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+
+#define FLIPIT_LEFT         BUTTON_LEFT
+#define FLIPIT_RIGHT        BUTTON_RIGHT
+#define FLIPIT_UP           BUTTON_UP
+#define FLIPIT_DOWN         BUTTON_DOWN
+#define FLIPIT_QUIT         BUTTON_POWER
+#define FLIPIT_SHUFFLE      BUTTON_VOL_UP
+#define FLIPIT_SOLVE        BUTTON_PREV
+#define FLIPIT_STEP_BY_STEP BUTTON_NEXT
+#define FLIPIT_TOGGLE       BUTTON_SELECT
+
 #else
 #error No keymap defined!
 #endif
@@ -838,6 +850,12 @@
     rb->lcd_putsxy(2, 28, "[MODE] shuffle");
     rb->lcd_putsxy(2, 38, "[MENU..] solution");
     rb->lcd_putsxy(2, 48, "[MENU] step by step");
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+    rb->lcd_putsxy(2, 8, "[POWER] to stop");
+    rb->lcd_putsxy(2, 18, "[SELECT] toggle");
+    rb->lcd_putsxy(2, 28, "[VOL+] shuffle");
+    rb->lcd_putsxy(2, 38, "[PREV] solution");
+    rb->lcd_putsxy(2, 48, "[NEXT] step by step");
 #endif
 
 #ifdef HAVE_TOUCHSCREEN
diff --git a/apps/plugins/fractals/fractal.h b/apps/plugins/fractals/fractal.h
index b0fa937..76f3229 100644
--- a/apps/plugins/fractals/fractal.h
+++ b/apps/plugins/fractals/fractal.h
@@ -366,6 +366,18 @@
 #define FRACTAL_PRECISION_DEC   (BUTTON_PLAYPAUSE|BUTTON_RIGHT)
 #define FRACTAL_RESET           BUTTON_BACK
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define FRACTAL_QUIT            BUTTON_POWER
+#define FRACTAL_UP              BUTTON_UP
+#define FRACTAL_DOWN            BUTTON_DOWN
+#define FRACTAL_LEFT            BUTTON_LEFT
+#define FRACTAL_RIGHT           BUTTON_RIGHT
+#define FRACTAL_ZOOM_IN         BUTTON_SCROLL_FWD
+#define FRACTAL_ZOOM_OUT        BUTTON_SCROLL_BACK
+#define FRACTAL_PRECISION_INC   BUTTON_VOL_UP
+#define FRACTAL_PRECISION_DEC   BUTTON_VOL_DOWN
+#define FRACTAL_RESET           BUTTON_PREV
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/goban/goban.h b/apps/plugins/goban/goban.h
index 1931311..d03bc82 100644
--- a/apps/plugins/goban/goban.h
+++ b/apps/plugins/goban/goban.h
@@ -138,6 +138,19 @@
 #define  GBN_BUTTON_CONTEXT            BUTTON_SELECT | BUTTON_REPEAT
 /* No next var */
 
+#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
+#define  GBN_BUTTON_UP                 BUTTON_UP
+#define  GBN_BUTTON_DOWN               BUTTON_DOWN
+#define  GBN_BUTTON_LEFT               BUTTON_LEFT
+#define  GBN_BUTTON_RIGHT              BUTTON_RIGHT
+#define  GBN_BUTTON_RETREAT            BUTTON_VOL_DOWN
+#define  GBN_BUTTON_ADVANCE            BUTTON_VOL_UP
+#define  GBN_BUTTON_MENU               BUTTON_POWER
+#define  GBN_BUTTON_PLAY               BUTTON_SELECT | BUTTON_REL
+#define  GBN_BUTTON_CONTEXT            BUTTON_SELECT | BUTTON_REPEAT
+#define  GBN_BUTTON_NEXT_VAR           BUTTON_NEXT
+
+
 #elif (CONFIG_KEYPAD == CREATIVEZVM_PAD) \
    || (CONFIG_KEYPAD == CREATIVEZV_PAD)
 #define  GBN_BUTTON_UP                 BUTTON_UP
diff --git a/apps/plugins/imageviewer/imageviewer_button.h b/apps/plugins/imageviewer/imageviewer_button.h
index 198b35c..9f345d8 100644
--- a/apps/plugins/imageviewer/imageviewer_button.h
+++ b/apps/plugins/imageviewer/imageviewer_button.h
@@ -364,6 +364,21 @@
 #define IMGVIEW_MENU        BUTTON_SELECT
 #define IMGVIEW_QUIT        BUTTON_POWER
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define IMGVIEW_ZOOM_PRE        BUTTON_SELECT
+#define IMGVIEW_ZOOM_IN         BUTTON_VOL_UP
+#define IMGVIEW_ZOOM_OUT        BUTTON_VOL_DOWN
+#define IMGVIEW_UP              BUTTON_UP
+#define IMGVIEW_DOWN            BUTTON_DOWN
+#define IMGVIEW_LEFT            BUTTON_LEFT
+#define IMGVIEW_RIGHT           BUTTON_RIGHT
+#define IMGVIEW_NEXT            BUTTON_SCROLL_FWD
+#define IMGVIEW_NEXT_REPEAT     (BUTTON_SCROLL_FWD|BUTTON_REPEAT)
+#define IMGVIEW_PREVIOUS        BUTTON_SCROLL_BACK
+#define IMGVIEW_PREVIOUS_REPEAT (BUTTON_SCROLL_BACK|BUTTON_REPEAT)
+#define IMGVIEW_MENU            BUTTON_POWER
+#define IMGVIEW_SLIDE_SHOW      BUTTON_NEXT
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/invadrox.c b/apps/plugins/invadrox.c
index 94d079f..96e04a9 100644
--- a/apps/plugins/invadrox.c
+++ b/apps/plugins/invadrox.c
@@ -129,7 +129,8 @@
 #define RIGHT BUTTON_RIGHT
 #define FIRE BUTTON_SELECT
 
-#elif CONFIG_KEYPAD == SANSA_E200_PAD
+#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 
 #define QUIT BUTTON_POWER
 #define LEFT BUTTON_LEFT
diff --git a/apps/plugins/jewels.c b/apps/plugins/jewels.c
index ae6105b..4d5a5b6 100644
--- a/apps/plugins/jewels.c
+++ b/apps/plugins/jewels.c
@@ -123,7 +123,8 @@
 #define HK_SELECT "SELECT"
 #define HK_CANCEL "POWER"
 
-#elif CONFIG_KEYPAD == SANSA_E200_PAD
+#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define JEWELS_SCROLLWHEEL
 #define JEWELS_UP     BUTTON_UP
 #define JEWELS_DOWN   BUTTON_DOWN
diff --git a/apps/plugins/lamp.c b/apps/plugins/lamp.c
index 7389811..d9ad70b 100644
--- a/apps/plugins/lamp.c
+++ b/apps/plugins/lamp.c
@@ -64,7 +64,8 @@
 #   define LAMP_DOWN       BUTTON_DOWN
 
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
-      (CONFIG_KEYPAD == SANSA_FUZE_PAD)
+      (CONFIG_KEYPAD == SANSA_FUZE_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #   define LAMP_LEFT       BUTTON_LEFT
 #   define LAMP_RIGHT      BUTTON_RIGHT
 #   define LAMP_UP         BUTTON_SCROLL_FWD
diff --git a/apps/plugins/lib/pluginlib_actions.c b/apps/plugins/lib/pluginlib_actions.c
index 4b0f3a6..0a2f12d 100644
--- a/apps/plugins/lib/pluginlib_actions.c
+++ b/apps/plugins/lib/pluginlib_actions.c
@@ -115,7 +115,8 @@
     || (CONFIG_KEYPAD == SANSA_E200_PAD) \
     || (CONFIG_KEYPAD == SANSA_FUZE_PAD) \
     || (CONFIG_KEYPAD == SAMSUNG_YH_PAD) \
-    || (CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD))
+    || (CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD) \
+    || (CONFIG_KEYPAD == SANSA_CONNECT_PAD))
     { PLA_UP,               BUTTON_UP,                          BUTTON_NONE },
     { PLA_DOWN,             BUTTON_DOWN,                        BUTTON_NONE },
     { PLA_LEFT,             BUTTON_LEFT,                        BUTTON_NONE },
@@ -270,7 +271,8 @@
     || CONFIG_KEYPAD == SANSA_CLIP_PAD \
     || CONFIG_KEYPAD == SANSA_M200_PAD \
     || CONFIG_KEYPAD == MROBE100_PAD \
-    || CONFIG_KEYPAD == PHILIPS_HDD1630_PAD)
+    || CONFIG_KEYPAD == PHILIPS_HDD1630_PAD \
+    || CONFIG_KEYPAD == SANSA_CONNECT_PAD)
     {PLA_CANCEL,            BUTTON_POWER|BUTTON_REL,            BUTTON_POWER},
     {PLA_EXIT,              BUTTON_POWER|BUTTON_REPEAT,         BUTTON_NONE},
     {PLA_SELECT,            BUTTON_SELECT,                      BUTTON_NONE},
diff --git a/apps/plugins/logo.c b/apps/plugins/logo.c
index dc0db8e..d651c2f 100644
--- a/apps/plugins/logo.c
+++ b/apps/plugins/logo.c
@@ -98,7 +98,8 @@
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
       (CONFIG_KEYPAD == SANSA_C200_PAD) || \
       (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
-      (CONFIG_KEYPAD == SANSA_M200_PAD)
+      (CONFIG_KEYPAD == SANSA_M200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define LP_QUIT BUTTON_POWER
 #define LP_DEC_X BUTTON_LEFT
 #define LP_INC_X BUTTON_RIGHT
diff --git a/apps/plugins/matrix.c b/apps/plugins/matrix.c
index d1a672c..1a10080 100644
--- a/apps/plugins/matrix.c
+++ b/apps/plugins/matrix.c
@@ -82,7 +82,8 @@
 #define MATRIX_SLEEP_LESS BUTTON_DOWN
 #define MATRIX_PAUSE BUTTON_SELECT
 
-#elif CONFIG_KEYPAD == SANSA_E200_PAD
+#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define MATRIX_EXIT BUTTON_POWER
 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
diff --git a/apps/plugins/midi/midiplay.c b/apps/plugins/midi/midiplay.c
index 3066502..1b5d184 100644
--- a/apps/plugins/midi/midiplay.c
+++ b/apps/plugins/midi/midiplay.c
@@ -225,6 +225,14 @@
 #define BTN_DOWN         BUTTON_DOWN
 #define BTN_PLAY         BUTTON_PLAYPAUSE
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define BTN_QUIT         BUTTON_POWER
+#define BTN_RIGHT        BUTTON_RIGHT
+#define BTN_LEFT         BUTTON_LEFT
+#define BTN_UP           BUTTON_UP
+#define BTN_DOWN         BUTTON_DOWN
+#define BTN_PLAY         BUTTON_SELECT
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/minesweeper.c b/apps/plugins/minesweeper.c
index d8313fb..ad67b1d 100644
--- a/apps/plugins/minesweeper.c
+++ b/apps/plugins/minesweeper.c
@@ -297,6 +297,20 @@
 #   define MINESWP_DISCOVER BUTTON_PLAYPAUSE
 #   define MINESWP_INFO     BUTTON_BACK
 
+#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
+
+#   define MINESWP_SCROLLWHEEL
+#   define MINESWP_LEFT     BUTTON_LEFT
+#   define MINESWP_RIGHT    BUTTON_RIGHT
+#   define MINESWP_UP       BUTTON_UP
+#   define MINESWP_DOWN     BUTTON_DOWN
+#   define MINESWP_QUIT     BUTTON_POWER
+#   define MINESWP_NEXT     BUTTON_SCROLL_FWD
+#   define MINESWP_PREV     BUTTON_SCROLL_BACK
+#   define MINESWP_TOGGLE   BUTTON_NEXT
+#   define MINESWP_DISCOVER BUTTON_SELECT
+#   define MINESWP_INFO     BUTTON_PREV
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/mosaique.c b/apps/plugins/mosaique.c
index f0f260f..ec41c8c 100644
--- a/apps/plugins/mosaique.c
+++ b/apps/plugins/mosaique.c
@@ -188,6 +188,11 @@
 #define MOSAIQUE_SPEED BUTTON_PLAYPAUSE
 #define MOSAIQUE_RESTART BUTTON_BACK
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define MOSAIQUE_QUIT BUTTON_POWER
+#define MOSAIQUE_SPEED BUTTON_SELECT
+#define MOSAIQUE_RESTART BUTTON_DOWN
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/mp3_encoder.c b/apps/plugins/mp3_encoder.c
index ac6a0ba..a70e316 100644
--- a/apps/plugins/mp3_encoder.c
+++ b/apps/plugins/mp3_encoder.c
@@ -2507,6 +2507,12 @@
 #define MP3ENC_DONE BUTTON_PLAYPAUSE
 #define MP3ENC_SELECT BUTTON_SELECT
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define MP3ENC_PREV BUTTON_PREV
+#define MP3ENC_NEXT BUTTON_NEXT
+#define MP3ENC_DONE BUTTON_DOWN
+#define MP3ENC_SELECT BUTTON_SELECT
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c
index 093d8ec..90b5478 100644
--- a/apps/plugins/mpegplayer/mpeg_settings.c
+++ b/apps/plugins/mpegplayer/mpeg_settings.c
@@ -240,6 +240,14 @@
 #define MPEG_START_TIME_DOWN        BUTTON_DOWN
 #define MPEG_START_TIME_EXIT        BUTTON_POWER
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define MPEG_START_TIME_SELECT      BUTTON_SELECT
+#define MPEG_START_TIME_LEFT        BUTTON_LEFT
+#define MPEG_START_TIME_RIGHT       BUTTON_RIGHT
+#define MPEG_START_TIME_UP          BUTTON_UP
+#define MPEG_START_TIME_DOWN        BUTTON_DOWN
+#define MPEG_START_TIME_EXIT        BUTTON_POWER
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index 2491bb1..e3d9865 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -353,6 +353,15 @@
 #define MPEG_RW         BUTTON_LEFT
 #define MPEG_FF         BUTTON_RIGHT
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define MPEG_MENU       BUTTON_POWER
+#define MPEG_PAUSE      (BUTTON_SELECT | BUTTON_REL)
+#define MPEG_STOP       (BUTTON_SELECT | BUTTON_REPEAT)
+#define MPEG_VOLDOWN    BUTTON_VOL_DOWN
+#define MPEG_VOLUP      BUTTON_VOL_UP
+#define MPEG_RW         BUTTON_LEFT
+#define MPEG_FF         BUTTON_RIGHT
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/oscilloscope.c b/apps/plugins/oscilloscope.c
index 52cef65..4469a92 100644
--- a/apps/plugins/oscilloscope.c
+++ b/apps/plugins/oscilloscope.c
@@ -331,6 +331,17 @@
 #define OSCILLOSCOPE_VOL_UP       BUTTON_VOL_UP
 #define OSCILLOSCOPE_VOL_DOWN     BUTTON_VOL_DOWN
 
+#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
+#define OSCILLOSCOPE_QUIT         BUTTON_POWER
+#define OSCILLOSCOPE_DRAWMODE     BUTTON_SELECT
+#define OSCILLOSCOPE_ADVMODE      BUTTON_DOWN
+#define OSCILLOSCOPE_ORIENTATION  BUTTON_UP
+#define OSCILLOSCOPE_PAUSE        BUTTON_NEXT
+#define OSCILLOSCOPE_SPEED_UP     BUTTON_RIGHT
+#define OSCILLOSCOPE_SPEED_DOWN   BUTTON_LEFT
+#define OSCILLOSCOPE_VOL_UP       BUTTON_VOL_UP
+#define OSCILLOSCOPE_VOL_DOWN     BUTTON_VOL_DOWN
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/pacbox/pacbox.h b/apps/plugins/pacbox/pacbox.h
index d9b8ec7..3c906ac 100644
--- a/apps/plugins/pacbox/pacbox.h
+++ b/apps/plugins/pacbox/pacbox.h
@@ -254,6 +254,17 @@
 #define PACMAN_COIN     BUTTON_PLAYPAUSE
 #define PACMAN_MENU     BUTTON_POWER
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+
+#define PACMAN_UP       BUTTON_UP
+#define PACMAN_DOWN     BUTTON_DOWN
+#define PACMAN_LEFT     BUTTON_LEFT
+#define PACMAN_RIGHT    BUTTON_RIGHT
+#define PACMAN_1UP      BUTTON_SELECT
+#define PACMAN_2UP      BUTTON_NEXT
+#define PACMAN_COIN     BUTTON_VOL_DOWN
+#define PACMAN_MENU     BUTTON_POWER
+
 #else
 
 #error Keymap not defined!
diff --git a/apps/plugins/pegbox.c b/apps/plugins/pegbox.c
index babe653..3eb6008 100644
--- a/apps/plugins/pegbox.c
+++ b/apps/plugins/pegbox.c
@@ -491,6 +491,25 @@
 #define LVL_DOWN_TEXT "Vol-"
 #define SELECT_TEXT "SELECT"
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define PEGBOX_SELECT   BUTTON_SELECT
+#define PEGBOX_QUIT     BUTTON_POWER
+#define PEGBOX_SAVE     BUTTON_VOL_UP
+#define PEGBOX_RESTART  BUTTON_VOL_DOWN
+#define PEGBOX_LVL_UP   BUTTON_NEXT
+#define PEGBOX_LVL_DOWN BUTTON_PREV
+#define PEGBOX_UP       BUTTON_UP
+#define PEGBOX_DOWN     BUTTON_DOWN
+#define PEGBOX_RIGHT    BUTTON_RIGHT
+#define PEGBOX_LEFT     BUTTON_LEFT
+
+#define SAVE_TEXT "Vol+"
+#define QUIT_TEXT "POWER"
+#define RESTART_TEXT "Vol-"
+#define LVL_UP_TEXT "NEXT"
+#define LVL_DOWN_TEXT "PREV"
+#define SELECT_TEXT "SELECT"
+
 #else
 #error Unsupported keymap!
 #endif
diff --git a/apps/plugins/plugin.lds b/apps/plugins/plugin.lds
index 7a20ddd..1da9065 100644
--- a/apps/plugins/plugin.lds
+++ b/apps/plugins/plugin.lds
@@ -120,7 +120,7 @@
 #define IRAMSIZE 0
 
 #elif CONFIG_CPU==DM320
-#define DRAMORIG 0x00900000 + STUBOFFSET
+#define DRAMORIG CONFIG_SDRAM_START + STUBOFFSET
 #define IRAM DRAM
 /* The bit of IRAM that is available is used in the core */
 #define IRAMSIZE 0
diff --git a/apps/plugins/pong.c b/apps/plugins/pong.c
index 37d7115..d3875f3 100644
--- a/apps/plugins/pong.c
+++ b/apps/plugins/pong.c
@@ -105,7 +105,8 @@
 
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
       (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
-      (CONFIG_KEYPAD == SANSA_M200_PAD)
+      (CONFIG_KEYPAD == SANSA_M200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define PONG_QUIT BUTTON_POWER
 #define PONG_PAUSE BUTTON_SELECT
 #define PONG_LEFT_UP BUTTON_LEFT
diff --git a/apps/plugins/reversi/reversi-gui.h b/apps/plugins/reversi/reversi-gui.h
index baeb343..a36efe5 100644
--- a/apps/plugins/reversi/reversi-gui.h
+++ b/apps/plugins/reversi/reversi-gui.h
@@ -108,7 +108,8 @@
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
 (CONFIG_KEYPAD == SANSA_C200_PAD) || \
 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
-(CONFIG_KEYPAD == SANSA_M200_PAD)
+(CONFIG_KEYPAD == SANSA_M200_PAD) || \
+(CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define REVERSI_BUTTON_QUIT BUTTON_POWER
 #define REVERSI_BUTTON_UP BUTTON_UP
 #define REVERSI_BUTTON_DOWN BUTTON_DOWN
diff --git a/apps/plugins/rockblox.c b/apps/plugins/rockblox.c
index 07e9c16..9354d10 100644
--- a/apps/plugins/rockblox.c
+++ b/apps/plugins/rockblox.c
@@ -369,6 +369,16 @@
 #define ROCKBLOX_DROP          BUTTON_PLAYPAUSE
 #define ROCKBLOX_RESTART       BUTTON_BACK
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define ROCKBLOX_OFF           BUTTON_POWER
+#define ROCKBLOX_ROTATE_CW     BUTTON_NEXT
+#define ROCKBLOX_ROTATE_CCW    BUTTON_PREV
+#define ROCKBLOX_DOWN          BUTTON_DOWN
+#define ROCKBLOX_LEFT          BUTTON_LEFT
+#define ROCKBLOX_RIGHT         BUTTON_RIGHT
+#define ROCKBLOX_DROP          BUTTON_SELECT
+#define ROCKBLOX_RESTART       BUTTON_VOL_DOWN
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/rockblox1d.c b/apps/plugins/rockblox1d.c
index 073bc30..49219c2 100644
--- a/apps/plugins/rockblox1d.c
+++ b/apps/plugins/rockblox1d.c
@@ -56,7 +56,8 @@
 #elif CONFIG_KEYPAD == SANSA_E200_PAD || \
       CONFIG_KEYPAD == SANSA_C200_PAD || \
       CONFIG_KEYPAD == SANSA_CLIP_PAD || \
-      CONFIG_KEYPAD == SANSA_M200_PAD
+      CONFIG_KEYPAD == SANSA_M200_PAD || \
+      CONFIG_KEYPAD == SANSA_CONNECT_PAD
 #define ONEDROCKBLOX_DOWN              BUTTON_SELECT
 #define ONEDROCKBLOX_QUIT              BUTTON_POWER
 
diff --git a/apps/plugins/rockboy/rockboy.c b/apps/plugins/rockboy/rockboy.c
index f3ca002..37f0566 100644
--- a/apps/plugins/rockboy/rockboy.c
+++ b/apps/plugins/rockboy/rockboy.c
@@ -330,6 +330,18 @@
         options.SELECT = (BUTTON_PLAYPAUSE | BUTTON_REPEAT);
         options.MENU   = (BUTTON_SELECT | BUTTON_REPEAT);
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+        options.UP     = BUTTON_UP;
+        options.DOWN   = BUTTON_DOWN;
+        options.LEFT   = BUTTON_LEFT;
+        options.RIGHT  = BUTTON_RIGHT;
+
+        options.A      = BUTTON_VOL_UP;
+        options.B      = BUTTON_VOL_DOWN;
+        options.START  = BUTTON_PREV;
+        options.SELECT = BUTTON_NEXT;
+        options.MENU   = BUTTON_SELECT;
+
 #else
 #error No Keymap Defined!
 #endif
diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c
index 9ec289f..7f16bf2 100644
--- a/apps/plugins/rockpaint.c
+++ b/apps/plugins/rockpaint.c
@@ -232,6 +232,17 @@
 #define ROCKPAINT_LEFT      BUTTON_LEFT
 #define ROCKPAINT_RIGHT     BUTTON_RIGHT
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define ROCKPAINT_QUIT      BUTTON_POWER
+#define ROCKPAINT_DRAW      BUTTON_SELECT
+#define ROCKPAINT_MENU      BUTTON_VOL_DOWN
+#define ROCKPAINT_TOOLBAR   BUTTON_PREV
+#define ROCKPAINT_TOOLBAR2  BUTTON_NEXT
+#define ROCKPAINT_UP        BUTTON_UP
+#define ROCKPAINT_DOWN      BUTTON_DOWN
+#define ROCKPAINT_LEFT      BUTTON_LEFT
+#define ROCKPAINT_RIGHT     BUTTON_RIGHT
+
 #else
 #error "Please define keys for this keypad"
 #endif
diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c
index 1d857c0..653099a 100644
--- a/apps/plugins/sliding_puzzle.c
+++ b/apps/plugins/sliding_puzzle.c
@@ -254,6 +254,15 @@
 #define PUZZLE_SHUFFLE BUTTON_PLAYPAUSE
 #define PUZZLE_PICTURE BUTTON_SELECT
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define PUZZLE_QUIT    BUTTON_POWER
+#define PUZZLE_LEFT    BUTTON_LEFT
+#define PUZZLE_RIGHT   BUTTON_RIGHT
+#define PUZZLE_UP      BUTTON_UP
+#define PUZZLE_DOWN    BUTTON_DOWN
+#define PUZZLE_SHUFFLE BUTTON_VOL_DOWN
+#define PUZZLE_PICTURE BUTTON_SELECT
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/snake.c b/apps/plugins/snake.c
index 2223887..09e72a5 100644
--- a/apps/plugins/snake.c
+++ b/apps/plugins/snake.c
@@ -105,7 +105,8 @@
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
     (CONFIG_KEYPAD == SANSA_C200_PAD) || \
     (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
-    (CONFIG_KEYPAD == SANSA_M200_PAD)
+    (CONFIG_KEYPAD == SANSA_M200_PAD) || \
+    (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define SNAKE_QUIT BUTTON_POWER
 #define SNAKE_LEFT BUTTON_LEFT
 #define SNAKE_RIGHT BUTTON_RIGHT
diff --git a/apps/plugins/snake2.c b/apps/plugins/snake2.c
index c23772a..0e7b499 100644
--- a/apps/plugins/snake2.c
+++ b/apps/plugins/snake2.c
@@ -200,7 +200,8 @@
 #define SNAKE2_PLAYPAUSE_TEXT "Select"
 
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
-(CONFIG_KEYPAD == SANSA_C200_PAD)
+(CONFIG_KEYPAD == SANSA_C200_PAD) || \
+(CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define SNAKE2_LEFT BUTTON_LEFT
 #define SNAKE2_RIGHT BUTTON_RIGHT
 #define SNAKE2_UP   BUTTON_UP
diff --git a/apps/plugins/snow.c b/apps/plugins/snow.c
index 2a3ba17..8a2de39 100644
--- a/apps/plugins/snow.c
+++ b/apps/plugins/snow.c
@@ -59,7 +59,8 @@
 (CONFIG_KEYPAD == ONDAVX747_PAD) || \
 (CONFIG_KEYPAD == ONDAVX777_PAD) || \
 (CONFIG_KEYPAD == GIGABEAT_PAD) || \
-(CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
+(CONFIG_KEYPAD == IAUDIO_X5M5_PAD) || \
+(CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define SNOW_QUIT BUTTON_POWER
 
 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
diff --git a/apps/plugins/sokoban.c b/apps/plugins/sokoban.c
index c5ba706..ddc9529 100644
--- a/apps/plugins/sokoban.c
+++ b/apps/plugins/sokoban.c
@@ -511,6 +511,21 @@
 #define BUTTON_SAVE          (BUTTON_SELECT|BUTTON_REPEAT)
 #define BUTTON_SAVE_NAME "SELECT LONG"
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define SOKOBAN_LEFT         BUTTON_LEFT
+#define SOKOBAN_RIGHT        BUTTON_RIGHT
+#define SOKOBAN_UP           BUTTON_UP
+#define SOKOBAN_DOWN         BUTTON_DOWN
+#define SOKOBAN_MENU         BUTTON_POWER
+#define SOKOBAN_UNDO         BUTTON_PREV
+#define SOKOBAN_REDO         BUTTON_NEXT
+#define SOKOBAN_LEVEL_DOWN   BUTTON_VOL_DOWN
+#define SOKOBAN_LEVEL_REPEAT (BUTTON_NEXT|BUTTON_PREV)
+#define SOKOBAN_LEVEL_UP     BUTTON_VOL_UP
+#define SOKOBAN_PAUSE        BUTTON_SELECT
+#define BUTTON_SAVE          (BUTTON_SELECT|BUTTON_REPEAT)
+#define BUTTON_SAVE_NAME "SELECT LONG"
+
 #else
 #error No keymap defined!
 #endif
@@ -1487,6 +1502,13 @@
                 rb->lcd_putsxy(3, 36, "[PREV] Previous Level");
                 rb->lcd_putsxy(3, 46, "[PLAY] Restart Level");
                 rb->lcd_putsxy(3, 56, "[NEXT] Next Level");
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+                rb->lcd_putsxy(3,  6, "[POWER] Menu");
+                rb->lcd_putsxy(3, 16, "[PREV] Undo");
+                rb->lcd_putsxy(3, 26, "[NEXT] Redo");
+                rb->lcd_putsxy(3, 36, "[VOL-] Previous Level");
+                rb->lcd_putsxy(3, 46, "[NEXT+PREV] Restart Level");
+                rb->lcd_putsxy(3, 56, "[VOL+] Next Level");
 #endif
 
 #ifdef HAVE_TOUCHSCREEN
diff --git a/apps/plugins/solitaire.c b/apps/plugins/solitaire.c
index b011d1d..91ef346 100644
--- a/apps/plugins/solitaire.c
+++ b/apps/plugins/solitaire.c
@@ -526,6 +526,24 @@
 #   define HK_CUR2STACK      "DOUBLE SELECT"
 #   define HK_REM2STACK      "LEFT"
 
+#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
+#   define SOL_QUIT          BUTTON_POWER
+#   define SOL_UP            BUTTON_UP
+#   define SOL_DOWN          BUTTON_DOWN
+#   define SOL_LEFT          BUTTON_SCROLL_BACK
+#   define SOL_RIGHT         BUTTON_SCROLL_FWD
+#   define SOL_MOVE          BUTTON_SELECT
+#   define SOL_DRAW          BUTTON_VOL_UP
+#   define SOL_REM2CUR       BUTTON_LEFT
+#   define SOL_CUR2STACK_PRE BUTTON_VOL_DOWN
+#   define SOL_CUR2STACK     BUTTON_NEXT
+#   define SOL_REM2STACK     BUTTON_PREV
+#   define HK_MOVE           "SELECT"
+#   define HK_DRAW           "Vol+"
+#   define HK_REM2CUR        "LEFT"
+#   define HK_CUR2STACK      "NEXT"
+#   define HK_REM2STACK      "PREV"
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/spacerocks.c b/apps/plugins/spacerocks.c
index d082640..0c03a31 100644
--- a/apps/plugins/spacerocks.c
+++ b/apps/plugins/spacerocks.c
@@ -268,6 +268,16 @@
 #define AST_RIGHT BUTTON_RIGHT
 #define AST_FIRE BUTTON_SELECT
 
+#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
+
+#define ALT_PAUSE BUTTON_VOL_DOWN
+#define AST_QUIT BUTTON_POWER
+#define AST_THRUST BUTTON_UP
+#define AST_HYPERSPACE BUTTON_DOWN
+#define AST_LEFT BUTTON_LEFT
+#define AST_RIGHT BUTTON_RIGHT
+#define AST_FIRE BUTTON_SELECT
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/star.c b/apps/plugins/star.c
index ebdaca5..620cddf 100644
--- a/apps/plugins/star.c
+++ b/apps/plugins/star.c
@@ -463,6 +463,23 @@
 #define STAR_LEVEL_DOWN_NAME "Vol-"
 #define STAR_LEVEL_REPEAT_NAME "BACK LONG"
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+
+#define STAR_QUIT           BUTTON_POWER
+#define STAR_LEFT           BUTTON_LEFT
+#define STAR_RIGHT          BUTTON_RIGHT
+#define STAR_UP             BUTTON_UP
+#define STAR_DOWN           BUTTON_DOWN
+#define STAR_TOGGLE_CONTROL BUTTON_SELECT
+#define STAR_LEVEL_UP       BUTTON_VOL_UP
+#define STAR_LEVEL_DOWN     BUTTON_VOL_DOWN
+#define STAR_LEVEL_REPEAT   (BUTTON_PREV | BUTTON_REPEAT)
+#define STAR_TOGGLE_CONTROL_NAME "SELECT"
+#define STAR_QUIT_NAME      "POWER"
+#define STAR_LEVEL_UP_NAME  "Vol+"
+#define STAR_LEVEL_DOWN_NAME "Vol-"
+#define STAR_LEVEL_REPEAT_NAME "PREV LONG"
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/starfield.c b/apps/plugins/starfield.c
index 6ead68f..e3b5634 100644
--- a/apps/plugins/starfield.c
+++ b/apps/plugins/starfield.c
@@ -61,7 +61,8 @@
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
       (CONFIG_KEYPAD == SANSA_C200_PAD) || \
       (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
-      (CONFIG_KEYPAD == SANSA_M200_PAD)
+      (CONFIG_KEYPAD == SANSA_M200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define STARFIELD_QUIT BUTTON_POWER
 #define STARFIELD_INCREASE_ZMOVE BUTTON_UP
 #define STARFIELD_DECREASE_ZMOVE BUTTON_DOWN
diff --git a/apps/plugins/stats.c b/apps/plugins/stats.c
index 1bfd107..c5ff31e 100644
--- a/apps/plugins/stats.c
+++ b/apps/plugins/stats.c
@@ -58,7 +58,8 @@
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
 (CONFIG_KEYPAD == SANSA_C200_PAD) || \
 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
-(CONFIG_KEYPAD == SANSA_M200_PAD)
+(CONFIG_KEYPAD == SANSA_M200_PAD) || \
+(CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define STATS_STOP BUTTON_POWER
 
 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
diff --git a/apps/plugins/stopwatch.c b/apps/plugins/stopwatch.c
index 03f183e..94785dc 100644
--- a/apps/plugins/stopwatch.c
+++ b/apps/plugins/stopwatch.c
@@ -255,6 +255,14 @@
 #define STOPWATCH_SCROLL_UP BUTTON_UP
 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define STOPWATCH_QUIT BUTTON_POWER
+#define STOPWATCH_START_STOP BUTTON_SELECT
+#define STOPWATCH_RESET_TIMER BUTTON_LEFT
+#define STOPWATCH_LAP_TIMER BUTTON_RIGHT
+#define STOPWATCH_SCROLL_UP BUTTON_UP
+#define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/sudoku/sudoku.h b/apps/plugins/sudoku/sudoku.h
index 86a8b33..456e4fd 100644
--- a/apps/plugins/sudoku/sudoku.h
+++ b/apps/plugins/sudoku/sudoku.h
@@ -318,6 +318,17 @@
 #define SUDOKU_BUTTON_TOGGLEBACK BUTTON_DOWN
 #define SUDOKU_BUTTON_POSSIBLE   BUTTON_PLAYPAUSE
 
+#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
+#define SUDOKU_BUTTON_QUIT BUTTON_POWER
+#define SUDOKU_BUTTON_UP BUTTON_UP
+#define SUDOKU_BUTTON_DOWN BUTTON_DOWN
+#define SUDOKU_BUTTON_LEFT BUTTON_LEFT
+#define SUDOKU_BUTTON_RIGHT BUTTON_RIGHT
+#define SUDOKU_BUTTON_TOGGLEBACK BUTTON_PREV
+#define SUDOKU_BUTTON_TOGGLE BUTTON_NEXT
+#define SUDOKU_BUTTON_MENU BUTTON_SELECT
+#define SUDOKU_BUTTON_POSSIBLE BUTTON_VOL_DOWN
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/superdom.c b/apps/plugins/superdom.c
index 2dfd142..b4e25af 100644
--- a/apps/plugins/superdom.c
+++ b/apps/plugins/superdom.c
@@ -190,6 +190,14 @@
 #define SUPERDOM_RIGHT  BUTTON_RIGHT
 #define SUPERDOM_CANCEL BUTTON_BACK
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define SUPERDOM_OK BUTTON_SELECT
+#define SUPERDOM_UP BUTTON_UP
+#define SUPERDOM_DOWN BUTTON_DOWN
+#define SUPERDOM_LEFT BUTTON_LEFT
+#define SUPERDOM_RIGHT BUTTON_RIGHT
+#define SUPERDOM_CANCEL BUTTON_POWER
+
 #endif
 
 #ifdef HAVE_TOUCHSCREEN
diff --git a/apps/plugins/text_viewer/tv_button.h b/apps/plugins/text_viewer/tv_button.h
index 3de2762..697076e 100644
--- a/apps/plugins/text_viewer/tv_button.h
+++ b/apps/plugins/text_viewer/tv_button.h
@@ -424,6 +424,18 @@
 #define TV_AUTOSCROLL   BUTTON_BACK
 #define TV_BOOKMARK     BUTTON_PLAYPAUSE
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define TV_QUIT         BUTTON_POWER
+#define TV_SCROLL_UP    BUTTON_UP
+#define TV_SCROLL_DOWN  BUTTON_DOWN
+#define TV_SCREEN_LEFT  BUTTON_LEFT
+#define TV_SCREEN_RIGHT BUTTON_RIGHT
+#define TV_MENU         BUTTON_SELECT
+#define TV_AUTOSCROLL   BUTTON_VOL_DOWN
+#define TV_LINE_UP      BUTTON_SCROLL_BACK
+#define TV_LINE_DOWN    BUTTON_SCROLL_FWD
+#define TV_BOOKMARK     (BUTTON_DOWN|BUTTON_SELECT)
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/vu_meter.c b/apps/plugins/vu_meter.c
index 27f9fe0..cf66070 100644
--- a/apps/plugins/vu_meter.c
+++ b/apps/plugins/vu_meter.c
@@ -327,6 +327,17 @@
 #define LABEL_MENU "BACK"
 #define LABEL_VOLUME "UP/DOWN"
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define VUMETER_QUIT BUTTON_POWER
+#define VUMETER_HELP BUTTON_NEXT
+#define VUMETER_MENU BUTTON_PREV
+#define VUMETER_UP BUTTON_UP
+#define VUMETER_DOWN BUTTON_DOWN
+#define LABEL_HELP "NEXT"
+#define LABEL_QUIT "POWER"
+#define LABEL_MENU "PREV"
+#define LABEL_VOLUME "VOL+/VOL-"
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/wormlet.c b/apps/plugins/wormlet.c
index bb35269..016c4ad 100644
--- a/apps/plugins/wormlet.c
+++ b/apps/plugins/wormlet.c
@@ -310,6 +310,16 @@
 #define BTN_QUIT BUTTON_POWER
 #define BTN_STOPRESET BUTTON_BACK
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+
+#define BTN_DIR_UP BUTTON_UP
+#define BTN_DIR_DOWN BUTTON_DOWN
+#define BTN_DIR_LEFT BUTTON_LEFT
+#define BTN_DIR_RIGHT BUTTON_RIGHT
+#define BTN_STARTPAUSE BUTTON_SELECT
+#define BTN_QUIT BUTTON_POWER
+#define BTN_STOPRESET BUTTON_VOL_DOWN
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/xobox.c b/apps/plugins/xobox.c
index 33cf823..8de0c8f 100644
--- a/apps/plugins/xobox.c
+++ b/apps/plugins/xobox.c
@@ -268,6 +268,15 @@
 #define DOWN  BUTTON_DOWN
 #define PAUSE BUTTON_PLAYPAUSE
 
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+
+#define QUIT  BUTTON_POWER
+#define LEFT  BUTTON_LEFT
+#define RIGHT BUTTON_RIGHT
+#define UP    BUTTON_UP
+#define DOWN  BUTTON_DOWN
+#define PAUSE BUTTON_SELECT
+
 #else
 #error No keymap defined!
 #endif
diff --git a/apps/plugins/zxbox/keymaps.h b/apps/plugins/zxbox/keymaps.h
index 5f216fd..4e5d73a 100644
--- a/apps/plugins/zxbox/keymaps.h
+++ b/apps/plugins/zxbox/keymaps.h
@@ -89,7 +89,8 @@
 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
       (CONFIG_KEYPAD == SANSA_C200_PAD) || \
       (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
-      (CONFIG_KEYPAD == SANSA_M200_PAD)
+      (CONFIG_KEYPAD == SANSA_M200_PAD) || \
+      (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 #define ZX_SELECT BUTTON_SELECT
 #define ZX_MENU BUTTON_POWER
 #define ZX_LEFT BUTTON_LEFT
diff --git a/apps/plugins/zxbox/zxbox_keyb.c b/apps/plugins/zxbox/zxbox_keyb.c
index 92a56a8..fc5ed41 100644
--- a/apps/plugins/zxbox/zxbox_keyb.c
+++ b/apps/plugins/zxbox/zxbox_keyb.c
@@ -117,7 +117,8 @@
 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
 (CONFIG_KEYPAD == SANSA_M200_PAD) || \
 (CONFIG_KEYPAD == SANSA_FUZE_PAD) || \
-(CONFIG_KEYPAD == MROBE100_PAD)
+(CONFIG_KEYPAD == MROBE100_PAD) || \
+(CONFIG_KEYPAD == SANSA_CONNECT_PAD)
 
 /* TODO: Check keyboard mappings */
 
diff --git a/bootloader/SOURCES b/bootloader/SOURCES
index 1725939..4678175 100644
--- a/bootloader/SOURCES
+++ b/bootloader/SOURCES
@@ -70,4 +70,7 @@
 #elif defined(RK27_GENERIC) || defined(HM60X) || defined(HM801)
 rk27xx.c
 show_logo.c
+#elif defined(SANSA_CONNECT)
+sansaconnect.c
+show_logo.c
 #endif
diff --git a/bootloader/sansaconnect.c b/bootloader/sansaconnect.c
new file mode 100644
index 0000000..9ef831f
--- /dev/null
+++ b/bootloader/sansaconnect.c
@@ -0,0 +1,135 @@
+/***************************************************************************
+*             __________               __   ___.
+*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+*                     \/            \/     \/    \/            \/
+* $Id: $
+*
+* Copyright (C) 2011 by Tomasz Moń
+*
+* All files in this archive are subject to the GNU General Public License.
+* See the file COPYING in the source tree root for full license agreement.
+*
+* 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 "kernel.h"
+#include "thread.h"
+#include "storage.h"
+#include "ata-target.h"
+#include "disk.h"
+#include "font.h"
+#include "backlight.h"
+#include "button.h"
+#include "common.h"
+#include "version.h"
+#include "uart-target.h"
+#include "power.h"
+
+extern void show_logo(void);
+
+void main(void)
+{
+    unsigned char* loadbuffer;
+    int buffer_size;
+    int(*kernel_entry)(void);
+    int ret;
+    int btn;
+
+    /* Make sure interrupts are disabled */
+    set_irq_level(IRQ_DISABLED);
+    set_fiq_status(FIQ_DISABLED);
+    system_init();
+    kernel_init();
+
+    /* Now enable interrupts */
+    set_irq_level(IRQ_ENABLED);
+    set_fiq_status(FIQ_ENABLED);
+    backlight_init();
+    lcd_init();
+    font_init();
+    button_init();
+
+#ifdef HAVE_LCD_ENABLE
+    lcd_enable(true);
+#endif
+    lcd_setfont(FONT_SYSFIXED);
+    reset_screen();
+    show_logo();
+
+    btn = button_read_device();
+
+    printf("Rockbox boot loader");
+    printf("Version " RBVERSION);
+
+    ret = storage_init();
+    if(ret)
+        printf("SD error: %d", ret);
+
+    disk_init(IF_MD(0));
+
+    ret = disk_mount_all();
+    if (ret <= 0)
+        error(EDISK, ret, true);
+
+    if (btn & BUTTON_PREV)
+    {
+        printf("Loading OF firmware...");
+        printf("Loading vmlinux.bin...");
+        loadbuffer = (unsigned char*)0x01008000;
+        buffer_size = 0x200000;
+
+        ret = load_raw_firmware(loadbuffer, "/vmlinux.bin", buffer_size);
+
+        if (ret < 0)
+        {
+            printf("Unable to load vmlinux.bin");
+        }
+        else
+        {
+            printf("Loading initrd.bin...");
+            loadbuffer = (unsigned char*)0x04400020;
+            buffer_size = 0x200000;
+            ret = load_raw_firmware(loadbuffer, "/initrd.bin", buffer_size);
+        }
+
+        if (ret > 0)
+        {
+            system_prepare_fw_start();
+
+            kernel_entry = (void*)0x01008000;
+            ret = kernel_entry();
+            printf("FAILED to boot OF");
+        }
+    }
+
+    printf("Loading Rockbox firmware...");
+
+    loadbuffer = (unsigned char*)CONFIG_SDRAM_START;
+    buffer_size = 0x1000000;
+
+    ret = load_firmware(loadbuffer, BOOTFILE, buffer_size);
+
+    if(ret < 0)
+    {
+        error(EBOOTFILE, ret, true);
+    }
+    else if(ret == EOK)
+    {
+        system_prepare_fw_start();
+
+        kernel_entry = (void*) loadbuffer;
+        ret = kernel_entry();
+        printf("FAILED!");
+    }
+    
+    storage_sleepnow();
+    
+    while(1);
+}
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 6a84b5f..b918a19 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -355,6 +355,8 @@
 drivers/audio/cs42l55.c
 #elif defined (HAVE_RK27XX_CODEC)
 drivers/audio/rk27xx_codec.c
+#elif defined(HAVE_AIC3X)
+drivers/audio/aic3x.c
 #elif defined (HAVE_DUMMY_CODEC)
 drivers/audio/dummy_codec.c
 #endif /* defined(HAVE_*) */
@@ -1064,6 +1066,9 @@
 target/arm/tms320dm320/debug-dm320.c
 target/arm/tms320dm320/dsp-dm320.c
 target/arm/tms320dm320/i2c-dm320.c
+#ifdef HAVE_SOFTWARE_I2C
+drivers/generic_i2c.c
+#endif
 target/arm/tms320dm320/kernel-dm320.c
 target/arm/tms320dm320/spi-dm320.c
 target/arm/tms320dm320/system-dm320.c
@@ -1112,6 +1117,24 @@
 #endif /* SIMULATOR */
 #endif /* CREATIVE_ZVx */
 
+#ifdef SANSA_CONNECT
+#ifndef SIMULATOR
+target/arm/mmu-arm.S
+target/arm/lcd-as-memframe.S
+target/arm/tms320dm320/sdmmc-dm320.c
+target/arm/tms320dm320/sansa-connect/crt0-board.S
+target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c
+target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c
+target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
+target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c
+target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c
+target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
+target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c
+target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
+target/arm/tms320dm320/dma-dm320.c
+#endif /* SIMULATOR */
+#endif /* SANSA_CONNECT */
+
 #ifdef MROBE_100
 #ifndef SIMULATOR
 #ifndef BOOTLOADER
diff --git a/firmware/drivers/audio/aic3x.c b/firmware/drivers/audio/aic3x.c
new file mode 100644
index 0000000..3284326
--- /dev/null
+++ b/firmware/drivers/audio/aic3x.c
@@ -0,0 +1,247 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "logf.h"
+#include "system.h"
+#include "string.h"
+#include "audio.h"
+
+#ifdef SANSA_CONNECT
+#include "avr-sansaconnect.h"
+#endif
+
+#if CONFIG_I2C == I2C_DM320
+#include "i2c-dm320.h"
+#endif
+#include "audiohw.h"
+
+/* (7-bit) address is 0x18, the LSB is read/write flag */
+#define AIC3X_ADDR (0x18 << 1)
+
+static char volume_left = 0, volume_right = 0;
+
+const struct sound_settings_info audiohw_settings[] = {
+    [SOUND_VOLUME]        = {"dB", 0,  1, VOLUME_MIN/10, VOLUME_MAX/10, -25},
+    /* HAVE_SW_TONE_CONTROLS */
+    [SOUND_BASS]          = {"dB", 0,  1, -24,  24,   0},
+    [SOUND_TREBLE]        = {"dB", 0,  1, -24,  24,   0},
+    [SOUND_BALANCE]       = {"%",  0,  1,-100, 100,   0},
+    [SOUND_CHANNELS]      = {"",   0,  1,   0,   5,   0},
+    [SOUND_STEREO_WIDTH]  = {"%",  0,  5,   0, 250, 100},
+};
+
+/* convert tenth of dB volume to master volume register value */
+int tenthdb2master(int db)
+{
+    /* 0 to -63.0dB in 1dB steps, aic3x can goto -63.5 in 0.5dB steps */
+    if (db < VOLUME_MIN)
+    {
+        return 0x7E;
+    }
+    else if (db >= VOLUME_MAX)
+    {
+        return 0x00;
+    }
+    else
+    {
+        return (-((db)/5)); /* VOLUME_MIN is negative */
+    }
+}
+
+static void aic3x_write_reg(unsigned reg, unsigned value)
+{
+    unsigned char data[2];
+
+    data[0] = reg;
+    data[1] = value;
+
+#if CONFIG_I2C == I2C_DM320
+    if (i2c_write(AIC3X_ADDR, data, 2) != 0)
+#else
+    #warning Implement aic3x_write_reg()
+#endif
+    {
+        logf("AIC3X error reg=0x%x", reg);
+        return;
+    }
+}
+
+static void aic3x_apply_volume(void)
+{
+    unsigned char data[3];
+
+#if 0 /* handle page switching onve we use first page at all */
+    aic3x_write_reg(0, 0); /* switch to page 0 */
+#endif
+
+    data[0] = AIC3X_LEFT_VOL;
+    data[1] = volume_left;
+    data[2] = volume_right;
+
+    /* use autoincrement write */
+#if CONFIG_I2C == I2C_DM320
+    if (i2c_write(AIC3X_ADDR, data, 3) != 0)
+#else
+    #warning Implement aic3x_apply_volume()
+#endif
+    {
+        logf("AIC3X error in apply volume");
+        return;
+    }
+}
+
+
+static void audiohw_mute(bool mute)
+{
+    if (mute)
+    {
+        volume_left |= 0x80;
+        volume_right |= 0x80;
+    }
+    else
+    {
+        volume_left &= 0x7F;
+        volume_right &= 0x7F;
+    }
+
+    aic3x_apply_volume();
+}
+
+/* public functions */
+
+/**
+ * Init our tlv with default values
+ */
+void audiohw_init(void)
+{
+    logf("AIC3X init");
+
+    /* Do software reset (self-clearing) */
+    aic3x_write_reg(AIC3X_SOFT_RESET, 0x80);
+
+    /* ADC fs = fs(ref)/5.5; DAC fs = fs(ref) */
+    aic3x_write_reg(AIC3X_SMPL_RATE, 0x90);
+
+    /* Enable PLL. Set Q=16, P=1 */
+    aic3x_write_reg(AIC3X_PLL_REG_A, 0x81);
+    /* PLL J = 53 */
+    aic3x_write_reg(AIC3X_PLL_REG_B, 0xD4);
+    /* PLL D = 5211 */
+    aic3x_write_reg(AIC3X_PLL_REG_C, 0x51); 
+    aic3x_write_reg(AIC3X_PLL_REG_D, 0x6C); /* PLL D = 5211 */
+
+    /* Left DAC plays left channel, Right DAC plays right channel */ 
+    aic3x_write_reg(AIC3X_DATAPATH, 0xA);
+
+    /* Audio data interface */
+    /* BCLK and WCLK are outputs (master mode) */
+    aic3x_write_reg(AIC3X_DATA_REG_A, 0xC0);
+    /* right-justified mode */
+    aic3x_write_reg(AIC3X_DATA_REG_B, 0x80);
+    /* data offset = 0 clocks */
+    aic3x_write_reg(AIC3X_DATA_REG_C, 0);
+    
+    /* GPIO1 used for audio serial data bus ADC word clock */
+    aic3x_write_reg(AIC3X_GPIO1_CTRL, 0x10);
+
+    /* power left and right DAC, HPLCOM constant VCM output */
+    aic3x_write_reg(AIC3X_DAC_POWER, 0xD0);
+    /* HPRCOM as constant VCM output. Enable short-circuit protection
+       (limit current) */
+    aic3x_write_reg(AIC3X_HIGH_POWER, 0xC);
+    
+    /* driver power-on time 200 ms, ramp-up step time 4 ms */
+    aic3x_write_reg(AIC3X_POP_REDUCT, 0x7C);
+
+    /* DAC_L1 routed to HPLOUT, volume analog gain 0xC (-6.0dB) */
+    aic3x_write_reg(AIC3X_DAC_L1_VOL, 0x8C);
+    /* HPLOUT output level 0dB, not muted, fully powered up */
+    aic3x_write_reg(AIC3X_HPLOUT_LVL, 0xB);
+
+    /* HPLCOM is muted */
+    aic3x_write_reg(AIC3X_HPLCOM_LVL, 0x7);
+
+    /* DAC_R1 routed to HPROUT, volume analog gain 0xC (-6.0 dB) */
+    aic3x_write_reg(AIC3X_DAC_R1_VOL, 0x8C);
+    /* HPROUT output level 0dB, not muted, fully powered up */
+    aic3x_write_reg(AIC3X_HPROUT_LVL, 0xB);
+
+    /* DAC_L1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */
+    aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL, 0x92);
+    /* DAC_R1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */
+    aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL, 0x92);
+    
+    /* MONO_LOP output level 6dB, not muted, fully powered up */
+    aic3x_write_reg(AIC3X_MONO_LOP_M_LVL, 0x6b);
+
+    /* DAC_L1 routed to LEFT_LOP/M */
+    aic3x_write_reg(AIC3X_DAC_L1_LEFT_LOP_M_VOL, 0x80);
+    /* LEFT_LOP/M output level 0dB, not muted */
+    aic3x_write_reg(AIC3X_LEFT_LOP_M_LVL, 0xB);
+
+    /* DAC_R1 routed to RIGHT_LOP/M */
+    aic3x_write_reg(AIC3X_DAC_R1_RIGHT_LOP_M_VOL, 0x80);
+    /* RIGHT_LOP/M output level 0dB, not muted */
+    aic3x_write_reg(AIC3X_RIGHT_LOP_M_LVL, 0xB);
+}
+
+void audiohw_postinit(void)
+{
+   audiohw_mute(false);
+
+   /* Power up Left, Right DAC/LOP, HPLOUT and HPROUT */
+   aic3x_write_reg(AIC3X_MOD_POWER, 0xFE);
+}
+
+void audiohw_set_frequency(int fsel)
+{
+    (void)fsel;
+    /* TODO */
+}
+
+void audiohw_set_headphone_vol(int vol_l, int vol_r)
+{
+    if ((volume_left & 0x7F) == (vol_l & 0x7F) &&
+        (volume_right & 0x7F) == (vol_r & 0x7F))
+    {
+        /* Volume already set to this value */
+        return;
+    }
+
+    volume_left &= 0x80; /* preserve mute bit */
+    volume_left |= (vol_l & 0x7F); /* set gain */
+
+    volume_right &= 0x80; /* preserve mute bit */
+    volume_right |= (vol_r & 0x7F); /* set gain */
+
+    aic3x_apply_volume();
+}
+
+/* Nice shutdown of AIC3X codec */
+void audiohw_close(void)
+{
+    audiohw_mute(true);
+#ifdef SANSA_CONNECT
+    avr_hid_reset_codec();
+#endif
+}
+
+
diff --git a/firmware/export/aic3x.h b/firmware/export/aic3x.h
new file mode 100644
index 0000000..17e5ea0
--- /dev/null
+++ b/firmware/export/aic3x.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 _AIC3X_H_
+#define _AIC3X_H_
+
+#define VOLUME_MIN -630
+#define VOLUME_MAX  0
+
+extern int tenthdb2master(int db);
+
+/*** definitions ***/
+extern void audiohw_set_headphone_vol(int vol_l, int vol_r);
+
+/* Page 0 registers */
+#define AIC3X_PAGE_SELECT 0
+#define AIC3X_SOFT_RESET  1
+#define AIC3X_SMPL_RATE   2
+#define AIC3X_PLL_REG_A   3
+#define AIC3X_PLL_REG_B   4
+#define AIC3X_PLL_REG_C   5
+#define AIC3X_PLL_REG_D   6
+#define AIC3X_DATAPATH    7
+#define AIC3X_DATA_REG_A  8
+#define AIC3X_DATA_REG_B  9
+#define AIC3X_DATA_REG_C  10
+
+#define AIC3X_DAC_POWER   37
+#define AIC3X_HIGH_POWER  38
+
+#define AIC3X_POP_REDUCT  42
+#define AIC3X_LEFT_VOL    43
+#define AIC3X_RIGHT_VOL   44
+
+#define AIC3X_DAC_L1_VOL  47
+#define AIC3X_HPLOUT_LVL  51
+
+#define AIC3X_HPLCOM_LVL  58
+
+#define AIC3X_DAC_R1_VOL  64
+#define AIC3X_HPROUT_LVL  65
+
+#define AIC3X_DAC_L1_MONO_LOP_M_VOL 75
+
+#define AIC3X_DAC_R1_MONO_LOP_M_VOL 76
+
+#define AIC3X_MONO_LOP_M_LVL 79
+
+#define AIC3X_DAC_L1_LEFT_LOP_M_VOL 82
+
+#define AIC3X_LEFT_LOP_M_LVL 86
+
+#define AIC3X_DAC_R1_RIGHT_LOP_M_VOL 92
+#define AIC3X_RIGHT_LOP_M_LVL 93
+#define AIC3X_MOD_POWER   94
+
+#define AIC3X_GPIO1_CTRL  98
+
+#endif /*_AIC3X_H_*/
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h
index 6bf4d71..102d107 100644
--- a/firmware/export/audiohw.h
+++ b/firmware/export/audiohw.h
@@ -70,6 +70,8 @@
 #include "ak4537.h"
 #elif defined(HAVE_RK27XX_CODEC)
 #include "rk27xx_codec.h"
+#elif defined(HAVE_AIC3X)
+#include "aic3x.h"
 #elif defined(HAVE_CS42L55)
 #include "cs42l55.h"
 #elif defined(HAVE_IMX233_CODEC)
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 55a1948..2e7b4dc 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -142,6 +142,7 @@
 #define RK27XX_GENERIC_PAD 49
 #define HM60X_PAD          50
 #define HM801_PAD          51
+#define SANSA_CONNECT_PAD  52
 
 /* CONFIG_REMOTE_KEYPAD */
 #define H100_REMOTE   1
@@ -229,6 +230,7 @@
 #define LCD_SPFD5420A 42 /* rk27xx */
 #define LCD_CLIPZIP   43 /* as used by the Sandisk Sansa Clip Zip */
 #define LCD_HX8340B   44 /* as used by the HiFiMAN HM-601/HM-602/HM-801 */
+#define LCD_CONNECT   45 /* as used by the Sandisk Sansa Connect */
 
 /* LCD_PIXELFORMAT */
 #define HORIZONTAL_PACKING 1
@@ -302,6 +304,7 @@
 #define RTC_D2       18 /* Either PCF50606 or PCF50635 */
 #define RTC_S35380A  19
 #define RTC_IMX233   20
+#define RTC_STM41T62 21 /* ST M41T62 */
 
 /* USB On-the-go */
 #define USBOTG_M66591   6591 /* M:Robe 500 */
@@ -314,6 +317,7 @@
 #define USBOTG_AS3525v2 3535 /* AMS AS3525v2 FIXME : same as S3C6400X */
 #define USBOTG_S3C6400X 6400 /* Samsung S3C6400X, also used in the S5L8701/S5L8702/S5L8720 */
 #define USBOTG_RK27XX   2700 /* Rockchip rk27xx */
+#define USBOTG_TNETV105 105  /* TI TNETV105 */
 
 /* Multiple cores */
 #define CPU 0
@@ -466,6 +470,8 @@
 #include "config/hifimanhm60x.h"
 #elif defined(HM801)
 #include "config/hifimanhm801.h"
+#elif defined(SANSA_CONNECT)
+#include "config/sansaconnect.h"
 #elif defined(SDLAPP)
 #include "config/sdlapp.h"
 #elif defined(ANDROID)
diff --git a/firmware/export/config/sansaconnect.h b/firmware/export/config/sansaconnect.h
new file mode 100644
index 0000000..714534d
--- /dev/null
+++ b/firmware/export/config/sansaconnect.h
@@ -0,0 +1,201 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/*
+ * This config file is for the Sansa Connect
+ */
+#define TARGET_TREE /* this target is using the target tree system */
+
+/* This is the absolute address on the bus set by OF bootloader */
+#define CONFIG_SDRAM_START 0x01000000
+
+#define SANSA_CONNECT 1
+#define MODEL_NAME   "Sandisk Sansa Connect"
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 81
+
+/* define this if you have a flash memory storage */
+#define HAVE_FLASH_STORAGE
+
+/* define this if you use an SD controller */
+#define CONFIG_STORAGE STORAGE_SD
+
+#define HAVE_MULTIDRIVE
+#define NUM_DRIVES 2
+#define HAVE_HOTSWAP
+#define HAVE_HOTSWAP_STORAGE_AS_MAIN
+
+/* 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 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 have access to the pitchscreen */
+#define HAVE_PITCHSCREEN
+
+/* 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 this if you want viewport clipping enabled for safe LCD functions */
+#define HAVE_VIEWPORT_CLIP
+
+/* LCD dimensions */
+#define CONFIG_LCD LCD_CONNECT
+
+#define LCD_WIDTH  240
+#define LCD_HEIGHT 320
+
+#define LCD_DEPTH  16   /* 65k colours */
+#define LCD_PIXELFORMAT RGB565 /* rgb565 */
+
+#define HAVE_LCD_ENABLE
+#ifndef BOOTLOADER
+#define HAVE_LCD_SLEEP
+#endif
+
+#define LCD_SLEEP_TIMEOUT (2*HZ)
+
+#define MAX_ICON_HEIGHT 35
+#define MAX_ICON_WIDTH 35
+
+
+#define CONFIG_KEYPAD SANSA_CONNECT_PAD
+
+/* Define this to have CPU bootsted while scrolling in the UI */
+#define HAVE_GUI_BOOST
+
+/* define this if the target has volume keys which can be used in the lists */
+#define HAVE_VOLUME_IN_LIST
+
+#define HAVE_MORSE_INPUT
+
+/* Define this if you do software codec */
+#define CONFIG_CODEC SWCODEC
+
+//#define HAVE_HARDWARE_BEEP
+
+/* There is no hardware tone control */
+#define HAVE_SW_TONE_CONTROLS
+
+#define HAVE_AIC3X
+
+//#define HW_SAMPR_CAPS SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11 | SAMPR_CAP_8
+
+/* define this if you have a real-time clock */
+//#define CONFIG_RTC RTC_STM41T62
+
+/* define this if the unit uses a scrollwheel for navigation */
+#define HAVE_SCROLLWHEEL
+
+/* Define this for LCD backlight available */
+#define HAVE_BACKLIGHT
+
+#define HAVE_BACKLIGHT_BRIGHTNESS
+
+#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING
+
+/* Main LCD backlight brightness range and defaults */
+#define MIN_BRIGHTNESS_SETTING          1
+#define MAX_BRIGHTNESS_SETTING          20
+#define DEFAULT_BRIGHTNESS_SETTING      16 /* OF default brightness (80%) */
+#define DEFAULT_DIMNESS_SETTING         6  /* OF default inactive (30%) */
+
+/* Define this if you have a software controlled poweroff */
+#define HAVE_SW_POWEROFF
+
+/* The number of bytes reserved for loadable codecs */
+#define CODEC_SIZE 0x100000
+
+/* The number of bytes reserved for loadable plugins */
+#define PLUGIN_BUFFER_SIZE 0x200000
+
+#define BATTERY_CAPACITY_DEFAULT 800 /* default battery capacity */
+#define BATTERY_CAPACITY_MIN 700     /* min. capacity selectable */
+#define BATTERY_CAPACITY_MAX 1000    /* max. capacity selectable */
+#define BATTERY_CAPACITY_INC 100     /* capacity increment */
+#define BATTERY_TYPES_COUNT  1       /* only one type */
+
+/* define current usage levels */
+#if 0
+/* TODO */
+#define CURRENT_NORMAL     85
+#define CURRENT_BACKLIGHT  200
+#endif
+
+/* Hardware controlled charging with monitoring */
+//#define CONFIG_CHARGING CHARGING_MONITOR
+
+#define CONFIG_CPU DM320
+
+#define CONFIG_I2C I2C_DM320
+#define HAVE_SOFTWARE_I2C
+
+/* define this if the hardware can be powered off while charging */
+#define HAVE_POWEROFF_WHILE_CHARGING
+
+/* The size of the flash ROM */
+#define FLASH_SIZE 0x400000
+
+/* Define this to the CPU frequency */
+#define CPU_FREQ 150000000
+
+/* Define this if you have ATA power-off control */
+#define HAVE_ATA_POWER_OFF
+
+/* Offset ( in the firmware file's header ) to the file CRC */
+#define FIRMWARE_OFFSET_FILE_CRC 0
+
+/* Offset ( in the firmware file's header ) to the real data */
+#define FIRMWARE_OFFSET_FILE_DATA 8
+
+#if 0
+#define HAVE_USBSTACK
+#define USB_VENDOR_ID 0x0781
+#define USB_PRODUCT_ID 0x7480
+#endif
+
+#define INCLUDE_TIMEOUT_API
+
+/* Define this if you have adjustable CPU frequency */
+#define HAVE_ADJUSTABLE_CPU_FREQ
+
+#define BOOTFILE_EXT "sansa"
+#define BOOTFILE "rockbox." BOOTFILE_EXT
+#define BOOTDIR "/.rockbox"
+
+/* Define this if a programmable hotkey is mapped */
+#define HAVE_HOTKEY
diff --git a/firmware/export/dm320.h b/firmware/export/dm320.h
index a629586..def8508 100644
--- a/firmware/export/dm320.h
+++ b/firmware/export/dm320.h
@@ -870,6 +870,8 @@
 #define CLK_MOD2_TMR0                  (1 << 1)
 #define CLK_MOD2_WDT                   (1 << 0)
 
+#define CLK_SEL0_UART0                 (1 << 5)
+
 #define CLK_SEL1_OSD                   (1 << 12)
 #define CLK_SEL1_CCD                   (1 << 8)
 #define CLK_SEL1_VENCPLL               (1 << 4)
@@ -884,6 +886,55 @@
 #define CLK_BYP_DSP                    (1 << 4)
 #define CLK_BYP_ARM                    (1 << 0)
 
+#define CLK_INV_MMC                    (1 << 0)
+#define CLK_INV_VENC                   (1 << 4)
+#define CLK_INV_CCD                    (1 << 8)
+#define CLK_INV_SIF0                   (1 << 12)
+#define CLK_INV_SIF1                   (1 << 13)
+
+#define MMC_CTRL_DATRST                (1 << 0)
+#define MMC_CTRL_CMDRST                (1 << 1)
+#define MMC_CTRL_WIDTH                 (1 << 2)
+#define MMC_CTRL_DMASZEN               (1 << 4)
+#define MMC_CTRL_TEST2                 (1 << 8)
+#define MMC_CTRL_PERMDR                (1 << 9)
+#define MMC_CTRL_PERMDX                (1 << 10)
+
+#define MMC_CMD_CMD_MASK               (0x3F)
+#define MMC_CMD_PPLEN                  (1 << 7)
+#define MMC_CMD_BSYEXP                 (1 << 8)
+#define MMC_CMD_RSPFMT_SHIFT           9
+#define MMC_CMD_RSPFMT_MASK            (3 << MMC_CMD_RSPFMT_SHIFT)
+#define MMC_CMD_WRITE                  (1 << 11)
+#define MMC_CMD_STREAM                 (1 << 12)
+#define MMC_CMD_DATA                   (1 << 13)
+#define MMC_CMD_INITCLK                (1 << 14)
+#define MMC_CMD_DCLR                   (1 << 15)
+
+#define MMC_ST0_DATDNE                 (1 << 0)
+#define MMC_ST0_BSYDNE                 (1 << 1)
+#define MMC_ST0_RSPDNE                 (1 << 2)
+#define MMC_ST0_DATA_TIMEOUT           (1 << 3)
+#define MMC_ST0_CMD_TIMEOUT            (1 << 4)
+#define MMC_ST0_WR_CRCERR              (1 << 5)
+#define MMC_ST0_RD_CRCERR              (1 << 6)
+#define MMC_ST0_RESP_CRCERR            (1 << 7)
+#define MMC_ST0_DMADNE                 (1 << 8)
+#define MMC_ST0_DXRDY                  (1 << 9)
+#define MMC_ST0_DRRDY                  (1 << 10)
+#define MMC_ST0_DAT3_EDGE              (1 << 11)
+
+#define MMC_ST1_BUSY                   (1 << 0)
+#define MMC_ST1_CLKSTP                 (1 << 1)
+#define MMC_ST1_DXEMPTY                (1 << 2)
+#define MMC_ST1_DXFULL                 (1 << 3)
+#define MMC_ST1_DAT3ST                 (1 << 4)
+
+#define MMC_DMAMODE_RD_WORDSWAP        (1 << 10)
+#define MMC_DMAMODE_WR_WORDSWAP        (1 << 11)
+#define MMC_DMAMODE_WRITE              (1 << 12)
+#define MMC_DMAMODE_ENABLE             (1 << 13)
+#define MMC_DMAMODE_TIMEOUTIRQ_EN      (1 << 14)
 /*
  *  IO_EINTx bits
  */
diff --git a/firmware/sound.c b/firmware/sound.c
index ec577d6..c97ccc2 100644
--- a/firmware/sound.c
+++ b/firmware/sound.c
@@ -250,7 +250,7 @@
     audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
 #endif
 
-#elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985) || defined(HAVE_IMX233_CODEC)
+#elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985) || defined(HAVE_IMX233_CODEC) || defined(HAVE_AIC3X)
     audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
 #elif defined(HAVE_JZ4740_CODEC) || defined(HAVE_SDL_AUDIO) || defined(ANDROID)
     audiohw_set_volume(current_volume);
diff --git a/firmware/target/arm/tms320dm320/app.lds b/firmware/target/arm/tms320dm320/app.lds
index 1e0d183..4ea22a7 100644
--- a/firmware/target/arm/tms320dm320/app.lds
+++ b/firmware/target/arm/tms320dm320/app.lds
@@ -29,7 +29,7 @@
 
 #define DRAMSIZE (MEMORYSIZE * 0x100000)
 
-#define DRAMORIG        0x00900000
+#define DRAMORIG        CONFIG_SDRAM_START
 
 #define FLASHORIG       0x00100000
 #define FLASHSIZE       0x00800000
diff --git a/firmware/target/arm/tms320dm320/boot.lds b/firmware/target/arm/tms320dm320/boot.lds
index 2b9f345..65649d7 100644
--- a/firmware/target/arm/tms320dm320/boot.lds
+++ b/firmware/target/arm/tms320dm320/boot.lds
@@ -28,14 +28,27 @@
 #define LCD_TTB_AREA    0x100000*((LCD_BUFFER_SIZE>>19)+1)
 
 /* Bootloader only uses/knows about the upper 32 M */
-#define DRAMORIG    0x02900000
+#define DRAMORIG    CONFIG_SDRAM_START+0x02000000
 #define DRAMSIZE    (MEMORYSIZE * 0x80000)
 
 #define IRAMORIG    0x00000000
 #define IRAMSIZE    0x4000
 
+#ifdef SANSA_CONNECT
+/* Offset in flash from beginning, we don't want overwrite OF bootloader
+   due to recovery mode and more importantly - hardware block protection.
+   This offset makes Rockbox bootloader a replacement for OF vmlinux.
+   In .srr file header add any valid memory address from following
+   <0x1000000; 0x1300180) u (0x131EAF4; 0x1420000) u (0x1440000; 0x5000000>
+   ensuring that complete bootloader fits in.
+   Entry point in .srr file should be 0x120010. */
+#define FLASHOFFSET 0x20010
+#else
+#define FLASHOFFSET 0
+#endif
+
 #define FLASHORIG   0x00100000
-#define FLASHSIZE   0x00800000
+#define FLASHSIZE   0x00800000-FLASHOFFSET
 
 PRO_STACK_SIZE =  0x2000;
 IRQ_STACK_SIZE =  0x400;
@@ -48,7 +61,7 @@
 {
    DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE
    IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE
-   FLASH : ORIGIN = FLASHORIG, LENGTH = FLASHSIZE
+   FLASH : ORIGIN = FLASHORIG+FLASHOFFSET, LENGTH = FLASHSIZE
 }
 
 SECTIONS
diff --git a/firmware/target/arm/tms320dm320/debug-dm320.c b/firmware/target/arm/tms320dm320/debug-dm320.c
index de17d54..262d843 100644
--- a/firmware/target/arm/tms320dm320/debug-dm320.c
+++ b/firmware/target/arm/tms320dm320/debug-dm320.c
@@ -212,6 +212,7 @@
         button = button_get(false);
         if(button & BUTTON_POWER)
             done = true;
+#if defined(CREATIVE_ZVx)
         else if(button & BUTTON_LEFT)
             lcd_set_direct_fb(false);
         else if(button & BUTTON_RIGHT)
@@ -222,6 +223,7 @@
             (lcd_get_direct_fb() ? "yes" : "no"));
         line++;
 #endif
+#endif
         lcd_puts(0, line++, "[Rockbox info]");
         lcd_putsf(0, line++, "current tick: %08x Seconds running: %08d",
             (unsigned int)current_tick, (unsigned int)current_tick/100);
diff --git a/firmware/target/arm/tms320dm320/dma-dm320.c b/firmware/target/arm/tms320dm320/dma-dm320.c
new file mode 100644
index 0000000..e60102b
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/dma-dm320.c
@@ -0,0 +1,78 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "kernel.h"
+#include "thread.h"
+#include "system.h"
+#include "dma-target.h"
+#include "dm320.h"
+#include <stdbool.h>
+
+void dma_init(void)
+{
+    /* TODO */
+}
+
+/*
+   Requests channel for peripheral.
+   Returns channel assigned for caller which must be released after
+   transfer complete using dma_release_channel().
+*/
+int dma_request_channel(int peripheral, int mode)
+{
+    /* TODO: proper checking if channel is already taken
+       currently only SDMMC and DSP uses DMA on this target */
+    int channel = -1;
+
+    if (peripheral == DMA_PERIPHERAL_MMCSD)
+    {
+        /* Set first DMA channel */
+        IO_SDRAM_SDDMASEL = (IO_SDRAM_SDDMASEL & 0xFFE0) | peripheral | 
+                            (mode << 3);
+        channel = 1;
+    }
+    else if (peripheral == DMA_PERIPHERAL_DSP)
+    {
+        /* Set second DMA channel */
+        IO_SDRAM_SDDMASEL = (IO_SDRAM_SDDMASEL & 0xFC1F) | 
+                            (peripheral << 5) |
+                            (mode << 8);
+        channel = 2;
+    }
+    else if (peripheral == DMA_PERIPHERAL_SIF)
+    {
+        IO_SDRAM_SDDMASEL = (IO_SDRAM_SDDMASEL & 0x83FF) |
+                            (peripheral << 10) |
+                            (mode << 13);
+        channel = 3;
+    }
+
+    return channel;
+}
+
+void dma_release_channel(int channel)
+{
+    (void)channel;
+    /* TODO */
+}
+
+
diff --git a/firmware/target/arm/tms320dm320/dma-target.h b/firmware/target/arm/tms320dm320/dma-target.h
new file mode 100644
index 0000000..37053b3
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/dma-target.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 DMA_TARGET_H
+#define DMA_TARGET_H
+
+/* These defines match DMA Select bits */
+#define DMA_PERIPHERAL_MTC   0
+#define DMA_PERIPHERAL_SIF   1
+#define DMA_PERIPHERAL_MS    2
+#define DMA_PERIPHERAL_MMCSD 3
+#define DMA_PERIPHERAL_DSP   4
+
+/* These defines match DMA Burst bits */
+/* 1 burst DMA - address must be 4 byte aligned */
+#define DMA_MODE_1_BURST 0
+/* 4 burst DMA - address must be 16 byte aligned */
+#define DMA_MODE_4_BURST 1
+/* 8 burst DMA - address must be 32 byte aligned */
+#define DMA_MODE_8_BURST 2
+
+void dma_init(void);
+int dma_request_channel(int peripheral, int mode);
+void dma_release_channel(int channel);
+
+#endif
diff --git a/firmware/target/arm/tms320dm320/i2c-dm320.c b/firmware/target/arm/tms320dm320/i2c-dm320.c
index 8bcc84d..990dad0 100644
--- a/firmware/target/arm/tms320dm320/i2c-dm320.c
+++ b/firmware/target/arm/tms320dm320/i2c-dm320.c
@@ -7,6 +7,7 @@
  *                     \/            \/     \/    \/            \/
  * $Id$
  *
+ * Copyright (C) 2011 by Tomasz Moń
  * Copyright (C) 2008 by Maurus Cuelenaere
  *
  * DM320 I²C driver
@@ -24,11 +25,11 @@
 #include "thread.h"
 #include "i2c-dm320.h"
 
-#define I2C_SCS_COND_START  0x0001
-#define I2C_SCS_COND_STOP   0x0002
-#define I2C_SCS_XMIT        0x0004
+#ifdef HAVE_SOFTWARE_I2C
+#include "generic_i2c.h"
+#endif
 
-#define I2C_TX_ACK          (1 << 8)
+#ifndef HAVE_SOFTWARE_I2C
 
 static struct mutex i2c_mtx;
 
@@ -42,6 +43,12 @@
     mutex_unlock(&i2c_mtx);
 }
 
+#define I2C_SCS_COND_START  0x0001
+#define I2C_SCS_COND_STOP   0x0002
+#define I2C_SCS_XMIT        0x0004
+
+#define I2C_TX_ACK          (1 << 8)
+
 static inline bool i2c_getack(void)
 {
     return (IO_I2C_RXDATA >> 8) & 1;
@@ -158,3 +165,126 @@
     IO_I2C_SCS &= ~0x8; //set clock to 100 kHz
     IO_INTC_EINT2 &= ~INTR_EINT2_I2C; // disable I²C interrupt
 }
+
+#else /* Software I2C implementation */
+
+#ifdef SANSA_CONNECT
+    /* SDA - GIO35 */
+    #define SDA_SET_REG IO_GIO_BITSET2
+    #define SDA_CLR_REG IO_GIO_BITCLR2
+    #define SOFTI2C_SDA (1 << 3)
+    /* SCL - GIO36 */
+    #define SCL_SET_REG IO_GIO_BITSET2
+    #define SCL_CLR_REG IO_GIO_BITCLR2
+    #define SOFTI2C_SCL (1 << 4)
+#else
+    #error Configure SDA and SCL lines
+#endif
+
+static int dm320_i2c_bus;
+
+static void dm320_scl_dir(bool out)
+{
+    if (out)
+    {
+        IO_GIO_DIR2 &= ~(SOFTI2C_SCL);
+    }
+    else
+    {
+        IO_GIO_DIR2 |= SOFTI2C_SCL;
+    }
+}
+
+static void dm320_sda_dir(bool out)
+{
+    if (out)
+    {
+        IO_GIO_DIR2 &= ~(SOFTI2C_SDA);
+    }
+    else
+    {
+        IO_GIO_DIR2 |= SOFTI2C_SDA;
+    }
+}
+
+static void dm320_scl_out(bool high)
+{
+    if (high)
+    {
+        SCL_SET_REG = SOFTI2C_SCL;
+    }
+    else
+    {
+        SCL_CLR_REG = SOFTI2C_SCL;
+    }
+}
+
+static void dm320_sda_out(bool high)
+{
+    if (high)
+    {
+        SDA_SET_REG = SOFTI2C_SDA;
+    }
+    else
+    {
+        SDA_CLR_REG = SOFTI2C_SDA;
+    }
+}
+
+static bool dm320_scl_in(void)
+{
+    return (SCL_SET_REG & SOFTI2C_SCL);
+}
+
+static bool dm320_sda_in(void)
+{
+    return (SDA_SET_REG & SOFTI2C_SDA);
+}
+
+/* simple delay */
+static void dm320_i2c_delay(int delay)
+{
+    udelay(delay);
+}
+
+/* interface towards the generic i2c driver */
+static const struct i2c_interface dm320_i2c_interface = {
+    .scl_dir = dm320_scl_dir,
+    .sda_dir = dm320_sda_dir,
+    .scl_out = dm320_scl_out,
+    .sda_out = dm320_sda_out,
+    .scl_in = dm320_scl_in,
+    .sda_in = dm320_sda_in,
+    .delay = dm320_i2c_delay,
+
+    /* uncalibrated */
+    .delay_hd_sta = 1,
+    .delay_hd_dat = 1,
+    .delay_su_dat = 1,
+    .delay_su_sto = 1,
+    .delay_su_sta = 1,
+    .delay_thigh = 1
+};
+
+void i2c_init(void)
+{
+#ifdef SANSA_CONNECT
+    IO_GIO_FSEL3 &= 0xFF0F; /* GIO35, GIO36 as normal GIO */
+    IO_GIO_INV2 &= ~(SOFTI2C_SDA | SOFTI2C_SCL); /* not inverted */
+#endif
+
+    /* generic_i2c takes care of setting direction */
+    dm320_i2c_bus = i2c_add_node(&dm320_i2c_interface);
+}
+
+int i2c_write(unsigned short address, const unsigned char* buf, int count)
+{
+    return i2c_write_data(dm320_i2c_bus, address, -1, buf, count);
+}
+
+int i2c_read(unsigned short address, unsigned char* buf, int count)
+{
+    return i2c_read_data(dm320_i2c_bus, address, -1, buf, count);
+}
+
+#endif
diff --git a/firmware/target/arm/tms320dm320/kernel-dm320.c b/firmware/target/arm/tms320dm320/kernel-dm320.c
index 08c5043..79206c3 100644
--- a/firmware/target/arm/tms320dm320/kernel-dm320.c
+++ b/firmware/target/arm/tms320dm320/kernel-dm320.c
@@ -37,7 +37,7 @@
 
     /* Setup the Divisor */
     IO_TIMER1_TMDIV = (TIMER_FREQ / (10*1000))*interval_in_ms - 1;
-    
+
     /* Turn Timer1 to Free Run mode */
     IO_TIMER1_TMMD = CONFIG_TIMER1_TMMD_FREE_RUN;
     
@@ -45,6 +45,13 @@
     bitset16(&IO_INTC_EINT0, INTR_EINT0_TMR1);
 }
 
+#ifdef BOOTLOADER
+void tick_stop(void)
+{
+    bitclr16(&IO_CLK_MOD2, CLK_MOD2_TMR1); /* disable TIMER1 clock */
+}
+#endif
+
 void TIMER1(void) __attribute__ ((section(".icode")));
 void TIMER1(void)
 {
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c
new file mode 100644
index 0000000..b3e427b
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c
@@ -0,0 +1,35 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "adc.h"
+#include "adc-target.h"
+#include "kernel.h"
+
+void adc_init(void)
+{
+}
+
+/* Called to get the recent ADC reading */
+inline unsigned short adc_read(int channel)
+{
+    return (short)channel;
+}
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/adc-target.h b/firmware/target/arm/tms320dm320/sansa-connect/adc-target.h
new file mode 100644
index 0000000..49244b4
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/adc-target.h
@@ -0,0 +1,25 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 _ADC_TARGET_H_
+#define _ADC_TARGET_H_
+
+#endif
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
new file mode 100644
index 0000000..3a6a748
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
@@ -0,0 +1,461 @@
+/***************************************************************************
+*             __________               __   ___.
+*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+*                     \/            \/     \/    \/            \/
+* $Id: $
+*
+* Copyright (C) 2011 by Tomasz Moń
+*
+* 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 "config.h"
+#include "system.h"
+#include "kernel.h"
+#include "logf.h"
+#include "avr-sansaconnect.h"
+#include "uart-target.h"
+#include "button.h"
+#include "backlight.h"
+#include "powermgmt.h"
+
+//#define BUTTON_DEBUG
+
+#ifdef BUTTON_DEBUG
+#include "lcd-target.h"
+#include "lcd.h"
+#include "font.h"
+#include "common.h"
+#endif
+
+#ifdef BUTTON_DEBUG
+#define dbgprintf DEBUGF
+#else
+#define dbgprintf(...)
+#endif
+
+#define CMD_SYNC        0xAA
+#define CMD_CLOSE       0xCC
+#define CMD_LCM_POWER   0xC9
+#define LCM_POWER_OFF   0x00
+#define LCM_POWER_ON    0x01
+#define LCM_POWER_SLEEP 0x02
+#define LCM_POWER_WAKE  0x03
+#define LCM_REPOWER_ON  0x04
+
+#define CMD_STATE       0xBB
+#define CMD_VER         0xBC
+#define CMD_WHEEL_EN    0xD0
+#define CMD_SET_INTCHRG 0xD1
+#define CMD_CODEC_RESET 0xD7
+#define CMD_FILL        0xFF
+
+#define CMD_SYS_CTRL 0xDA
+#define SYS_CTRL_POWEROFF 0x00
+
+/* protects spi avr commands from concurrent access */
+static struct mutex avr_mtx;
+
+/* buttons thread */
+#define BTN_INTERRUPT 1
+static int btn = 0;
+static bool hold_switch;
+#ifndef BOOTLOADER
+static long btn_stack[DEFAULT_STACK_SIZE/sizeof(long)];
+static const char btn_thread_name[] = "buttons";
+static struct event_queue btn_queue;
+#endif
+
+static inline unsigned short be2short(unsigned char* buf)
+{
+   return (unsigned short)((buf[0] << 8) | buf[1]);
+}
+
+#define BUTTON_DIRECT_MASK (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN | BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_NEXT | BUTTON_PREV)
+
+#ifndef BOOTLOADER
+static void handle_wheel(unsigned char wheel)
+{
+    static int key = 0;
+    static unsigned char velocity = 0;
+    static unsigned long wheel_delta = 1ul << 24;
+    static unsigned char wheel_prev = 0;
+    static long next_backlight_on = 0;
+    static int prev_key = -1;
+    static int prev_key_post = 0;
+
+    if (TIME_AFTER(current_tick, next_backlight_on))
+    {
+        backlight_on();
+        reset_poweroff_timer();
+        next_backlight_on = current_tick + HZ/4;
+    }
+
+    if (wheel_prev < wheel)
+    {
+        key = BUTTON_SCROLL_FWD;
+        velocity = wheel - wheel_prev;
+    }
+    else if (wheel_prev > wheel)
+    {
+        key = BUTTON_SCROLL_BACK;
+        velocity = wheel_prev - wheel;
+    }
+
+    if (prev_key != key && velocity < 2 /* filter "rewinds" */)
+    {
+        /* direction reversal */
+        prev_key = key;
+        wheel_delta = 1ul << 24;
+        return;
+    }
+
+    /* TODO: take velocity into account */
+    if (queue_empty(&button_queue))
+    {
+        if (prev_key_post == key)
+        {
+            key |= BUTTON_REPEAT;
+        }
+
+        /* Post directly, don't update btn as avr doesn't give
+           interrupt on scroll stop */
+        queue_post(&button_queue, key, wheel_delta);
+
+        wheel_delta = 1ul << 24;
+
+        prev_key_post = key;
+    }
+    else
+    {
+        /* skipped post - increment delta and limit to 7 bits */
+        wheel_delta += 1ul << 24;
+
+        if (wheel_delta > (0x7ful << 24))
+            wheel_delta = 0x7ful << 24;
+    }
+
+    wheel_prev = wheel;
+
+    prev_key = key;
+}
+#endif
+
+/* buf must be 11-byte array of byte (reply from avr_hid_get_state() */
+static void parse_button_state(unsigned char *buf)
+{
+    unsigned short main_btns_state = be2short(&buf[4]);
+#ifdef BUTTON_DEBUG
+    unsigned short main_btns_changed = be2short(&buf[6]);
+#endif
+
+    /* make sure other bits doesn't conflict with our "free bits" buttons */
+    main_btns_state &= BUTTON_DIRECT_MASK;
+
+    if (buf[3] & 0x01) /* is power button pressed? */
+    {
+        main_btns_state |= BUTTON_POWER;
+    }
+
+    btn = main_btns_state;
+
+#ifndef BOOTLOADER
+    /* check if stored hold_switch state changed (prevents lost changes) */
+    if ((buf[3] & 0x20) /* hold change notification */ ||
+        (hold_switch != ((buf[3] & 0x02) >> 1)))
+    {
+#endif
+        hold_switch = (buf[3] & 0x02) >> 1;
+#ifdef BUTTON_DEBUG
+        dbgprintf("HOLD changed (%d)", hold_switch);
+#endif
+#ifndef BOOTLOADER
+        backlight_hold_changed(hold_switch);
+    }
+#endif
+#ifndef BOOTLOADER
+    if ((hold_switch == false) && (buf[3] & 0x80)) /* scrollwheel change */
+    {
+        handle_wheel(buf[2]);
+    }
+#endif
+
+#ifdef BUTTON_DEBUG
+    if (buf[3] & 0x10) /* power button change */
+    {
+        /* power button state has changed */
+        main_btns_changed |= BUTTON_POWER;
+    }
+
+    if (btn & BUTTON_LEFT)        dbgprintf("LEFT");
+    if (btn & BUTTON_UP)          dbgprintf("UP");
+    if (btn & BUTTON_RIGHT)       dbgprintf("RIGHT");
+    if (btn & BUTTON_DOWN)        dbgprintf("DOWN");
+    if (btn & BUTTON_SELECT)      dbgprintf("SELECT");
+    if (btn & BUTTON_VOL_UP)      dbgprintf("VOL UP");
+    if (btn & BUTTON_VOL_DOWN)    dbgprintf("VOL DOWN");
+    if (btn & BUTTON_NEXT)        dbgprintf("NEXT");
+    if (btn & BUTTON_PREV)        dbgprintf("PREV");
+    if (btn & BUTTON_POWER)       dbgprintf("POWER");
+    if (btn & BUTTON_HOLD)        dbgprintf("HOLD");
+    if (btn & BUTTON_SCROLL_FWD)  dbgprintf("SCROLL FWD");
+    if (btn & BUTTON_SCROLL_BACK) dbgprintf("SCROLL BACK");
+#endif
+}
+
+/* HID Slave Select - GIO14 */
+#define HID_SS (1<<14)
+
+static inline void select_hid(bool on)
+{
+    if (on == true)
+    {
+        /* SS is active low */
+        IO_GIO_BITCLR0 = HID_SS;
+    }
+    else
+    {
+        IO_GIO_BITSET0 = HID_SS;
+    }
+}
+
+static void spi_txrx(unsigned char *buf_tx, unsigned char *buf_rx, int n)
+{
+    int i;
+    unsigned short rxdata;
+
+    mutex_lock(&avr_mtx);
+
+    bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF1);
+    IO_SERIAL1_TX_ENABLE = 0x0001;
+    select_hid(true);
+
+    for (i = 0; i<n; i++)
+    {
+        IO_SERIAL1_TX_DATA = buf_tx[i];
+        udelay(100);
+
+        do
+        {
+            rxdata = IO_SERIAL1_RX_DATA;
+        } while (rxdata & (1<<8));
+
+        if (buf_rx != NULL)
+            buf_rx[i] = rxdata & 0xFF;
+
+        //udelay(100);
+    }
+
+    select_hid(false);
+    IO_SERIAL1_TX_ENABLE = 0;
+    bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF1);
+
+    mutex_unlock(&avr_mtx);
+}
+
+static void avr_hid_sync(void)
+{
+    int i;
+    unsigned char prg[4] = {CMD_SYNC, CMD_VER, CMD_FILL, CMD_CLOSE};
+
+    /* Send SYNC three times */
+    for (i = 0; i<3; i++)
+    {
+        spi_txrx(prg, NULL, sizeof(prg));
+    }
+}
+
+void avr_hid_init(void)
+{
+    /*
+       setup alternate GIO functions:
+       GIO29 - SIF1 Enable
+       GIO30 - SIF1 Clock
+       GIO31 - SIF1 Data In
+       GIO32 - SIF1 Data Out
+    */
+    IO_GIO_FSEL2 = (IO_GIO_FSEL2 & 0x00FF) | 0xAA00;
+
+    bitclr16(&IO_GIO_DIR0, HID_SS); /* set GIO14 as output */ 
+
+    /* RATE = 219 (0xDB) -> 200 kHz */
+    IO_SERIAL1_MODE = 0x6DB;
+
+    mutex_init(&avr_mtx);
+
+    avr_hid_sync();
+}
+
+
+static void avr_hid_get_state(void)
+{
+    static unsigned char cmd[11] = {CMD_SYNC, CMD_STATE,
+      CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL,
+      CMD_CLOSE};
+
+    static unsigned char buf[11];
+    static unsigned char cmd_empty[1] = {0xCC};
+
+    spi_txrx(cmd, buf, sizeof(cmd));
+
+    spi_txrx(cmd_empty, NULL, 1); /* request interrupt on button press */
+
+    parse_button_state(buf);
+}
+
+static void avr_hid_enable_wheel(void)
+{
+    unsigned char wheel_en[4] = {CMD_SYNC, CMD_WHEEL_EN, 0x01, CMD_CLOSE};
+
+    spi_txrx(wheel_en, NULL, sizeof(wheel_en));
+}
+
+/* command that is sent by "hidtool -J 1" issued on every OF boot */
+void avr_hid_enable_charger(void)
+{
+    unsigned char charger_en[4] = {CMD_SYNC, CMD_SET_INTCHRG, 0x01, CMD_CLOSE};
+
+    spi_txrx(charger_en, NULL, sizeof(charger_en));
+}
+
+void avr_hid_lcm_sleep(void)
+{
+    unsigned char lcm_sleep[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_SLEEP, CMD_CLOSE};
+
+    spi_txrx(lcm_sleep, NULL, sizeof(lcm_sleep));
+}
+
+
+void avr_hid_lcm_wake(void)
+{
+    unsigned char lcm_wake[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_WAKE, CMD_CLOSE};
+
+    spi_txrx(lcm_wake, NULL, sizeof(lcm_wake));
+}
+
+void avr_hid_lcm_power_on(void)
+{
+    unsigned char lcm_power_on[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_ON, CMD_CLOSE};
+
+    spi_txrx(lcm_power_on, NULL, sizeof(lcm_power_on));
+}
+
+void avr_hid_lcm_power_off(void)
+{
+    unsigned char lcm_power_off[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_OFF, CMD_CLOSE};
+
+    spi_txrx(lcm_power_off, NULL, sizeof(lcm_power_off));
+}
+
+void avr_hid_reset_codec(void)
+{
+    unsigned char codec_reset[4] = {CMD_SYNC, CMD_CODEC_RESET, CMD_CLOSE, CMD_FILL};
+
+    spi_txrx(codec_reset, NULL, sizeof(codec_reset));
+}
+
+void avr_hid_power_off(void)
+{
+    unsigned char prg[4] = {CMD_SYNC, CMD_SYS_CTRL, SYS_CTRL_POWEROFF, CMD_CLOSE};
+
+    spi_txrx(prg, NULL, sizeof(prg));
+}
+
+#ifndef BOOTLOADER
+void btn_thread(void)
+{
+    struct queue_event ev;
+
+    while (1)
+    {
+        queue_wait(&btn_queue, &ev);
+        
+        /* Ignore all messages except BTN_INTERRUPT */
+        if (ev.id != BTN_INTERRUPT)
+            continue;
+
+        /* Enable back button interrupt */
+        IO_INTC_EINT1 |= INTR_EINT1_EXT0;
+
+        /* Read buttons state */
+        avr_hid_get_state();
+
+        yield();
+
+        if (queue_empty(&btn_queue) && ((IO_GIO_BITSET0 & 0x1) == 0))
+        {
+            /* for some reason we have lost next interrupt */
+            queue_post(&btn_queue, BTN_INTERRUPT, 0);
+        }
+    }
+}
+
+void GIO0(void) __attribute__ ((section(".icode")));
+void GIO0(void)
+{
+    /* Clear interrupt */
+    IO_INTC_IRQ1 = (1 << 5);
+    /* Disable interrupt */
+    IO_INTC_EINT1 &= ~INTR_EINT1_EXT0;
+
+    /* interrupt will be enabled back after button read */
+    queue_post(&btn_queue, BTN_INTERRUPT, 0);
+}
+#endif
+
+void button_init_device(void)
+{
+    btn = 0;
+    hold_switch = false;
+#ifndef BOOTLOADER
+    queue_init(&btn_queue, true);
+    create_thread(btn_thread, btn_stack, sizeof(btn_stack), 0,
+                  btn_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE)
+                  IF_COP(, CPU));
+#endif
+    IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */
+
+    /* Enable wheel */
+    avr_hid_enable_wheel();
+    /* Read button status and tell avr we want interrupt on next change */
+    avr_hid_get_state();
+
+#ifndef BOOTLOADER
+    IO_GIO_IRQPORT |= 0x01; /* Enable GIO0 external interrupt */
+    IO_GIO_INV0 &= ~0x01; /* Clear INV for GIO0 (falling edge detection) */
+    IO_GIO_IRQEDGE &= ~0x01; /* Set edge detection (falling) */
+
+    /* Enable GIO0 interrupt */
+    IO_INTC_EINT1 |= INTR_EINT1_EXT0;
+#endif
+}
+
+int button_read_device(void)
+{
+    if(hold_switch)
+        return 0;
+    else
+        return btn;
+}
+
+bool button_hold(void)
+{
+    return hold_switch;
+}
+
+void lcd_enable(bool on)
+{
+    (void)on;
+}
+
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
new file mode 100644
index 0000000..64b4467
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+*             __________               __   ___.
+*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+*                     \/            \/     \/    \/            \/
+* $Id: $
+*
+* Copyright (C) 2011 by Tomasz Moń
+*
+* 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 _AVR_SANSACONNECT_H_
+#define _AVR_SANSACONNECT_H_
+
+#include "config.h"
+
+void avr_hid_init(void);
+
+void avr_hid_enable_charger(void);
+
+void avr_hid_lcm_sleep(void);
+void avr_hid_lcm_wake(void);
+void avr_hid_lcm_power_on(void);
+void avr_hid_lcm_power_off(void);
+void avr_hid_reset_codec(void);
+void avr_hid_power_off(void);
+
+#endif /* _AVR_SANSACONNECT_H_ */
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c
new file mode 100644
index 0000000..b798984
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "cpu.h"
+#include "system.h"
+#include "backlight-target.h"
+#include "backlight.h"
+#include "lcd.h"
+#include "power.h"
+#include "spi-target.h"
+#include "lcd-target.h"
+
+static void _backlight_write_brightness(int brightness)
+{
+    /*
+       Maps brightness int to percentage value found in OF
+
+       OF   PWM1H
+       5%   14
+       10%  140
+       15%  210
+       20%  280
+       ...
+       95%  1330
+       100% 1400
+    */
+    if (brightness > 20)
+        brightness = 20;
+    else if (brightness < 0)
+        brightness = 0;
+
+    IO_CLK_PWM1H = brightness*70;
+}
+
+void _backlight_on(void)
+{
+    /* set GIO34 as PWM1 */
+    IO_GIO_FSEL3 = (IO_GIO_FSEL3 & 0xFFF3) | (1 << 2);
+
+#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_NO_FADING)
+    _backlight_write_brightness(backlight_brightness);
+#endif
+}
+
+void _backlight_off(void)
+{
+    _backlight_write_brightness(0);
+
+    bitclr16(&IO_GIO_FSEL3, 0xC); /* set GIO34 to normal GIO */
+    bitclr16(&IO_GIO_INV2, (1 << 2)); /* make sure GIO34 is not inverted */
+    IO_GIO_BITCLR2 = (1 << 2); /* drive GIO34 low */
+}
+
+/* Assumes that the backlight has been initialized */
+void _backlight_set_brightness(int brightness)
+{
+    _backlight_write_brightness(brightness);
+}
+
+void __backlight_dim(bool dim_now)
+{
+    _backlight_set_brightness(dim_now ?
+        DEFAULT_BRIGHTNESS_SETTING :
+        DEFAULT_DIMNESS_SETTING);
+}
+
+bool _backlight_init(void)
+{
+    IO_CLK_PWM1C = 0x58D; /* as found in OF */
+
+    _backlight_set_brightness(backlight_brightness);
+    return true;
+}
+
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h b/firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h
new file mode 100644
index 0000000..89bd837
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 BACKLIGHT_TARGET_H
+#define BACKLIGHT_TARGET_H
+
+bool _backlight_init(void);
+void _backlight_on(void);
+void _backlight_off(void);
+void _backlight_set_brightness(int brightness);
+
+/* true: backlight fades off - false: backlight fades on */
+void __backlight_dim(bool dim);
+
+#endif
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/button-target.h b/firmware/target/arm/tms320dm320/sansa-connect/button-target.h
new file mode 100644
index 0000000..2eb571a
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/button-target.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+*             __________               __   ___.
+*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+*                     \/            \/     \/    \/            \/
+* $Id: $
+*
+* Copyright (C) 2011 by Tomasz Moń
+*
+* 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 "config.h"
+
+#define BUTTON_REMOTE 0
+
+/* these definitions match the avr hid reply */
+#define BUTTON_LEFT     (1 << 2)
+#define BUTTON_UP       (1 << 3)
+#define BUTTON_RIGHT    (1 << 4)
+#define BUTTON_DOWN     (1 << 5)
+#define BUTTON_SELECT   (1 << 6)
+#define BUTTON_VOL_UP   (1 << 10)
+#define BUTTON_VOL_DOWN (1 << 11)
+#define BUTTON_NEXT     (1 << 13)
+#define BUTTON_PREV     (1 << 14)
+
+/* following definitions use "free bits" from avr hid reply */
+#define BUTTON_POWER       (1 << 0)
+#define BUTTON_HOLD        (1 << 1)
+#define BUTTON_SCROLL_FWD  (1 << 7)
+#define BUTTON_SCROLL_BACK (1 << 8)
+
+
+#define BUTTON_REMOTE       0
+#define BUTTON_MAIN (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN |\
+                     BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN |\
+                     BUTTON_NEXT | BUTTON_PREV | BUTTON_POWER |\
+                     BUTTON_SCROLL_FWD | BUTTON_SCROLL_BACK)
+
+#define POWEROFF_BUTTON     BUTTON_POWER
+#define POWEROFF_COUNT      5
+
+#define HAS_BUTTON_HOLD
+
+void button_init_device(void);
+int button_read_device(void);
+bool button_hold(void);
+
+int get_debug_info(int choice);
+
+#endif /* _BUTTON_TARGET_H_ */
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S b/firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S
new file mode 100644
index 0000000..debd2cd
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S
@@ -0,0 +1,238 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "cpu.h"
+
+/* Macro for reading a register */
+.macro mrh  register
+    ldr     r1, =\register
+    ldrh    r0, [r1]
+.endm
+
+/* Macro for writing a register */
+.macro mwh  register, value
+    ldr     r0, =\value
+    ldr     r1, =\register
+    strh    r0, [r1]
+.endm
+
+/* This version uses a mov to save on the literal pool size. Otherwise it is
+ *  functionally equivalent.
+ */
+.macro mwhm register, value
+    mov     r0, #\value
+    ldr     r1, =\register
+    strh    r0, [r1]
+.endm
+
+ /*
+  * _init_board:
+  *    This function initializes the specific board this SoC is on.
+  */
+.section    .init, "ax"
+.code       32
+.align      0x04
+.global     _init_board
+.type       _init_board, %function
+
+_init_board:
+
+    /* Setup the EMIF interface timings */
+
+    /* FLASH interface:
+     * These are based on the OF setup 
+     */
+    /* IO_EMIF_CS0CTRL1 and
+     * IO_EMIF_CS0CTRL2 
+     */
+    mwh     0x30A00, 0x889A
+    mwh     0x30A02, 0x1110
+
+    mwhm    0x30A04, 0
+    mwh     0x30A06, 0x1415
+    mwh     0x30A08, 0x1109
+
+    mwh     0x30A0A, 0x1220
+    mwh     0x30A0C, 0x1104
+    mwh     0x30A0E, 0x0222
+
+    /* IO_EMIF_CS3CTRL1 and
+     * IO_EMIF_CS3CTRL2 
+     */
+    mwh     0x30A10, 0x8899
+    mwh     0x30A12, 0x5110
+
+   /* USB interface */
+    /* IO_EMIF_CS4CTRL1 and
+     * IO_EMIF_CS4CTRL2
+     */
+    mwh     0x30A14, 0x77DF
+    mwh     0x30A16, 0x7740
+
+    /* IO_EMIF_BUSCTRL */
+    mwhm    0x30A18, 0
+    mwhm    0x30A1A, 0
+    mwhm    0x30A1C, 0
+    mwhm    0x30A1E, 0
+
+_clock_setup:
+    /* Clock initialization */
+
+    /* IO_CLK_BYP: Bypass the PLLs for the following changes */
+    mwh 0x30894, 0x1111
+
+    /*
+     *  IO_CLK_PLLA
+     *  IO_CLK_PLLB
+     */
+    mwhm 0x30880, 0x00A0
+    mwhm 0x30882, 0x1000
+
+    /* IO_CLK_SEL0 */
+    mwh 0x30884, 0x0066
+
+    /* IO_CLK_SEL1 */
+    mwhm 0x30886, 0x0003
+
+    # IO_CLK_SEL2: ARM, AXL, SDRAM and DSP are from PLLA */
+    mwh 0x30888, 0
+
+    /* IO_CLK_DIV0: Set the slow clock speed for the ARM/AHB */
+    mwh 0x3088A, 0x0101
+
+    /* IO_CLK_DIV1: Accelerator, SDRAM */
+    mwh 0x3088C, 0x0102
+
+    /* IO_CLK_DIV2: DSP, MS Clock */
+    mwhm 0x3088E, 0x0200
+
+    # PLLA &= ~0x1000 (BIC #0x1000)
+    mrh     0x30880
+    bic     r0, r0, #0x1000
+    strh    r0, [r1]
+
+    /* Wait for PLLs to lock before feeding them to the downstream devices */
+_plla_wait:
+    mrh     0x30880
+    bic     r0, r0, #0x7F
+    tst     r0, r0
+    beq     _plla_wait
+
+    /* IO_CLK_BYP: Enable PLL feeds  */
+    mwhm 0x30894, 0x0
+
+    /* IO_CLK_MOD0 */
+    mwh 0x30898, 0x01A7
+
+    /* IO_CLK_MOD1 */
+    mwhm 0x3089A, 0x18
+
+    /* IO_CLK_MOD2 */
+    mwhm 0x3089C, 0x4A0
+
+    /* Setup the SDRAM range on the AHB bus */
+    /* SDRAMSA */
+    mov    r0, #0x60000
+    mov    r1, #0x1000000
+    str    r1, [r0, #0xF00]
+    
+    /* SDRAMEA: 64MB */
+    mov    r1, #0x5000000
+    str    r1, [r0, #0xF04]
+    
+    /* SDRC_REFCTL */
+    mwh    0x309A8, 0
+
+    ldr    r0, =0x309A6
+    mov    r2, #0x1380
+    orr    r1, r2, #2
+    strh   r1, [r0]
+    orr    r1, r2, #4
+    strh   r1, [r0]
+    strh   r1, [r0]
+    strh   r1, [r0]
+    strh   r1, [r0]
+    strh   r1, [r0]
+    strh   r1, [r0]
+    strh   r1, [r0]
+    strh   r1, [r0]
+    orr    r1, r2, #1
+    strh   r1, [r0]
+    strh   r2, [r0]
+    strh   r2, [r0]
+
+    mwhm   0x309A8, 0x0140
+
+    mwhm   0x309BE, 0x4
+    mwhm   0x309BC, 0x2
+    ldr    r0, =0x309C4
+    ldr    r1, [r0]
+    orr    r1, r1, #1
+    strh   r1, [r0]
+
+    ldr    r0, =0x309A6
+    mov    r1, #0x1380
+    strh   r1, [r0]
+    bic    r1, r1, #0x80
+    strh   r1, [r0]
+    orr    r1, r1, #0x40
+    strh   r1, [r0]
+
+    mwhm   0x309A8, 0x0140
+
+    /* Go through the GPIO initialization */
+    /* Warning: setting some of the functions wrong will make OF unable 
+       to boot (freeze during startup) */
+    /* IO_GIO_FSEL0: Set up the GPIO pin functions 0-16 */
+    mwhm   0x305A4, 0xC000
+
+    /* IO_GIO_FSEL1: 17-24 */
+    mwh    0x305A6, 0xAAAA
+
+    /* IO_GIO_FSEL2: 18-32 */
+    mwh    0x305A8, 0xA80A
+
+    /* IO_GIO_FSEL3: 33-40 */
+    mwh    0x305AA, 0x1007
+
+    /* IO_GIO_DIR0 */
+    mwh    0x30580, 0xFF77
+
+    /* IO_GIO_DIR1 */
+    mwh     0x30582, 0xEFFE
+
+    /* IO_GIO_DIR2 */
+    mwh     0x30584, 0x01FD
+    
+    /* IO_GIO_INV0 */
+    mwh     0x30586, 0x0000
+
+    /* IO_GIO_INV1 */
+    mwh     0x30588, 0x0000
+
+    /* IO_GIO_INV2 */
+    mwh     0x3058A, 0x0000
+
+    bx     lr
+
+.ltorg  
+.size       _init_board, .-_init_board
+
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c
new file mode 100644
index 0000000..fcfc82e
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c
@@ -0,0 +1,273 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 <sys/types.h>
+#include "config.h"
+#include "cpu.h"
+#include "string.h"
+#include "kernel.h"
+#include "system.h"
+#include "system-target.h"
+#include "lcd.h"
+#include "lcd-target.h"
+#include "avr-sansaconnect.h"
+
+/* Copies a rectangle from one framebuffer to another. Can be used in
+   single transfer mode with width = num pixels, and height = 1 which
+   allows a full-width rectangle to be copied more efficiently. */
+extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src,
+                                 int width, int height);
+
+static bool lcd_on = true;
+
+bool lcd_active(void)
+{
+    return lcd_on;
+}
+
+#if defined(HAVE_LCD_SLEEP)
+void lcd_sleep(void)
+{
+    if (lcd_on)
+    {
+        lcd_on = false;
+        avr_hid_lcm_sleep();
+        sleep(HZ/20);
+
+        /* disable video encoder */
+        bitclr16(&IO_VID_ENC_VMOD, 0x01);
+
+        sleep(HZ/20);
+
+        /* disable video encoder clock */
+        bitclr16(&IO_CLK_MOD1, CLK_MOD1_VENC);
+    }
+}
+
+void lcd_awake(void)
+{
+    if (!lcd_on)
+    {
+        lcd_on = true;
+        /* enable video encoder clock */
+        bitset16(&IO_CLK_MOD1, CLK_MOD1_VENC); 
+
+        /* enable video encoder */
+        bitset16(&IO_VID_ENC_VMOD, 0x01);
+
+        avr_hid_lcm_wake();
+
+        send_event(LCD_EVENT_ACTIVATION, NULL);
+
+        lcd_update();
+    }
+}
+#endif
+
+void lcd_init_device(void)
+{
+    unsigned int addr;
+ 
+    /* Disable Video Encoder clock */
+    bitclr16(&IO_CLK_MOD1, CLK_MOD1_VENC);
+
+    /* configure GIO39, GIO34 and GIO33 as outputs */
+    IO_GIO_DIR2 &= ~((1 << 7) /* GIO39 */ | (1 << 2) /* GIO34 */ |
+                     (1 << 1) /* GIO33 */);
+    
+    IO_GIO_FSEL3 = (IO_GIO_FSEL3 & ~(0x300F)) |
+                   (0x1000) /* GIO39 - FIELD_VENC */ |
+                   (0x3)    /* GIO33 - CLKOUT1B (bootloader does this) */ |
+                   (0x4);   /* GIO34 - PWM1 (brightness control) */
+
+    /* OSD Clock = VENC Clock /2,
+       CCD clock PCLK,
+       VENC Clock from PLLA */
+    IO_CLK_SEL1 = 0x3;
+
+    /* Set VENC Clock Division to 11
+       OF bootloader sets division to 8, vmlinux sets it to 11 */
+    IO_CLK_DIV3 = (IO_CLK_DIV3 & ~(0x1F00)) | 0xB00;
+
+    /* Enable DAC and OSD clocks */
+    bitset16(&IO_CLK_MOD1, CLK_MOD1_DAC | CLK_MOD1_OSD);
+
+    /* magic values based on OF bootloader initialization */
+    IO_VID_ENC_VMOD = 0x2010;
+    IO_VID_ENC_VDPRO = 0x80;
+    IO_VID_ENC_HSPLS = 0x4;
+    IO_VID_ENC_HINT = 0x4B0;
+    IO_VID_ENC_HSTART = 0x88;
+    IO_VID_ENC_HVALID = 0x3C0;
+    IO_VID_ENC_HSDLY = 0;
+    IO_VID_ENC_VSPLS = 0x2;
+    IO_VID_ENC_VINT = 0x152;
+    IO_VID_ENC_VSTART = 0x6;
+    IO_VID_ENC_VVALID = 0x140;
+    IO_VID_ENC_VSDLY = 0;
+    IO_VID_ENC_DCLKCTL = 0x3;
+    IO_VID_ENC_DCLKPTN0 = 0xC;
+    IO_VID_ENC_VDCTL = 0x6000;
+    IO_VID_ENC_SYNCTL = 0x2;
+    IO_VID_ENC_LCDOUT = 0x101;
+    IO_VID_ENC_VMOD = 0x2011;
+
+    /* Copy Rockbox frame buffer to the second framebuffer */
+    lcd_update();
+
+    avr_hid_lcm_power_on();
+
+    /* set framebuffer address - OF sets RAM start address to 0x1000000 */
+    addr = ((int)FRAME-CONFIG_SDRAM_START)/32;
+
+    IO_OSD_OSDWINADH    = addr >> 16;
+    IO_OSD_OSDWIN0ADL   = addr & 0xFFFF;
+
+    IO_OSD_BASEPX = 0x44;
+    IO_OSD_BASEPY = 0x6;
+    IO_OSD_OSDWIN0XP = 0;
+    IO_OSD_OSDWIN0YP = 0;
+    IO_OSD_OSDWIN0XL = LCD_WIDTH*2;  /* OF bootloader sets 480 */
+    IO_OSD_OSDWIN0YL = LCD_HEIGHT;   /* OF bootloader sets 320 */
+    IO_OSD_OSDWIN0OFST = 0xF;
+    IO_OSD_OSDWINMD0 = 0x25FB;/* OF bootloader sets 25C3,
+                                 vmlinux changes this to 0x25FB */
+    IO_OSD_VIDWINMD = 0; /* disable video windows (OF sets 0x03) */
+
+    IO_OSD_OSDWINMD1 = 0; /* disable OSD window 1 */
+
+    /* Enable DAC, Video Encoder and OSD clocks */
+    bitset16(&IO_CLK_MOD1, CLK_MOD1_DAC | CLK_MOD1_VENC | CLK_MOD1_OSD);
+
+    /* Enable Video Encoder - RGB666, custom timing */
+    IO_VID_ENC_VMOD = 0x2011;
+    avr_hid_lcm_wake();
+}
+
+/* Update a fraction of the display. */
+void lcd_update_rect(int x, int y, int width, int height)
+        __attribute__ ((section(".icode")));
+void lcd_update_rect(int x, int y, int width, int height)
+{
+    register fb_data *dst, *src;
+
+    if (!lcd_on)
+        return;
+
+    if ((width | height) < 0)
+        return; /* Nothing left to do */
+
+    if (x + width > LCD_WIDTH)
+        width = LCD_WIDTH - x; /* Clip right */
+    if (x < 0)
+        width += x, x = 0; /* Clip left */
+
+    if (y + height > LCD_HEIGHT)
+        height = LCD_HEIGHT - y; /* Clip bottom */
+    if (y < 0)
+        height += y, y = 0; /* Clip top */
+
+    dst = FRAME + LCD_WIDTH*y + x;
+    src = &lcd_framebuffer[y][x];
+
+    /* 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);
+    }
+}
+
+/* Update the display.
+   This must be called after all other LCD functions that change the display. */
+void lcd_update(void) __attribute__ ((section(".icode")));
+void lcd_update(void)
+{
+    if (!lcd_on)
+        return;
+
+    lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
+}
+
+void lcd_set_contrast(int val) {
+  (void) val;
+  // TODO:
+}
+
+void lcd_set_invert_display(bool yesno) {
+  (void) yesno;
+  // TODO:
+}
+
+void lcd_set_flip(bool yesno) {
+  (void) yesno;
+  // TODO:
+}
+
+/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
+extern void lcd_write_yuv420_lines(fb_data *dst,
+                                   unsigned char chroma_buf[LCD_HEIGHT/2*3],
+                                   unsigned char const * const src[3],
+                                   int width, int stride);
+
+/* Performance function to blit a YUV bitmap directly to the LCD */
+void lcd_blit_yuv(unsigned char * const src[3],
+                  int src_x, int src_y, int stride,
+                  int x, int y, int width, int height)
+{
+    /* Caches for chroma data so it only need be recalculated every other
+       line */
+    unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 480 bytes */
+    unsigned char const * yuv_src[3];
+    off_t z;
+
+    if (!lcd_on)
+        return;
+
+    /* Sorry, but width and height must be >= 2 or else */
+    width &= ~1;
+    height >>= 1;
+
+    fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + (LCD_WIDTH - y) - 1;
+
+    z = stride*src_y;
+    yuv_src[0] = src[0] + z + src_x;
+    yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
+    yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
+
+    do
+    {
+        lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width,
+        stride);
+
+        yuv_src[0] += stride << 1; /* Skip down two luma lines */
+        yuv_src[1] += stride >> 1; /* Skip down one chroma line */
+        yuv_src[2] += stride >> 1;
+        dst -= 2;
+    }
+    while (--height > 0);
+}
+
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h b/firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h
new file mode 100644
index 0000000..0c1ad0d
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h
@@ -0,0 +1,25 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 _LCD_TARGET_H_
+#define _LCD_TARGET_H_
+
+#endif
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
new file mode 100644
index 0000000..3f04838
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
@@ -0,0 +1,207 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "system.h"
+#include "kernel.h"
+#include "logf.h"
+#include "audio.h"
+#include "sound.h"
+#include "file.h"
+#include "dsp-target.h"
+#include "dsp/ipc.h"
+#include "mmu-arm.h"
+#include "pcm-internal.h"
+#include "dma-target.h"
+
+/* This is global to save some latency when pcm_play_dma_get_peak_buffer is 
+ *  called.
+ */
+static void *start;
+static int dma_channel;
+
+void pcm_play_dma_postinit(void)
+{
+    audiohw_postinit();
+}
+
+/* Return the current location in the SDRAM to SARAM transfer along with the
+ *  number of bytes read in the current buffer (count).  There is latency with
+ *  this method equivalent to ~ the size of the SARAM buffer since there is
+ *  another buffer between your ears and this calculation, but this works for
+ *  key clicks and an approximate peak meter.
+ */
+const void * pcm_play_dma_get_peak_buffer(int *count)
+{
+    int cnt = DSP_(_sdem_level);
+
+    unsigned long addr = (unsigned long) start + cnt;
+    
+    *count = (cnt & 0xFFFFF) >> 1;
+    return (void *)((addr + 2) & ~3);
+}
+
+void pcm_play_dma_init(void)
+{
+    /* GIO16 is DSP/AIC3X CLK */
+    IO_GIO_FSEL0 &= 0x3FFF;
+    IO_CLK_OSEL = (IO_CLK_OSEL & 0xFFF0) | 4; /* PLLIN clock */
+    IO_CLK_O0DIV = 7;
+    IO_GIO_DIR1 &= ~(1 << 0); /* GIO16 - output */
+    IO_GIO_FSEL0 |= 0xC000; /* GIO16 - CLKOUT0 */
+
+    audiohw_init();
+    audiohw_set_frequency(HW_FREQ_DEFAULT);
+
+    IO_INTC_IRQ0 = INTR_IRQ0_IMGBUF;
+    bitset16(&IO_INTC_EINT0, INTR_EINT0_IMGBUF);
+    
+    /* Set this as a FIQ */
+    bitset16(&IO_INTC_FISEL0, INTR_EINT0_IMGBUF);
+    
+    /* Enable the HPIB clock */
+    bitset16(&IO_CLK_MOD0, (CLK_MOD0_HPIB | CLK_MOD0_DSP));
+
+    /* Enable IMGBUF clock */
+    bitset16(&IO_CLK_MOD1, CLK_MOD1_IMGBUF);
+
+    dma_channel = dma_request_channel(DMA_PERIPHERAL_DSP,
+                                      DMA_MODE_1_BURST);
+
+    IO_DSPC_HPIB_CONTROL = 1 << 10 | 1 << 9 | 1 << 8 | 1 << 7 | 1 << 3 | 1 << 0;
+ 
+    dsp_reset();
+    dsp_load(dsp_image);
+
+    DSP_(_dma0_stopped)=1;
+    dsp_wake();
+}
+
+void pcm_dma_apply_settings(void)
+{
+    audiohw_set_frequency(pcm_fsel);
+}
+
+/* Note that size is actually limited to the size of a short right now due to
+ *  the implementation on the DSP side (and the way that we access it)
+ */
+void pcm_play_dma_start(const void *addr, size_t size)
+{
+    unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START;
+    /* Initialize codec. */
+    DSP_(_sdem_addrl) = sdem_addr & 0xffff;
+    DSP_(_sdem_addrh) = sdem_addr >> 16;
+    DSP_(_sdem_dsp_size) = size;
+    DSP_(_dma0_stopped)=0;
+    
+    dsp_wake();
+}
+
+void pcm_play_dma_stop(void)
+{
+    DSP_(_dma0_stopped)=1;
+    dsp_wake();
+}
+
+void pcm_play_lock(void)
+{
+
+}
+
+void pcm_play_unlock(void)
+{
+
+}
+
+void pcm_play_dma_pause(bool pause)
+{
+    if (pause)
+    {
+        DSP_(_dma0_stopped)=2;
+        dsp_wake();
+    }
+    else
+    {
+        DSP_(_dma0_stopped)=0;
+        dsp_wake();
+    }
+}
+
+size_t pcm_get_bytes_waiting(void)
+{
+    return DSP_(_sdem_dsp_size)-DSP_(_sdem_level);
+}
+
+/* Only used when debugging */
+static char buffer[80];
+
+void DSPHINT(void) __attribute__ ((section(".icode")));
+void DSPHINT(void)
+{
+    unsigned int i;
+    size_t size;
+
+    IO_INTC_FIQ0 = INTR_IRQ0_IMGBUF;
+
+    switch (dsp_message.msg) 
+    {
+    case MSG_DEBUGF:
+        /* DSP stores one character per word. */
+        for (i = 0; i < sizeof(buffer); i++) 
+        {
+            buffer[i] = dsp_message.payload.debugf.buffer[i];
+        }
+
+        DEBUGF("DSP: %s", buffer);
+        break;
+        
+    case MSG_REFILL:
+        /* Buffer empty.  Try to get more. */
+        pcm_play_get_more_callback(&start, &size);
+
+        if (size != 0)
+        {
+            unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START;
+            /* Flush any pending cache writes */
+            clean_dcache_range(start, size);
+
+            /* set the new DMA values */
+            DSP_(_sdem_addrl) = sdem_addr & 0xffff;
+            DSP_(_sdem_addrh) = sdem_addr >> 16;
+            DSP_(_sdem_dsp_size) = size;
+            
+            DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx",
+                (unsigned long)start, (unsigned long)sdem_addr);
+
+            pcm_play_dma_started_callback();
+        }
+        
+        break;
+    default:
+        DEBUGF("DSP: unknown msg 0x%04x", dsp_message.msg);
+        break;
+    }
+
+    /* Re-Activate the channel */
+    dsp_wake();
+    
+    DEBUGF("DSP: %s", buffer);
+}
+    
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
new file mode 100644
index 0000000..52ea9be
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
@@ -0,0 +1,59 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "cpu.h"
+#include <stdbool.h>
+#include "kernel.h"
+#include "system.h"
+#include "power.h"
+#include "backlight.h"
+#include "backlight-target.h"
+#include "avr-sansaconnect.h"
+
+void power_init(void)
+{
+}
+
+void power_off(void)
+{
+    avr_hid_reset_codec();
+    avr_hid_power_off();
+}
+
+#if CONFIG_CHARGING
+unsigned int power_input_status(void)
+{
+    return POWER_INPUT_NONE;
+}
+
+/* Returns true if the unit is charging the batteries. */
+bool charging_state(void)
+{
+    return false;
+}
+#endif
+
+void ide_power_enable(bool on)
+{
+  (void)on;
+}
+
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c
new file mode 100644
index 0000000..bd90c51
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c
@@ -0,0 +1,56 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "adc.h"
+#include "powermgmt.h"
+#include "kernel.h"
+
+/* THIS CONTAINS CURRENTLY DUMMY CODE! */
+
+static const unsigned short current_voltage = 3910;
+const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
+{
+    0
+};
+
+const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
+{
+    0
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
+{
+    { 100, 300, 400, 500, 600, 700, 800, 900, 1000, 1200, 1320 },
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
+const unsigned short percent_to_volt_charge[11] =
+{
+    100, 300, 400, 500, 600, 700, 800, 900, 1000, 1200, 1320,
+};
+
+/* Returns battery voltage from ADC [millivolts] */
+unsigned int battery_adc_voltage(void)
+{
+    return current_voltage;
+}
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c
new file mode 100644
index 0000000..ab42beb
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c
@@ -0,0 +1,53 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "kernel.h"
+#include "usb.h"
+#ifdef HAVE_USBSTACK
+#include "usb_drv.h"
+#include "usb_core.h"
+#endif
+
+bool usb_drv_connected(void)
+{
+    return false;
+}
+
+int usb_detect(void)
+{
+    return USB_EXTRACTED;
+}
+
+void usb_init_device(void)
+{
+    return;
+}
+
+void usb_enable(bool on)
+{
+    (void)on;
+}
+
+void usb_attach(void)
+{
+}
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/usb-target.h b/firmware/target/arm/tms320dm320/sansa-connect/usb-target.h
new file mode 100644
index 0000000..6142b09
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sansa-connect/usb-target.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 USB_TARGET_H
+#define USB_TARGET_H
+
+#include "dm320.h"
+
+#include <stdbool.h>
+int usb_detect(void);
+void usb_init_device(void);
+bool usb_drv_connected(void);
+
+#endif
diff --git a/firmware/target/arm/tms320dm320/sdmmc-dm320.c b/firmware/target/arm/tms320dm320/sdmmc-dm320.c
new file mode 100644
index 0000000..307b90e
--- /dev/null
+++ b/firmware/target/arm/tms320dm320/sdmmc-dm320.c
@@ -0,0 +1,949 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: $
+ *
+ * Copyright (C) 2011 by Tomasz Moń
+ *
+ * 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 "sd.h"
+#include "system.h"
+#include <string.h>
+#include "gcc_extensions.h"
+#include "thread.h"
+#include "panic.h"
+#include "kernel.h"
+#include "dma-target.h"
+
+//#define SD_DEBUG
+
+#ifdef SD_DEBUG
+#include "lcd-target.h"
+#include "lcd.h"
+#include "font.h"
+#ifdef BOOTLOADER
+#include "common.h"
+#else
+#include "debug.h"
+#endif
+#endif
+#include "sdmmc.h"
+#include "disk.h"
+#include "fat.h"
+#include "system-target.h"
+
+/* The configuration method is not very flexible. */
+#define CARD_NUM_SLOT   1
+#define NUM_CARDS       2
+
+#define EC_OK                    0
+#define EC_FAILED                1
+#define EC_NOCARD                2
+#define EC_WAIT_STATE_FAILED     3
+#define EC_POWER_UP              4
+#define EC_FIFO_WR_EMPTY         5
+#define EC_FIFO_WR_DONE          6
+#define EC_TRAN_READ_ENTRY       7
+#define EC_TRAN_READ_EXIT        8
+#define EC_TRAN_WRITE_ENTRY      9
+#define EC_TRAN_WRITE_EXIT       10
+#define EC_COMMAND               11
+#define EC_WRITE_PROTECT         12
+#define EC_DATA_TIMEOUT          13
+#define EC_RESP_TIMEOUT          14
+#define EC_CRC_ERROR             15
+#define NUM_EC                   16
+
+#define MIN_YIELD_PERIOD        1000
+#define UNALIGNED_NUM_SECTORS   10
+#define MAX_TRANSFER_ERRORS     10
+
+#define SECTOR_SIZE        512
+#define BLOCKS_PER_BANK    0x7A7800
+
+/* command flags for send_cmd */
+#define SDHC_RESP_FMT_NONE 0x0000
+#define SDHC_RESP_FMT_1    0x0200
+#define SDHC_RESP_FMT_2    0x0400
+#define SDHC_RESP_FMT_3    0x0600
+
+#define INITIAL_CLK    312500   /* Initial clock */
+#define SD_CLK       24000000   /* Clock for SD cards */
+#define MMC_CLK      15000000   /* Clock for MMC cards */
+
+#ifdef SD_DEBUG
+#ifdef BOOTLOADER
+#define dbgprintf printf
+#else
+#define dbgprintf DEBUGF
+#endif
+#else
+#define dbgprintf(...)
+#endif
+
+struct sd_card_status
+{
+    int retry;
+    int retry_max;
+};
+
+/** static, private data **/ 
+
+/* for compatibility */
+static long last_disk_activity = -1;
+
+static bool initialized = false;
+static unsigned int sd_thread_id = 0;
+
+static bool sd_enabled = false;
+static long next_yield = 0;
+
+static tCardInfo card_info [NUM_CARDS];
+static tCardInfo *currcard;
+
+static struct sd_card_status sd_status[NUM_CARDS] =
+{
+#if NUM_CARDS > 1
+    {0, 10},
+#endif
+    {0, 10}
+};
+
+/* Shoot for around 75% usage */
+static long             sd_stack [(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)];
+static const char               sd_thread_name[] = "sd";
+static struct mutex             sd_mtx SHAREDBSS_ATTR;
+static struct event_queue       sd_queue;
+static volatile unsigned int    transfer_error[NUM_DRIVES];
+/* align on cache line size */
+static unsigned char    aligned_buffer[UNALIGNED_NUM_SECTORS * SD_BLOCK_SIZE] 
+                        __attribute__((aligned(32)));
+
+static void sd_card_mux(int card_no)
+{
+#ifdef HAVE_MULTIDRIVE
+#ifdef SANSA_CONNECT
+    /* GIO6 - select Card; GIO5 - select iNAND (both active low) */
+    if (card_no == CARD_NUM_SLOT)
+    {
+        IO_GIO_BITSET0 = (1 << 5); /* deselect iNAND (GIO5) */
+        IO_GIO_BITCLR0 = (1 << 6); /* select card (GIO6) */
+    }
+    else
+    {
+        IO_GIO_BITSET0 = (1 << 6); /* deselect card (GIO6) */
+        IO_GIO_BITCLR0 = (1 << 5); /* select iNAND (GIO5) */
+    }
+#else /* Different players */
+    (void)card_no;
+#endif
+#else /* No multidrive */
+    (void)card_no;
+#endif
+}
+
+
+void sd_enable(bool on)
+{
+    if (sd_enabled == on)
+        return; /* nothing to do */
+
+    if (on)
+    {
+        sd_enabled = true;
+    }
+    else
+    {
+        sd_enabled = false;
+    }
+}
+
+/* sets clock rate just like OF does */
+static void sd_set_clock_rate(unsigned long rate)
+{
+    unsigned char rate_val = 0;
+
+    if (rate == INITIAL_CLK)
+    {
+        rate_val = 0x3B;
+    }
+    else if (rate > INITIAL_CLK)
+    {
+        rate_val = 0;
+    }
+    else
+    {
+        rate_val = 0xFF;
+    }
+
+    IO_MMC_MEM_CLK_CONTROL = (IO_MMC_MEM_CLK_CONTROL & 0xFF00) | rate_val;
+}
+
+static int sd_poll_status(int st_reg_num, volatile unsigned int flag)
+{
+    unsigned int status;
+    unsigned int status1;
+    bool done;
+
+    do
+    {
+        long time = current_tick;
+
+        if (TIME_AFTER(time, next_yield))
+        {
+            long ty = current_tick;
+            yield();
+            next_yield = ty + MIN_YIELD_PERIOD;
+        }
+
+        status = IO_MMC_STATUS0;
+        status1 = IO_MMC_STATUS1;
+
+        if (status & MMC_ST0_CMD_TIMEOUT)
+        {
+            dbgprintf("CMD timeout");
+            return -EC_RESP_TIMEOUT;
+        }
+        if (status & MMC_ST0_DATA_TIMEOUT)
+        {
+            dbgprintf("DATA timeout");
+            return -EC_DATA_TIMEOUT;
+        }
+
+        if (status &
+            (MMC_ST0_WR_CRCERR | MMC_ST0_RD_CRCERR | MMC_ST0_RESP_CRCERR))
+        {
+            dbgprintf("CRC error");
+            return -EC_CRC_ERROR;
+        }
+
+        if (st_reg_num == 0)
+        {
+            done = status & flag;
+        }
+        else
+        {
+            done = status1 & flag;
+        }
+    } while (!done);
+
+    return EC_OK;
+}
+
+static int dma_wait_for_completion(void)
+{
+    unsigned short dma_status;
+
+    do
+    {
+        long time = current_tick;
+
+        if (TIME_AFTER(time, next_yield))
+        {
+            long ty = current_tick;
+            yield();
+            next_yield = ty + MIN_YIELD_PERIOD;
+        }
+
+        dma_status = IO_MMC_SD_DMA_STATUS1;
+        if (dma_status & (1 << 13))
+        {
+            return -EC_DATA_TIMEOUT;
+        }
+    } while (dma_status & (1 << 12));
+
+    return EC_OK;
+}
+
+static int sd_command(int cmd, unsigned long arg,
+                      int cmdat, unsigned long *response)
+{
+    int ret;
+
+    /* Clear response registers */
+    IO_MMC_RESPONSE0 = 0;
+    IO_MMC_RESPONSE1 = 0;
+    IO_MMC_RESPONSE2 = 0;
+    IO_MMC_RESPONSE3 = 0;
+    IO_MMC_RESPONSE4 = 0;
+    IO_MMC_RESPONSE5 = 0;
+    IO_MMC_RESPONSE6 = 0;
+    IO_MMC_RESPONSE7 = 0;
+    IO_MMC_COMMAND_INDEX = 0;
+    IO_MMC_SPI_DATA = 0;
+
+    IO_MMC_ARG_LOW = (unsigned int)((arg & 0xFFFF));
+    IO_MMC_ARG_HI = (unsigned int)((arg & 0xFFFF0000) >> 16);
+
+    /* SD is always in push-pull mode */
+    cmdat |= MMC_CMD_PPLEN;
+
+    cmdat |= (cmd & MMC_CMD_CMD_MASK);
+
+    if (cmdat & MMC_CMD_DATA)
+        cmdat |= MMC_CMD_DCLR;
+
+    IO_MMC_COMMAND = cmdat;
+
+    if (cmdat & MMC_CMD_DATA)
+    {
+        /* Command requires data - do not wait for RSPDNE */
+        ret = EC_OK;
+    }
+    else
+    {
+        ret = sd_poll_status(0, MMC_ST0_RSPDNE);
+    }
+
+    if (ret != EC_OK)
+    {
+        dbgprintf("Command failed (ret %d)", ret);
+        return ret;
+    }
+
+    if (response == NULL)
+    {
+        /* discard response */
+    }
+    else if ((cmdat & SDHC_RESP_FMT_1) || (cmdat & SDHC_RESP_FMT_3))
+    {
+        response[0] = (IO_MMC_RESPONSE7 << 16) | IO_MMC_RESPONSE6;
+    }
+    else if (cmdat & SDHC_RESP_FMT_2)
+    {
+        response[0] = (IO_MMC_RESPONSE7 << 16) | IO_MMC_RESPONSE6;
+        response[1] = (IO_MMC_RESPONSE5 << 16) | IO_MMC_RESPONSE4;
+        response[2] = (IO_MMC_RESPONSE3 << 16) | IO_MMC_RESPONSE2;
+        response[3] = (IO_MMC_RESPONSE1 << 16) | IO_MMC_RESPONSE0;
+    }
+
+    return 0;
+}
+
+static int sd_init_card(const int card_no)
+{
+    bool sdhc = false;
+    unsigned long response[4];
+    int ret;
+    int i;
+
+    memset(currcard, 0, sizeof(*currcard));
+    sd_card_mux(card_no);
+
+    /* Set data bus width to 1 bit */
+    bitclr16(&IO_MMC_CONTROL, MMC_CTRL_WIDTH);
+    sd_set_clock_rate(INITIAL_CLK);
+
+    ret = sd_command(SD_GO_IDLE_STATE, 0, MMC_CMD_INITCLK, NULL);
+
+    if (ret < 0)
+        return -1;
+
+    ret = sd_command(SD_SEND_IF_COND, 0x1AA,
+                     SDHC_RESP_FMT_3, response);
+    if ((response[0] & 0xFFF) == 0x1AA)
+    {
+        sdhc = true;
+        dbgprintf("found sdhc card");
+    }
+
+    while ((currcard->ocr & (1 << 31)) == 0) /* until card is powered up */
+    {
+        ret = sd_command(SD_APP_CMD, currcard->rca,
+                         SDHC_RESP_FMT_1, NULL);
+        if (ret < 0)
+        {
+            dbgprintf("SD_APP_CMD failed");
+            return -1;
+        }
+
+        ret = sd_command(SD_APP_OP_COND,
+                         (1 << 20) /* 3.2-3.3V */ |
+                         (1 << 21) /* 3.3-3.4V */ |
+                         (sdhc ? (1 << 30) : 0),
+                         SDHC_RESP_FMT_3, &currcard->ocr);
+
+        if (ret < 0)
+        {
+            dbgprintf("SD_APP_OP_COND failed");
+            return -1;
+        }
+    }
+
+    dbgprintf("Card powered up");
+
+    ret = sd_command(SD_ALL_SEND_CID, 0,
+                     SDHC_RESP_FMT_2, response);
+    if (ret < 0)
+    {
+        dbgprintf("SD_ALL_SEND_CID failed");
+        return -1;
+    }
+
+    for (i = 0; i<4; i++)
+    {
+        currcard->cid[i] = response[i];
+    }
+
+    ret = sd_command(SD_SEND_RELATIVE_ADDR, 0,
+                     SDHC_RESP_FMT_1, &currcard->rca);
+    if (ret < 0)
+    {
+        dbgprintf("SD_SEND_RELATIVE_ADDR failed"); 
+        return -1;
+    }
+
+    ret = sd_command(SD_SEND_CSD, currcard->rca,
+                     SDHC_RESP_FMT_2, response);
+    if (ret < 0)
+    {
+        dbgprintf("SD_SEND_CSD failed");
+        return -1;
+    }
+
+    for (i = 0; i<4; i++)
+    {
+        currcard->csd[i] = response[i];
+    }
+
+    sd_parse_csd(currcard);
+
+    sd_set_clock_rate(currcard->speed);
+
+    ret = sd_command(SD_SELECT_CARD, currcard->rca,
+                     SDHC_RESP_FMT_1, NULL);
+    if (ret < 0)
+    {
+        dbgprintf("SD_SELECT_CARD failed");
+        return -1;
+    }
+
+    ret = sd_command(SD_APP_CMD, currcard->rca,
+                     SDHC_RESP_FMT_1, NULL);
+    if (ret < 0)
+    {
+        dbgprintf("SD_APP_CMD failed");
+        return -1;
+    }
+
+    ret = sd_command(SD_SET_BUS_WIDTH, currcard->rca | 2,
+                     SDHC_RESP_FMT_1, NULL); /* 4 bit */
+    if (ret < 0)
+    {
+        dbgprintf("SD_SET_BUS_WIDTH failed");
+        return -1;
+    }
+
+    /* Set data bus width to 4 bits */
+    bitset16(&IO_MMC_CONTROL, MMC_CTRL_WIDTH);
+
+    ret = sd_command(SD_SET_BLOCKLEN, currcard->blocksize,
+                     SDHC_RESP_FMT_1, NULL);
+    if (ret < 0)
+    {
+        dbgprintf("SD_SET_BLOCKLEN failed");
+        return -1;
+    }
+
+    IO_MMC_BLOCK_LENGTH = currcard->blocksize;
+
+    dbgprintf("Card initialized");
+    currcard->initialized = 1;
+
+    return EC_OK;
+}
+
+/* lock must already by aquired */
+static void sd_select_device(int card_no)
+{
+    currcard = &card_info[card_no];
+
+    if (card_no == 0)
+    {
+        /* Main card always gets a chance */
+        sd_status[0].retry = 0;
+    }
+
+    if (currcard->initialized > 0)
+    {
+        /* This card is already initialized - switch to it */
+        sd_card_mux(card_no);
+        return;
+    }
+
+    if (currcard->initialized == 0)
+    {
+        /* Card needs (re)init */
+        sd_init_card(card_no);
+    }
+}
+
+static inline bool card_detect_target(void)
+{
+#ifdef SANSA_CONNECT
+    bool removed;
+
+    removed = IO_GIO_BITSET0 & (1 << 14);
+
+    return !removed;
+#else
+    return false;
+#endif
+}
+
+
+#ifdef HAVE_HOTSWAP
+
+static int sd1_oneshot_callback(struct timeout *tmo)
+{
+    (void)tmo;
+
+    /* This is called only if the state was stable for 300ms - check state
+     * and post appropriate event. */
+    if (card_detect_target())
+    {
+        queue_broadcast(SYS_HOTSWAP_INSERTED, 0);
+    }
+    else
+        queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0);
+    return 0;
+}
+
+#ifdef SANSA_CONNECT
+void GIO14(void) __attribute__ ((section(".icode")));
+void GIO14(void)
+{
+    static struct timeout sd1_oneshot;
+
+    /* clear interrupt */
+    IO_INTC_IRQ2 = (1<<3);
+
+    timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
+}
+#endif
+
+bool sd_removable(IF_MD_NONVOID(int card_no))
+{
+#ifndef HAVE_MULTIDRIVE
+    const int card_no = 0;
+#endif
+
+    return (card_no == CARD_NUM_SLOT);
+}
+
+bool sd_present(IF_MD_NONVOID(int card_no))
+{
+#ifndef HAVE_MULTIDRIVE
+    const int card_no = 0;
+#endif
+
+    return (card_no == CARD_NUM_SLOT) ? card_detect_target() :
+#ifdef SANSA_CONNECT
+    true; /* iNAND is always present */
+#else
+    false;
+#endif
+}
+
+#else /* no hotswap */
+
+bool sd_removable(IF_MD_NONVOID(int card_no))
+{
+#ifdef HAVE_MULTIDRIVE
+    (void)card_no;
+#endif
+    
+    /* not applicable */
+    return false;
+}
+
+#endif /* HAVE_HOTSWAP */
+
+static void sd_thread(void) NORETURN_ATTR;
+static void sd_thread(void)
+{
+    struct queue_event ev;
+
+    /* TODO */
+    while (1)
+    {
+        queue_wait_w_tmo(&sd_queue, &ev, HZ);
+        switch ( ev.id )
+        {
+#ifdef HAVE_HOTSWAP
+        case SYS_HOTSWAP_INSERTED:
+        case SYS_HOTSWAP_EXTRACTED:
+        {
+            int success = 1;
+            fat_lock();          /* lock-out FAT activity first -
+                                    prevent deadlocking via disk_mount that
+                                    would cause a reverse-order attempt with
+                                    another thread */
+            mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
+                                    into driver that bypass the fat cache */
+
+            /* We now have exclusive control of fat cache and ata */
+
+            disk_unmount(0);     /* release "by force", ensure file
+                                    descriptors aren't leaked and any busy
+                                    ones are invalid if mounting */
+
+            /* Force card init for new card, re-init for re-inserted one or
+             * clear if the last attempt to init failed with an error. */
+            card_info[0].initialized = 0;
+
+            if (ev.id == SYS_HOTSWAP_INSERTED)
+            {
+                /* FIXME: once sd_enabled is implement properly,
+                 * reinitializing the controllers might be needed */
+                sd_enable(true);
+                if (success < 0) /* initialisation failed */
+                    panicf("SD init failed : %d", success);
+                success = disk_mount(0); /* 0 if fail */
+            }
+
+            /* notify the system about the changed filesystems
+             */
+            if (success)
+                queue_broadcast(SYS_FS_CHANGED, 0);
+
+            /* Access is now safe */
+            mutex_unlock(&sd_mtx);
+            fat_unlock();
+            sd_enable(false);
+        }
+            break;
+#endif
+        }        
+    }
+}
+
+static int sd_wait_for_state(unsigned int state)
+{
+    unsigned long response = 0;
+    unsigned int timeout = HZ; /* ticks */
+    long t = current_tick;
+
+    while (1)
+    {
+        long tick;
+        int ret = sd_command(SD_SEND_STATUS, currcard->rca,
+                             SDHC_RESP_FMT_1, &response);
+        if (ret < 0)
+            return ret;
+
+        if ((SD_R1_CURRENT_STATE(response) == state))
+        {
+            return EC_OK;
+        }
+
+        if(TIME_AFTER(current_tick, t + timeout))
+            return -2;
+
+        if (TIME_AFTER((tick = current_tick), next_yield))
+        {
+            yield();
+            timeout += current_tick - tick;
+            next_yield = tick + MIN_YIELD_PERIOD;
+        }
+    }
+}
+
+static int sd_transfer_sectors(int card_no, unsigned long start,
+                               int count, void *buffer, bool write)
+{
+    int ret;
+    unsigned long start_addr;
+    int dma_channel = -1;
+    bool use_direct_dma;
+    int count_per_dma;
+    unsigned long rel_addr;
+
+    dbgprintf("transfer %d %d %d", card_no, start, count);
+    mutex_lock(&sd_mtx);
+    sd_enable(true);
+
+sd_transfer_retry:
+    if (card_no == CARD_NUM_SLOT && !card_detect_target())
+    {
+        /* no external sd-card inserted */
+        ret = -EC_NOCARD;
+        goto sd_transfer_error;
+    }
+
+    sd_select_device(card_no);
+
+    if (currcard->initialized < 0)
+    {
+        ret = currcard->initialized;
+        goto sd_transfer_error;
+    }
+
+    last_disk_activity = current_tick;
+
+    ret = sd_wait_for_state(SD_TRAN);
+    if (ret < EC_OK)
+    {
+        goto sd_transfer_error;
+    }
+
+    IO_MMC_BLOCK_LENGTH = currcard->blocksize;
+
+    start_addr = start;
+
+    do
+    {
+        count_per_dma = count;
+
+        if (((unsigned long)buffer) & 0x1F)
+        {
+            /* MMC/SD interface requires 32-byte alignment of buffer */
+            use_direct_dma = false;
+            if (count > UNALIGNED_NUM_SECTORS)
+            {
+                count_per_dma = UNALIGNED_NUM_SECTORS;
+            }
+        }
+        else
+        {
+            use_direct_dma = true;
+        }
+
+        if (write == true)
+        {
+            if (use_direct_dma == false)
+            {
+                memcpy(aligned_buffer, buffer, count_per_dma*SD_BLOCK_SIZE);
+            }
+            commit_dcache_range(use_direct_dma ? buffer : aligned_buffer,
+                                count_per_dma*SD_BLOCK_SIZE);
+        }
+
+        IO_MMC_NR_BLOCKS = count_per_dma;
+
+        /* Set start_addr to the correct unit (blocks or bytes) */
+        if (!(card_info[card_no].ocr & SD_OCR_CARD_CAPACITY_STATUS))
+            start_addr *= SD_BLOCK_SIZE; /* not SDHC */
+
+        ret = sd_command(write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK,
+                         start_addr, MMC_CMD_DCLR | MMC_CMD_DATA |
+                         SDHC_RESP_FMT_1 | (write ? MMC_CMD_WRITE : 0),
+                         NULL);
+
+        if (ret < 0)
+            goto sd_transfer_error;
+
+        /* other burst modes are not supported for this peripheral */
+        dma_channel = dma_request_channel(DMA_PERIPHERAL_MMCSD,
+                                          DMA_MODE_8_BURST);
+
+        if (use_direct_dma == true)
+        {
+            rel_addr = ((unsigned long)buffer)-CONFIG_SDRAM_START;
+        }
+        else
+        {
+            rel_addr = ((unsigned long)aligned_buffer)-CONFIG_SDRAM_START;
+        }
+
+        IO_MMC_SD_DMA_ADDR_LOW = rel_addr & 0xFFFF;
+        IO_MMC_SD_DMA_ADDR_HI = (rel_addr & 0xFFFF0000) >> 16;
+
+        IO_MMC_SD_DMA_MODE |= MMC_DMAMODE_ENABLE;
+        if (write == true)
+        {
+            IO_MMC_SD_DMA_MODE |= MMC_DMAMODE_WRITE;
+        }
+
+        IO_MMC_SD_DMA_TRIGGER = 1;
+
+        dbgprintf("SD DMA transfer in progress");
+
+        ret = dma_wait_for_completion();
+        dma_release_channel(dma_channel);
+
+        dbgprintf("SD DMA transfer complete");
+
+        if (ret != EC_OK)
+        {
+            goto sd_transfer_error;
+        }
+
+        count -= count_per_dma;
+
+        if (write == false)
+        {
+            discard_dcache_range(use_direct_dma ? buffer : aligned_buffer,
+                                 count_per_dma*SD_BLOCK_SIZE);
+
+            if (use_direct_dma == false)
+            {
+                memcpy(buffer, aligned_buffer, count_per_dma*SD_BLOCK_SIZE);
+            }
+        }
+
+        buffer += count_per_dma*SD_BLOCK_SIZE;
+        start_addr += count_per_dma;
+
+        last_disk_activity = current_tick;
+
+        ret = sd_command(SD_STOP_TRANSMISSION, 0, SDHC_RESP_FMT_1, NULL);
+        if (ret < 0)
+        {
+            goto sd_transfer_error;
+        }
+
+        ret = sd_wait_for_state(SD_TRAN);
+        if (ret < 0)
+        {
+            goto sd_transfer_error;
+        }
+    } while (count > 0);
+
+    while (1)
+    {
+        sd_enable(false);
+        mutex_unlock(&sd_mtx);
+
+        return ret;
+
+sd_transfer_error:
+        if (sd_status[card_no].retry < sd_status[card_no].retry_max
+            && ret != -EC_NOCARD)
+        {
+            sd_status[card_no].retry++;
+            currcard->initialized = 0;
+            goto sd_transfer_retry;
+        }
+    }
+}
+
+int sd_read_sectors(IF_MD2(int card_no,) unsigned long start, int incount,
+                     void* inbuf)
+{
+#ifndef HAVE_MULTIDRIVE
+    const int card_no = 0;
+#endif
+    return sd_transfer_sectors(card_no, start, incount, inbuf, false);
+}
+
+int sd_write_sectors(IF_MD2(int card_no,) unsigned long start, int count,
+                      const void* outbuf)
+{
+#ifndef BOOTLOADER
+#ifndef HAVE_MULTIDRIVE
+    const int card_no = 0;
+#endif
+    return sd_transfer_sectors(card_no, start, count, (void*)outbuf, true);
+#else /* we don't need write support in bootloader */
+#ifdef HAVE_MULTIDRIVE
+    (void)card_no;
+#endif
+    (void)start;
+    (void)count;
+    (void)outbuf;
+    return 0;
+#endif
+}
+
+int sd_init(void)
+{
+    int ret = EC_OK;
+
+#ifndef BOOTLOADER
+    sd_enabled = true;
+    sd_enable(false);
+#endif
+    mutex_init(&sd_mtx);
+
+    mutex_lock(&sd_mtx);
+    initialized = true;
+
+    /* based on linux/drivers/mmc/dm320mmc.c
+       Copyright (C) 2006 ZSI, All Rights Reserved.
+       Written by: Ben Bostwick */
+
+    bitclr16(&IO_CLK_MOD2, CLK_MOD2_MMC);
+    bitset16(&IO_CLK_INV, CLK_INV_MMC);
+
+    /* mmc module clock: 75 Mhz (AHB) / 2 = ~37.5 Mhz */
+    /* OF uses 1, but for some reason it freezes on us */
+    IO_CLK_DIV3 = (IO_CLK_DIV3 & 0xFF00) | 0x02;
+
+    bitset16(&IO_CLK_MOD2, CLK_MOD2_MMC);
+
+    /* set mmc module into reset */
+    bitset16(&IO_MMC_CONTROL, (MMC_CTRL_DATRST | MMC_CTRL_CMDRST));
+
+    /* set resp timeout to max */
+    IO_MMC_RESPONSE_TIMEOUT |= 0x1FFF;
+    IO_MMC_READ_TIMEOUT = 0xFFFF;
+
+    /* all done, take mmc module out of reset */
+    bitclr16(&IO_MMC_CONTROL, (MMC_CTRL_DATRST | MMC_CTRL_CMDRST));
+
+#ifdef SANSA_CONNECT
+    /* GIO37 - Power Card; GIO38 - Power iNAND (both active low) */
+    IO_GIO_DIR2 &= ~((1 << 5) /* GIO37 */ | (1 << 6) /* GIO38 */);
+    IO_GIO_INV2 &= ~((1 << 5) /* GIO37 */ | (1 << 6) /* GIO38 */);
+    IO_GIO_BITCLR2 = (1 << 5) | (1 << 6);
+
+    /* GIO6 - select Card; GIO5 - select iNAND (both active low) */
+    IO_GIO_DIR0 &= ~((1 << 6) /* GIO6 */ | (1 << 5) /* GIO5 */);
+    IO_GIO_INV0 &= ~((1 << 6) /* GIO6 */ | (1 << 5) /* GIO5 */);
+    IO_GIO_BITSET0 = (1 << 6) | (1 << 5);
+
+#ifdef HAVE_HOTSWAP
+    /* GIO14 is card detect */
+    IO_GIO_DIR0 |= (1 << 14); /* Set GIO14 as input */
+    IO_GIO_INV0 &= ~(1 << 14); /* GIO14 not inverted */
+    IO_GIO_IRQPORT |= (1 << 14); /* Enable GIO14 external interrupt */
+    IO_GIO_IRQEDGE |= (1 << 14); /* Any edge detection */
+
+    /* Enable GIO14 interrupt */
+    IO_INTC_EINT2 |= INTR_EINT2_EXT14;
+#endif
+#endif
+
+    sd_select_device(1);
+
+    /* Enable Memory Card CLK */
+    bitset16(&IO_MMC_MEM_CLK_CONTROL, (1 << 8));
+
+    queue_init(&sd_queue, true);
+    sd_thread_id = create_thread(sd_thread, sd_stack, sizeof(sd_stack),
+        0, sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE)
+        IF_COP(, CPU));
+
+    mutex_unlock(&sd_mtx);
+
+    return ret;
+}
+
+long sd_last_disk_activity(void)
+{
+    return last_disk_activity;
+}
+
+tCardInfo *card_get_info_target(int card_no)
+{    
+    return &card_info[card_no];
+}
+
+void sd_sleepnow(void)
+{
+}
+
diff --git a/firmware/target/arm/tms320dm320/system-dm320.c b/firmware/target/arm/tms320dm320/system-dm320.c
index f2a4aac..528d442 100644
--- a/firmware/target/arm/tms320dm320/system-dm320.c
+++ b/firmware/target/arm/tms320dm320/system-dm320.c
@@ -26,11 +26,16 @@
 #include "uart-target.h"
 #include "system-arm.h"
 #include "spi.h"
+#include "i2c.h"
 #ifdef CREATIVE_ZVx
 #include "dma-target.h"
-#else
+#endif
+#ifdef MROBE_500
 #include "usb-mr500.h"
 #endif
+#ifdef SANSA_CONNECT
+#include "avr-sansaconnect.h"
+#endif
 
 static unsigned short clock_arm_slow = 0xFFFF;
 static unsigned short clock_arm_fast = 0xFFFF;
@@ -182,7 +187,12 @@
     IO_INTC_EINT0 = 0;
     IO_INTC_EINT1 = 0;
     IO_INTC_EINT2 = 0;
+#ifdef MROBE_500
     while ((IO_GIO_BITSET0&0x01) != 0); /* Wait for power button */
+#endif
+#ifdef SANSA_CONNECT
+    while (1); /* Holding power button for a while makes avr system reset */
+#endif
 }
 
 void system_init(void)
@@ -311,7 +321,7 @@
         clock_arm_slow = (0 << 8) | 3;
         clock_arm_fast = (1 << 8) | 1;
     }
-    
+
     /* M48XI disabled, USB buffer powerdown */
     IO_CLK_LPCTL1 = 0x11; /* I2C wodn't work with this disabled */
 
@@ -337,14 +347,22 @@
     uart_init();
     spi_init();
 
+#ifdef MROBE_500
     /* Initialization is done so shut the front LED off so that the battery
      * can charge.
      */
     IO_GIO_BITCLR2 = 0x0001;
-    
+#endif
+
 #ifdef CREATIVE_ZVx
     dma_init();
 #endif
+
+#ifdef SANSA_CONNECT
+    i2c_init();
+    avr_hid_init();
+    avr_hid_enable_charger();
+#endif
 }
 
 int system_memory_guard(int newmode)
@@ -388,4 +406,13 @@
     }
 }
 
+#ifdef BOOTLOADER
+void system_prepare_fw_start(void)
+{
+    tick_stop();
+    IO_INTC_EINT0 = 0;
+    IO_INTC_EINT1 = 0;
+    IO_INTC_EINT2 = 0;
+}
+#endif
 
diff --git a/firmware/target/arm/tms320dm320/system-target.h b/firmware/target/arm/tms320dm320/system-target.h
index 22cf554..59ae61f 100644
--- a/firmware/target/arm/tms320dm320/system-target.h
+++ b/firmware/target/arm/tms320dm320/system-target.h
@@ -41,4 +41,9 @@
     true; }) /* handled here */
 #endif
 
+#ifdef BOOTLOADER
+void tick_stop(void);
+void system_prepare_fw_start(void);
+#endif
+
 #endif /* SYSTEM_TARGET_H */
diff --git a/tools/configure b/tools/configure
index 222d1dc..d715ef4 100755
--- a/tools/configure
+++ b/tools/configure
@@ -1282,14 +1282,14 @@
                                                  63) Sansa Fuze v2
  ==Samsung==              ==Tatung==             64) Sansa Fuze+
  140) YH-820              150) Elio TPJ-1022     65) Sansa Clip Zip
- 141) YH-920                                     
- 142) YH-925              ==Packard Bell==       ==Logik==
- 143) YP-S3               160) Vibe 500          80) DAX 1GB MP3/DAB
-                                                 
-==Application==           ==MPIO==               ==Lyre project==
- 200) SDL                 170) HD200             130) Lyre proto 1
- 201) Android             171) HD300             131) Mini2440
- 202) Nokia N8xx
+ 141) YH-920                                     66) Sansa Connect
+ 142) YH-925              ==Packard Bell==
+ 143) YP-S3               160) Vibe 500          ==Logik==
+                                                 80) DAX 1GB MP3/DAB
+ ==Application==          ==MPIO==
+ 200) SDL                 170) HD200             ==Lyre project==
+ 201) Android             171) HD300             130) Lyre proto 1
+ 202) Nokia N8xx                                 131) Mini2440
  203) Nokia N900          ==ROCKCHIP==           ==HiFiMAN==
  204) Pandora             180) rk27xx generic    190) HM-60x
                                                  191) HM-801
@@ -2550,6 +2550,25 @@
     arm926ejscc
     ;;
 
+   66|sansaconnect)
+    target_id=81
+    modelname="sansaconnect"
+    target="-DSANSA_CONNECT"
+    memory=64
+    bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
+    bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
+    tool="$rootdir/tools/scramble -add=conn"
+    output="rockbox.sansa"
+    bootoutput="bootloader-connect.sansa"
+    appextra="recorder:gui"
+    plugins="yes"
+    swcodec="yes"
+    toolset=$scramblebitmaptools
+    t_cpu="arm"
+    t_manufacturer="tms320dm320"
+    t_model="sansa-connect"
+    arm926ejscc
+    ;;
    150|tatungtpj1022)
     target_id=25
     modelname="tatungtpj1022"
diff --git a/tools/scramble.c b/tools/scramble.c
index 126fa7b..7c7a847 100644
--- a/tools/scramble.c
+++ b/tools/scramble.c
@@ -341,6 +341,8 @@
             modelnum = 73;
         else if (!strcmp(&argv[1][5], "clzp")) /* Sansa Clip Zip */
             modelnum = 79;
+        else if (!strcmp(&argv[1][5], "conn")) /* Sansa Connect */
+            modelnum = 81;
         else {
             fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
             return 2;