Index: apps/lang/english.lang
===================================================================
--- apps/lang/english.lang	(revision 26398)
+++ apps/lang/english.lang	(working copy)
@@ -8058,6 +8058,20 @@
   </voice>
 </phrase>
 <phrase>
+  id: LANG_LOOPBACK
+  desc:
+  user: core
+  <source>
+    *: "Loopback mount"
+  </source>
+  <dest>
+    *: "Loopback mount"
+  </dest>
+  <voice>
+    *: "Loopback mount"
+  </voice>
+</phrase>
+<phrase>
   id: LANG_PITCH
   desc: "pitch" in the pitch screen
   user: core
Index: apps/onplay.c
===================================================================
--- apps/onplay.c	(revision 26398)
+++ apps/onplay.c	(working copy)
@@ -63,6 +63,7 @@
 #include "statusbar-skinned.h"
 #include "pitchscreen.h"
 #include "viewport.h"
+#include "loopback.h"
 
 static int context;
 static char* selected_file = NULL;
@@ -1000,6 +1001,14 @@
     return false;
 }
 
+static bool onplay_loopback(void *param)
+{
+    (void)param;
+    int res=loopback_set_file(selected_file);
+    splashf(HZ/2,"%s %smounted",selected_file,res==0?"":"not ");
+    return false;
+}
+
 MENUITEM_FUNCTION(list_viewers_item, 0, ID2P(LANG_ONPLAY_OPEN_WITH),
                   list_viewers, NULL, clipboard_callback, Icon_NOICON);
 MENUITEM_FUNCTION(properties_item, MENU_FUNC_USEPARAM, ID2P(LANG_PROPERTIES),
@@ -1008,6 +1017,9 @@
 MENUITEM_FUNCTION(add_to_faves_item, MENU_FUNC_USEPARAM, ID2P(LANG_ADD_TO_FAVES),
                   onplay_load_plugin, (void *)"shortcuts_append",
                   clipboard_callback, Icon_NOICON);
+MENUITEM_FUNCTION(loopback_item, MENU_FUNC_USEPARAM, ID2P(LANG_LOOPBACK),
+                  onplay_loopback, NULL,
+                  clipboard_callback, Icon_NOICON);
 
 #if LCD_DEPTH > 1
 static bool set_backdrop(void)
@@ -1082,6 +1094,7 @@
                     this_item == &clipboard_cut_item ||
                     this_item == &clipboard_copy_item ||
                     this_item == &properties_item ||
+                    this_item == &loopback_item ||
                     this_item == &add_to_faves_item)
                 {
                     return action;
@@ -1151,6 +1164,7 @@
            &set_recdir_item,
 #endif
            &add_to_faves_item,
+           &loopback_item,
          );
 static int onplaymenu_callback(int action,const struct menu_item_ex *this_item)
 {
Index: firmware/SOURCES
===================================================================
--- firmware/SOURCES	(revision 26398)
+++ firmware/SOURCES	(working copy)
@@ -176,6 +176,9 @@
 #if (CONFIG_STORAGE & STORAGE_RAMDISK)
 drivers/ramdisk.c
 #endif
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+drivers/loopback.c
+#endif
 storage.c
 drivers/fat.c
 #if (CONFIG_STORAGE & STORAGE_MMC) || (CONFIG_STORAGE & STORAGE_SD)
Index: firmware/drivers/loopback.c
===================================================================
--- firmware/drivers/loopback.c	(revision 0)
+++ firmware/drivers/loopback.c	(revision 0)
@@ -0,0 +1,200 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: loopback.c 21933 2009-07-17 22:28:49Z gevaerts $
+ *
+ * Copyright (C) 2008 Frank Gevaerts
+ *
+ * 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 <stdbool.h>
+#include <string.h>
+#include <file.h>
+#include <disk.h>
+
+#include "storage.h"
+#include "kernel.h"
+
+//#define LOGF_ENABLE
+#include "logf.h"
+
+#define SECTOR_SIZE 512
+
+static char loopback_file[MAX_PATH];
+static int loopback_fd=-1;
+static size_t sectors;
+static int driveno;
+
+
+long last_disk_activity = -1;
+
+int loopback_read_sectors(IF_MD2(int drive,)
+                     unsigned long start,
+                     int count,
+                     void* buf)
+{
+#ifdef HAVE_MULTIDRIVE
+    (void)drive; /* unused for now */
+#endif
+    logf("loopback_read_sectors(%d,%d)",start,count);
+    if(start+count>sectors)
+    {
+        logf("beyond end of disk");
+        return -1;
+    }
+    if(lseek(loopback_fd,start*SECTOR_SIZE,SEEK_SET)<0)
+    {
+        logf("lseek failed");
+        return -1;
+    }
+    if(read(loopback_fd,buf,count*SECTOR_SIZE)<0)
+    {
+        logf("read failed");
+        return -1;
+    }
+    return 0;
+}
+
+int loopback_write_sectors(IF_MD2(int drive,)
+                      unsigned long start,
+                      int count,
+                      const void* buf)
+{
+#ifdef HAVE_MULTIDRIVE
+    (void)drive; /* unused for now */
+#endif
+    if(start+count>sectors)
+    {
+        return -1;
+    }
+    if(lseek(loopback_fd,start*SECTOR_SIZE,SEEK_SET)<0)
+    {
+        return -1;
+    }
+    if(write(loopback_fd,buf,count*SECTOR_SIZE)<0)
+    {
+        return -1;
+    }
+    return 0;
+}
+
+int loopback_set_file(char *newfile)
+{
+    strlcpy(loopback_file,newfile,MAX_PATH);
+    loopback_fd=open(loopback_file,O_RDWR);
+    if(loopback_fd<0)
+        return -1;
+    sectors=filesize(loopback_fd)/SECTOR_SIZE;
+    if(disk_mount(driveno)==0)
+        return -2;
+    queue_broadcast(SYS_FS_CHANGED, 0);
+    return 0;
+}
+
+void loopback_clear_file(void)
+{
+    disk_unmount(1); /* release "by force" */
+    queue_broadcast(SYS_FS_CHANGED, 0);
+    loopback_fd=-1;
+}
+
+int loopback_init(void)
+{
+    loopback_fd=-1;
+    return 0;
+}
+
+long loopback_last_disk_activity(void)
+{
+    return last_disk_activity;
+}
+
+void loopback_sleep(void)
+{
+}
+
+void loopback_spin(void)
+{
+}
+
+void loopback_sleepnow(void)
+{
+}
+
+void loopback_enable(bool on)
+{
+    (void)on;
+}
+
+bool loopback_disk_is_active(void)
+{
+    return true;
+}
+
+int loopback_soft_reset(void)
+{
+    return 0;
+}
+
+int loopback_spinup_time(void)
+{
+    return 0;
+}
+
+void loopback_spindown(int seconds)
+{
+    (void)seconds;
+}
+#ifdef STORAGE_GET_INFO
+void loopback_get_info(IF_MD2(int drive,) struct storage_info *info)
+{
+#ifdef HAVE_MULTIDRIVE
+    (void)drive; /* unused for now */
+#endif
+    /* firmware version */
+    info->revision="0.00";
+
+    /* vendor field, need better name? */
+    info->vendor="Rockbox";
+    /* model field, need better name? */
+    info->product=strrchr(loopback_file,'/')+1;
+
+    /* blocks count */
+    info->num_sectors=sectors;
+    info->sector_size=SECTOR_SIZE;
+}
+#endif
+
+#ifdef CONFIG_STORAGE_MULTI
+int loopback_num_drives(int first_drive)
+{
+    driveno=first_drive;
+    
+    return 1;
+}
+#endif
+
+bool loopback_present(IF_MD_NONVOID(int drive))
+{
+#ifdef HAVE_MULTIDRIVE
+    (void)drive;
+#endif
+    return (loopback_fd>=0);
+}
+
+void card_enable_monitoring(bool enable)
+{
+    (void)enable;
+}
Index: firmware/export/hotswap.h
===================================================================
--- firmware/export/hotswap.h	(revision 26398)
+++ firmware/export/hotswap.h	(working copy)
@@ -61,7 +61,7 @@
 #define card_enable_monitoring card_enable_monitoring_target
 #endif
 
-#else /* STORAGE_MMC */
+#elif (CONFIG_STORAGE & STORAGE_MMC)
 
 #include "ata_mmc.h"
 #define card_get_info          mmc_card_info
Index: firmware/export/config.h
===================================================================
--- firmware/export/config.h	(revision 26398)
+++ firmware/export/config.h	(working copy)
@@ -27,11 +27,12 @@
 /* symbolic names for multiple choice configurations: */
 
 /* CONFIG_STORAGE (note these are combineable bit-flags) */
-#define STORAGE_ATA     0x01
-#define STORAGE_MMC     0x02
-#define STORAGE_SD      0x04
-#define STORAGE_NAND    0x08
-#define STORAGE_RAMDISK 0x10
+#define STORAGE_ATA      0x01
+#define STORAGE_MMC      0x02
+#define STORAGE_SD       0x04
+#define STORAGE_NAND     0x08
+#define STORAGE_RAMDISK  0x10
+#define STORAGE_LOOPBACK 0x20
 
 /* CONFIG_TUNER (note these are combineable bit-flags) */
 #define S1A0903X01 0x01 /* Samsung */
Index: firmware/export/storage.h
===================================================================
--- firmware/export/storage.h	(revision 26398)
+++ firmware/export/storage.h	(working copy)
@@ -41,6 +41,9 @@
 #if (CONFIG_STORAGE & STORAGE_RAMDISK)
 #include "ramdisk.h"
 #endif
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+#include "loopback.h"
+#endif
 
 struct storage_info
 {
@@ -182,6 +185,32 @@
             #define storage_removable(drive) ramdisk_removable(IF_MD(drive))
             #define storage_present(drive) ramdisk_present(IF_MD(drive))
         #endif
+    #elif (CONFIG_STORAGE & STORAGE_LOOPBACK)
+        #define STORAGE_FUNCTION(NAME) (loopback_## NAME)
+        #define storage_spindown loopback_spindown
+        #define storage_sleep loopback_sleep
+        #define storage_spin loopback_spin
+
+        #define storage_enable(on) loopback_enable(on)
+        #define storage_sleepnow() loopback_sleepnow()
+        #define storage_disk_is_active() loopback_disk_is_active()
+        #define storage_soft_reset() loopback_soft_reset()
+        #define storage_init() loopback_init()
+        #define storage_close() loopback_close()
+        #ifdef HAVE_STORAGE_FLUSH
+            #define storage_flush() (void)0
+        #endif
+        #define storage_last_disk_activity() loopback_last_disk_activity()
+        #define storage_spinup_time() loopback_spinup_time()
+        #define storage_get_identify() loopback_get_identify()
+
+        #ifdef STORAGE_GET_INFO
+            #define storage_get_info(drive, info) loopback_get_info(IF_MD2(drive,) info)
+        #endif
+        #ifdef HAVE_HOTSWAP
+            #define storage_removable(drive) loopback_removable(IF_MD(drive))
+            #define storage_present(drive) loopback_present(IF_MD(drive))
+        #endif
     #else
         //#error No storage driver!
     #endif
Index: firmware/export/config/ipodvideo.h
===================================================================
--- firmware/export/config/ipodvideo.h	(revision 26398)
+++ firmware/export/config/ipodvideo.h	(working copy)
@@ -11,8 +11,14 @@
 #define MODEL_NUMBER 5
 
 /* define this if you use an ATA controller */
-#define CONFIG_STORAGE STORAGE_ATA
+#define CONFIG_STORAGE (STORAGE_ATA|STORAGE_LOOPBACK)
+#define HAVE_MULTIDRIVE
+#define HAVE_MULTIVOLUME
+#define HAVE_HOTSWAP
+#define NUM_DRIVES 2
+#define HAVE_FAT16SUPPORT
 
+
 /* define this if the ATA controller and method of USB access support LBA48 */
 #define HAVE_LBA48
 
Index: firmware/export/loopback.h
===================================================================
--- firmware/export/loopback.h	(revision 0)
+++ firmware/export/loopback.h	(revision 0)
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: loopback.h 21933 2009-07-17 22:28:49Z gevaerts $
+ *
+ * Copyright (C) 2002 by Alan Korr
+ * Copyright (C) 2008 by Frank Gevaerts
+ *
+ * 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 __LOOPBACK_H__
+#define __LOOPBACK_H__
+
+#include <stdbool.h>
+#include "mv.h" /* for HAVE_MULTIDRIVE or not */
+
+struct storage_info;
+
+void loopback_enable(bool on);
+void loopback_spindown(int seconds);
+void loopback_sleep(void);
+bool loopback_disk_is_active(void);
+int loopback_soft_reset(void);
+int loopback_init(void);
+void loopback_close(void);
+int loopback_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf);
+int loopback_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf);
+void loopback_spin(void);
+void loopback_sleepnow(void);
+int loopback_spinup_time(void);
+
+#ifdef STORAGE_GET_INFO
+void loopback_get_info(IF_MD2(int drive,) struct storage_info *info);
+#endif
+
+long loopback_last_disk_activity(void);
+
+#ifdef CONFIG_STORAGE_MULTI
+int loopback_num_drives(int first_drive);
+#endif
+
+int loopback_set_file(char *newfile);
+void loopback_clear_file(void);
+#endif
+
+#ifdef HAVE_HOTSWAP
+bool loopback_removable(IF_MD_NONVOID(int drive));
+bool loopback_present(IF_MD_NONVOID(int drive));
+#endif
+
Index: firmware/storage.c
===================================================================
--- firmware/storage.c	(revision 26398)
+++ firmware/storage.c	(working copy)
@@ -120,6 +120,11 @@
     case STORAGE_RAMDISK:
         return ramdisk_read_sectors(IF_MD2(ldrive,) start,count,buf);
 #endif
