Index: apps/plugins/SOURCES
===================================================================
--- apps/plugins/SOURCES	(revision 21087)
+++ apps/plugins/SOURCES	(working copy)
@@ -1,4 +1,9 @@
 /* plugins common to all models */
+
+test_codec.c
+test_disk.c
+test_fps.c
+
 chessclock.c
 credits.c
 cube.c
Index: firmware/target/arm/as3525/debug-as3525.c
===================================================================
--- firmware/target/arm/as3525/debug-as3525.c	(revision 21087)
+++ firmware/target/arm/as3525/debug-as3525.c	(working copy)
@@ -28,6 +28,7 @@
 #include "sprintf.h"
 #include "cpu.h"
 #include "pl180.h"
+#include "sd.h"

 #define _DEBUG_PRINTF(a,varargs...) \
     snprintf(buf, sizeof(buf), (a), ##varargs); lcd_puts(0,line++,buf)
@@ -339,10 +340,11 @@
 {
     char buf[50];
     int line;
+        char buf2[512*2];

     lcd_clear_display();
     lcd_setfont(FONT_SYSFIXED);
-
+    sd_read_sectors(0, 0x7A7800 - 1, 2, buf2);
     while(1)
     {
         line = 0;
@@ -359,6 +361,7 @@
         line++;
         _DEBUG_PRINTF("[CP15]");
         _DEBUG_PRINTF("CP15: 0x%8x", read_cp15());
+        _DEBUG_PRINTF("DIR0: %x DIR4: %x", *(buf2+512), *(buf2+512+4));
         lcd_update();
         if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL))
             break;
Index: firmware/target/arm/as3525/ata_sd_as3525.c
===================================================================
--- firmware/target/arm/as3525/ata_sd_as3525.c	(revision 21087)
+++ firmware/target/arm/as3525/ata_sd_as3525.c	(working copy)
@@ -142,8 +142,8 @@
     GPIOA_IC = (1<<2);
     timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
 }
-#endif
-#endif
+#endif  /* defined(SANSA_E200V2) || defined(SANSA_FUZE) */
+#endif  /* HAVE_HOTSWAP */

 void INT_NAND(void)
 {
@@ -211,7 +211,7 @@
         {   /* resp received */
             if(flags & MCI_LONG_RESP)
             {
-                /* store the response in little endian order for the words */
+                /* store the response in reverse words order */
                 response[0] = MCI_RESP3(drive);
                 response[1] = MCI_RESP2(drive);
                 response[2] = MCI_RESP1(drive);
@@ -322,7 +322,7 @@

     card_info[drive].initialized = 1;

-    MCI_CLOCK(drive) |= MCI_CLOCK_BYPASS;   /* full speed */
+    MCI_CLOCK(drive) |= MCI_CLOCK_BYPASS; /* full speed for controller clock */
     mci_delay();

     /*
@@ -627,7 +627,6 @@
     const int drive = 0;
 #endif
     int ret = 0;
-    int bank;
     bool unaligned_transfer = (int)buf & 3;

     /* skip SanDisk OF */
@@ -648,29 +647,10 @@

     last_disk_activity = current_tick;

-    /* Only switch banks for internal storage */
-    if(drive == INTERNAL_AS3525)
-    {
-        bank = start / BLOCKS_PER_BANK;
-
-        if(card_info[INTERNAL_AS3525].current_bank != bank)
-        {
-            ret = sd_select_bank(bank);
-            if (ret < 0)
-            {
-                ret -= 20;
-                goto sd_transfer_error;
-            }
-        }
-
-        start -= bank * BLOCKS_PER_BANK;
-    }
-
-
     ret = sd_wait_for_state(drive, SD_TRAN);
     if (ret < 0)
     {
-        ret -= 2*20;
+        ret -= 20;
         goto sd_transfer_error;
     }

@@ -684,13 +664,35 @@
         void *dma_buf;
         const int cmd =
             write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK;
-        int arg = start;
-        if(!(card_info[drive].ocr & (1<<30)))   /* not SDHC */
-            arg *= BLOCK_SIZE;
+        unsigned long bank_start = start;

         /* Interrupt handler might set this to true during transfer */
         retry = false;

+        /* Only switch banks for internal storage */
+        if(drive == INTERNAL_AS3525)
+        {
+            int bank = start / BLOCKS_PER_BANK; /* Current bank */
+
+            /* Switch bank if needed */
+            if(card_info[INTERNAL_AS3525].current_bank != bank)
+            {
+                ret = sd_select_bank(bank);
+                if (ret < 0)
+                {
+                    ret -= 2*20;
+                    goto sd_transfer_error;
+                }
+            }
+
+            /* Adjust start block in current bank */
+            bank_start -= bank * BLOCKS_PER_BANK;
+
+            /* Do not cross a bank boundary in a single transfer loop */
+            if((transfer + bank_start) >= BLOCKS_PER_BANK)
+                transfer = BLOCKS_PER_BANK - bank_start;
+        }
+
         if(unaligned_transfer)
         {
             dma_buf = aligned_buffer;
@@ -699,10 +701,14 @@
             if(write)
                 memcpy(aligned_buffer, buf, transfer * SECTOR_SIZE);
         }
-        else
+        else    /* Aligned transfers are faster : no memcpy */
             dma_buf = buf;

-        if(!send_cmd(drive, cmd, arg, MCI_ARG, NULL))
+        /* Set bank_start to the correct unit (blocks or bytes) */
+        if(!(card_info[drive].ocr & (1<<30)))   /* not SDHC */
+            bank_start *= BLOCK_SIZE;
+
+        if(!send_cmd(drive, cmd, bank_start, MCI_ARG, NULL))
         {
             ret -= 3*20;
             goto sd_transfer_error;