+
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    case STORAGE_LOOPBACK:
+        return loopback_read_sectors(IF_MD2(ldrive,) start,count,buf);
+#endif
     }
     
     return -1;
@@ -166,6 +171,11 @@
     case STORAGE_RAMDISK:
         return ramdisk_write_sectors(IF_MD2(ldrive,)start,count,buf);
 #endif
+
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    case STORAGE_LOOPBACK:
+        return loopback_write_sectors(IF_MD2(ldrive,)start,count,buf);
+#endif
     }
     
     return -1;
@@ -251,6 +261,17 @@
     }
 #endif
 
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    if ((rc=loopback_init())) return rc;
+    
+    int loopback_drives = loopback_num_drives(num_drives);
+    for (i=0; i<loopback_drives; i++)
+    {
+        storage_drivers[num_drives++] =
+            (STORAGE_LOOPBACK<<DRIVER_OFFSET) | (i << DRIVE_OFFSET);
+    }
+#endif
+
     return 0;
 }
 
@@ -276,6 +297,10 @@
 #if (CONFIG_STORAGE & STORAGE_RAMDISK)
     ramdisk_enable(on);
 #endif
+
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    loopback_enable(on);
+#endif
 }
 
 void storage_sleep(void)
@@ -299,6 +324,10 @@
 #if (CONFIG_STORAGE & STORAGE_RAMDISK)
     ramdisk_sleep();
 #endif
+
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    loopback_sleep();
+#endif
 }
 
 void storage_sleepnow(void)
@@ -322,6 +351,10 @@
 #if (CONFIG_STORAGE & STORAGE_RAMDISK)
     ramdisk_sleepnow();
 #endif
+
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    loopback_sleepnow();
+#endif
 }
 
 bool storage_disk_is_active(void)
@@ -346,6 +379,10 @@
     if (ramdisk_disk_is_active()) return true;
 #endif
 
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    if (loopback_disk_is_active()) return true;
+#endif
+
     return false;
 }
 
@@ -373,6 +410,10 @@
     if ((rc=ramdisk_soft_reset())) return rc;
 #endif
 
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    if ((rc=loopback_soft_reset())) return rc;
+#endif
+
     return rc;
 }
 
@@ -426,6 +467,10 @@
 #if (CONFIG_STORAGE & STORAGE_RAMDISK)
     ramdisk_spin();
 #endif
+
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    loopback_spin();
+#endif
 }
 
 void storage_spindown(int seconds)
@@ -449,6 +494,10 @@
 #if (CONFIG_STORAGE & STORAGE_RAMDISK)
     ramdisk_spindown(seconds);
 #endif
+
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    loopback_spindown(seconds);
+#endif
 }
 
 #if (CONFIG_LED == LED_REAL)
@@ -473,6 +522,10 @@
 #if (CONFIG_STORAGE & STORAGE_RAMDISK)
     ramdisk_set_led_enabled(enabled);
 #endif
+
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    loopback_set_led_enabled(enabled);
+#endif
 }
 #endif /* CONFIG_LED == LED_REAL */
 
@@ -506,6 +559,11 @@
     if (t>max) max=t;
 #endif
 
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    t=loopback_last_disk_activity();
+    if (t>max) max=t;
+#endif
+
     return max;
 }
 
@@ -539,6 +597,11 @@
     if (t>max) max=t;
 #endif
 
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    t=loopback_spinup_time();
+    if (t>max) max=t;
+#endif
+
     return max;
 }
 
@@ -574,6 +637,11 @@
     case STORAGE_RAMDISK:
         return ramdisk_get_info(ldrive,info);
 #endif
+
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    case STORAGE_LOOPBACK:
+        return loopback_get_info(ldrive,info);
+#endif
     }
 }
 #endif /* STORAGE_GET_INFO */
@@ -583,6 +651,7 @@
 {
     int driver=(storage_drivers[drive] & DRIVER_MASK)>>DRIVER_OFFSET;
     int ldrive=(storage_drivers[drive] & DRIVE_MASK)>>DRIVE_OFFSET;
+    (void)ldrive;
     
     switch(driver)
     {
@@ -611,6 +680,11 @@
         return false;
 #endif
 
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    case STORAGE_LOOPBACK:
+        ret = true;
+#endif
+
     default:
         return false;
     }
@@ -648,6 +722,11 @@
         return true;
 #endif
 
+#if (CONFIG_STORAGE & STORAGE_LOOPBACK)
+    case STORAGE_LOOPBACK:
+        return loopback_present(ldrive);
+#endif
+
     default:
         return false;
     }
