Settings are now stored in /.rockbox/config.cfg instead of the hidden sector. (FS #6557)


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12093 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/SOURCES b/apps/SOURCES
index 2070732..2304ee7 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -20,6 +20,7 @@
 plugin.c
 screens.c
 settings.c
+settings_list.c
 settings_menu.c
 sound_menu.c
 status.c
diff --git a/apps/filetree.c b/apps/filetree.c
index f10c02b..cd020d0 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -486,7 +486,7 @@
 
             case TREE_ATTR_CFG:
                 gui_syncsplash(0, true, str(LANG_WAIT));
-                if (!settings_load_config(buf))
+                if (!settings_load_config(buf,true))
                     break;
                 gui_syncsplash(HZ, true, str(LANG_SETTINGS_LOADED));
                 break;
diff --git a/apps/main.c b/apps/main.c
index 1361b81..5137ff9 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -247,7 +247,6 @@
     screen_access_init();
     gui_syncstatusbar_init(&statusbars);
     settings_reset();
-    settings_calc_config_sector();
     settings_load(SETTINGS_ALL);
     gui_sync_wps_init();
     settings_apply();
@@ -447,8 +446,6 @@
         }
     }
 
-    settings_calc_config_sector();
-    
 #if defined(SETTINGS_RESET) || (CONFIG_KEYPAD == IPOD_4G_PAD) || \
     (CONFIG_KEYPAD == IRIVER_H10_PAD) || (CONFIG_KEYPAD == GIGABEAT_PAD)
 #ifdef SETTINGS_RESET
diff --git a/apps/recorder/radio.h b/apps/recorder/radio.h
index 439061e..a4f9f1a 100644
--- a/apps/recorder/radio.h
+++ b/apps/recorder/radio.h
@@ -18,7 +18,6 @@
  ****************************************************************************/
 #ifndef RADIO_H
 #define RADIO_H
-#define FMPRESET_PATH ROCKBOX_DIR "/fmpresets"
 
 #ifndef FMRADIO_H
 #include "fmradio.h"
diff --git a/apps/settings.c b/apps/settings.c
index 4ef2f14..01ede41 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -25,6 +25,7 @@
 #include "kernel.h"
 #include "thread.h"
 #include "action.h"
+#include "crc32.h"
 #include "settings.h"
 #include "disk.h"
 #include "panic.h"
@@ -72,6 +73,7 @@
 #include "statusbar.h"
 #include "splash.h"
 #include "list.h"
+#include "settings_list.h"
 #if LCD_DEPTH > 1
 #include "backdrop.h"
 #endif
@@ -100,9 +102,7 @@
 #include "eq_menu.h"
 #endif
 
-#define CONFIG_BLOCK_VERSION 59
-#define CONFIG_BLOCK_SIZE 512
-#define RTC_BLOCK_SIZE 44
+#define NVRAM_BLOCK_SIZE 44
 
 #ifdef HAVE_LCD_BITMAP
 #define MAX_LINES 10
@@ -115,644 +115,115 @@
 #endif
 
 long lasttime = 0;
-static long config_sector = 0;  /* mark uninitialized */
-static unsigned char config_block[CONFIG_BLOCK_SIZE];
 
-
-/* descriptor for a configuration value */
-/* (watch the struct packing and member sizes to keep this small) */
-struct bit_entry
-{
-    /* how many bits within the bitfield (1-32), MSB set if value is signed */
-    unsigned char bit_size; /* min 6+1 bit */
-    /* how many bytes in the global_settings struct (1,2,4) */
-    unsigned char byte_size; /* min 3 bits */
-    /* store position in global_settings struct */
-    short settings_offset; /* min 9 bit, better 10 */
-    /* default value */
-    int default_val; /* min 15 bit */
-    /* variable name in a .cfg file, NULL if not to be saved */
-    const char* cfg_name;
-    /* set of values, "rgb" for a color, or NULL for a numerical value */
-    const char* cfg_val;
-};
-
-/********************************************
-
-Config block as saved on the battery-packed RTC user RAM memory block
-of 44 bytes, starting at offset 0x14 of the RTC memory space.
-
-offset  abs
-0x00    0x14    "Roc"   header signature: 0x52 0x6f 0x63
-0x03    0x17    <version byte: 0x0>
-0x04    0x18    start of bit-table
-...
-0x28,0x29 unused, not reachable by set_bits() without disturbing the next 2
-0x2A,0x2B <checksum 2 bytes: xor of 0x00-0x29>
-
-Config memory is reset to 0xff and initialized with 'factory defaults' if
-a valid header & checksum is not found. Config version number is only
-increased when information is _relocated_ or space is _reused_ so that old
-versions can read and modify configuration changed by new versions.
-Memory locations not used by a given version should not be
-modified unless the header & checksum test fails.
-
-Rest of config block, only saved to disk:
-0x2C  start of 2nd bit-table
-...
-0xA4  (char[20]) FMR Preset file
-0xB8  (char[20]) WPS file
-0xCC  (char[20]) Lang file
-0xE0  (char[20]) Font file
-...   (char[20]) RWPS file (on targets supporting a Remote WPS)
-...   (char[20]) Main backdrop file (on color LCD targets)
-
-... to 0x200  <unused>
-
-*************************************/
-
-/* The persistence of the global_settings members is now controlled by
-   the two tables below, rtc_bits and hd_bits.
-   New values can just be added to the end, it will be backwards
-   compatible. If you however change order, bitsize, etc. of existing
-   entries, you need to bump CONFIG_BLOCK_VERSION to break compatibility.
+/* NVRAM stuff, if the target doesnt have NVRAM it is saved in ROCKBOX_DIR /nvram.bin */
+/* NVRAM is set out as
+[0] 'R'
+[1] 'b'
+[2] version
+[3] stored variable count
+[4-7] crc32 checksum
+[8-NVRAM_BLOCK_SIZE] data
 */
+#define NVRAM_DATA_START 8
+#define NVRAM_FILE ROCKBOX_DIR "/nvram.bin"
+static char nvram_buffer[NVRAM_BLOCK_SIZE];
 
-
-/* convenience macro for both size and offset of global_settings member */
-#define S_O(val) sizeof(global_settings.val), offsetof(struct user_settings, val)
-#define SIGNED 0x80 /* for bitsize value with signed attribute */
-
-/* some sets of values which are used more than once, to save memory */
-static const char off_on[] = "off,on";
-static const char off_on_ask[] = "off,on,ask";
-static const char off_number_spell_hover[] = "off,number,spell,hover";
-#ifdef HAVE_LCD_BITMAP
-static const char graphic_numeric[] = "graphic,numeric";
-#endif
-
-#ifdef HAVE_RECORDING
-/* keep synchronous to trig_durations and
-   trigger_times in settings_apply_trigger */
-static const char trig_durations_conf [] =
-                  "0s,1s,2s,5s,10s,15s,20s,25s,30s,1min,2min,5min,10min";
-#endif
-
-#if defined(CONFIG_BACKLIGHT)
-static const char backlight_times_conf [] =
-                  "off,on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90";
-#endif
-
-/* the part of the settings which ends up in the RTC RAM, where available
-   (those we either need early, save frequently, or without spinup) */
-static const struct bit_entry rtc_bits[] =
+static bool read_nvram_data(char* buf, int max_len)
 {
-    /* placeholder, containing the size information */
-    {9, 0, 0, 0, NULL, NULL }, /* 9 bit to tell how far this is populated */
-
-    /* # of bits, offset+size, default, .cfg name, .cfg values */
-    /* sound */
-#if CONFIG_CODEC == MAS3507D
-    {8 | SIGNED, S_O(volume), -18, "volume", NULL }, /* -78...+18 */
+    unsigned crc32 = 0xffffffff;
+    int var_count = 0, i = 0, buf_pos = 0;
+#ifndef HAVE_RTC_RAM
+    int fd = open(NVRAM_FILE,O_RDONLY);
+    if (fd < 0)
+        return false;
+    memset(buf,0,max_len);
+    if (read(fd,buf,max_len) < 8) /* min is 8 bytes,magic, ver, vars, crc32 */
+        return false;
+    close(fd);
 #else
-    {8 | SIGNED, S_O(volume), -25, "volume", NULL }, /* -100...+12 / -84...0 */
+    memset(buf,0,max_len);
+    /* read rtc block */
+    for (i=0; i < max_len; i++ )
+        buf[i] = rtc_read(0x14+i);
 #endif
-    {8 | SIGNED, S_O(balance), 0, "balance", NULL }, /* -100...100 */
-#if CONFIG_CODEC != SWCODEC /* any MAS */
-    {5 | SIGNED, S_O(bass), 0, "bass", NULL }, /* -15..+15 / -12..+12 */
-    {5 | SIGNED, S_O(treble), 0, "treble", NULL }, /* -15..+15 / -12..+12 */
-#elif defined HAVE_UDA1380
-    {5, S_O(bass), 0, "bass", NULL }, /* 0..+24 */
-    {3, S_O(treble), 0, "treble", NULL }, /* 0..+6 */
-#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
-    || defined(HAVE_WM8731) || defined(HAVE_WM8721) \
-    || defined(HAVE_WM8751)
-    {5 | SIGNED, S_O(bass), 0, "bass", NULL }, /* -6..+9 */
-    {5 | SIGNED, S_O(treble), 0, "treble", NULL }, /* -6..+9 */
-#endif
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    {5, S_O(loudness), 0, "loudness", NULL }, /* 0...17 */
-    {3, S_O(avc), 0, "auto volume", "off,20ms,2,4,8" },
-    {1, S_O(superbass), false, "superbass", off_on },
-#endif
-    {3, S_O(channel_config), 0, "channels",
-        "stereo,mono,custom,mono left,mono right,karaoke" },
-    {8, S_O(stereo_width), 100, "stereo width", NULL},
-    /* playback */
-    {1, S_O(resume), false, "resume", off_on },
-    {1, S_O(playlist_shuffle), false, "shuffle", off_on },
-    {16 | SIGNED, S_O(resume_index), -1, NULL, NULL },
-    {16 | SIGNED, S_O(resume_first_index), 0, NULL, NULL },
-    {32 | SIGNED, S_O(resume_offset), -1, NULL, NULL },
-    {32 | SIGNED, S_O(resume_seed), -1, NULL, NULL },
-    {3, S_O(repeat_mode), REPEAT_ALL, "repeat", "off,all,one,shuffle,ab" },
-    /* LCD */
-#ifdef HAVE_LCD_CONTRAST
-    {6, S_O(contrast), DEFAULT_CONTRAST_SETTING, "contrast", NULL },
-#endif
-#ifdef CONFIG_BACKLIGHT
-    {5, S_O(backlight_timeout), 6, "backlight timeout", backlight_times_conf },
-#ifdef CONFIG_CHARGING
-    {5, S_O(backlight_timeout_plugged), 11, "backlight timeout plugged",
-        backlight_times_conf },
-#endif
-#endif /* CONFIG_BACKLIGHT */
-#ifdef HAVE_LCD_BITMAP
-    {1, S_O(invert), false, "invert", off_on },
-    {1, S_O(flip_display), false, "flip display", off_on },
-    /* display */
-    {1, S_O(invert_cursor), true, "invert cursor", off_on },
-    {1, S_O(statusbar), true, "statusbar", off_on },
-    {1, S_O(scrollbar), true, "scrollbar", off_on },
-#if CONFIG_KEYPAD == RECORDER_PAD
-    {1, S_O(buttonbar), true, "buttonbar", off_on },
-#endif
-    {1, S_O(volume_type), 0, "volume display", graphic_numeric },
-    {1, S_O(battery_display), 0, "battery display", graphic_numeric },
-    {1, S_O(timeformat), 0, "time format", "24hour,12hour" },
-#endif /* HAVE_LCD_BITMAP */
-    {1, S_O(show_icons), true, "show icons", off_on },
-    /* system */
-    {4, S_O(poweroff), 10,
-        "idle poweroff", "off,1,2,3,4,5,6,7,8,9,10,15,30,45,60" },
-    {18, S_O(runtime), 0, NULL, NULL },
-    {18, S_O(topruntime), 0, NULL, NULL },
-#if MEM > 1
-    {15, S_O(max_files_in_playlist), 10000,
-        "max files in playlist", NULL }, /* 1000...20000 */
-    {14, S_O(max_files_in_dir), 400,
-        "max files in dir", NULL }, /* 50...10000 */
-#else
-    {15, S_O(max_files_in_playlist), 1000,
-        "max files in playlist", NULL }, /* 1000...20000 */
-    {14, S_O(max_files_in_dir), 200,
-        "max files in dir", NULL }, /* 50...10000 */
-#endif
-    /* battery */
-    {12, S_O(battery_capacity), BATTERY_CAPACITY_DEFAULT, "battery capacity",
-         NULL }, /* 1500...3200 for NiMH, 2200...3200 for LiIon,
-                     500...1500 for Alkaline */
-#ifdef CONFIG_CHARGING
-    {1, S_O(car_adapter_mode), false, "car adapter mode", off_on },
-#endif
-    /* tuner */
-#ifdef CONFIG_TUNER
-    {1, S_O(fm_force_mono), false, "force fm mono", off_on },
-    {9, S_O(last_frequency), 0, NULL, NULL }, /* Default: MIN_FREQ */
-#endif
-
-#if BATTERY_TYPES_COUNT > 1
-    {1, S_O(battery_type), 0, "battery type", "alkaline,nimh" },
-#endif
-
-#ifdef HAVE_REMOTE_LCD
-    /* remote lcd */
-    {6, S_O(remote_contrast), DEFAULT_REMOTE_CONTRAST_SETTING,
-        "remote contrast", NULL },
-    {1, S_O(remote_invert), false, "remote invert", off_on },
-    {1, S_O(remote_flip_display), false, "remote flip display", off_on },
-    {5, S_O(remote_backlight_timeout), 6, "remote backlight timeout",
-        backlight_times_conf },
-#ifdef CONFIG_CHARGING
-    {5, S_O(remote_backlight_timeout_plugged), 11,
-        "remote backlight timeout plugged", backlight_times_conf },
-#endif
-#ifdef HAVE_REMOTE_LCD_TICKING
-    {1, S_O(remote_reduce_ticking), false, "remote reduce ticking", off_on },
-#endif
-#endif
-
-#ifdef CONFIG_BACKLIGHT
-    {1, S_O(bl_filter_first_keypress), false,
-            "backlight filters first keypress", off_on },
-#ifdef HAVE_REMOTE_LCD
-    {1, S_O(remote_bl_filter_first_keypress), false,
-            "backlight filters first remote keypress", off_on },
-#endif
-#endif /* CONFIG_BACKLIGHT */
-
-    /* new stuff to be added here */
-    /* If values are just added to the end, no need to bump the version. */
-
-    /* Current sum of bits: 277 (worst case, but w/o remote lcd) */
-    /* Sum of all bit sizes must not grow beyond 288! */
-};
-
-
-/* the part of the settings which ends up in HD sector only */
-static const struct bit_entry hd_bits[] =
-{
-    /* This table starts after the 44 RTC bytes = 352 bits. */
-    /* Here we need 11 bits to tell how far this is populated. */
-
-    /* placeholder, containing the size information */
-    {11, 0, 0, 0, NULL, NULL }, /* 11 bit to tell how far this is populated */
-
-    /* # of bits, offset+size, default, .cfg name, .cfg values */
-    /* more display */
-#ifdef CONFIG_BACKLIGHT
-    {1, S_O(caption_backlight), false, "caption backlight", off_on },
-#endif
-#ifdef HAVE_REMOTE_LCD
-    {1, S_O(remote_caption_backlight), false,
-        "remote caption backlight", off_on },
-#endif
-#ifdef HAVE_BACKLIGHT_BRIGHTNESS
-    {6, S_O(brightness), DEFAULT_BRIGHTNESS_SETTING, "brightness", NULL },
-#endif
-#ifdef HAVE_BACKLIGHT_PWM_FADING
-    /* backlight fading */
-    {2, S_O(backlight_fade_in), 1, "backlight fade in", "off,500ms,1s,2s"},
-    {3, S_O(backlight_fade_out), 3, "backlight fade out",
-        "off,500ms,1s,2s,3s,4s,5s,10s"},
-#endif
-
-    {4, S_O(scroll_speed), 9, "scroll speed", NULL }, /* 0...15 */
-    {8, S_O(scroll_delay), 100, "scroll delay", NULL }, /* 0...250 */
-    {8, S_O(bidir_limit), 50, "bidir limit", NULL }, /* 0...200 */
-
-#ifdef HAVE_REMOTE_LCD
-    {4, S_O(remote_scroll_speed), 9, "remote scroll speed", NULL }, /* 0...15 */
-    {8, S_O(remote_scroll_step), 6, "remote scroll step", NULL }, /* 1...160 */
-    {8, S_O(remote_scroll_delay), 100, "remote scroll delay", NULL }, /* 0...250 */
-    {8, S_O(remote_bidir_limit), 50, "remote bidir limit", NULL }, /* 0...200 */
-#endif
-
-#ifdef HAVE_LCD_BITMAP
-    {1, S_O(offset_out_of_view), false, "Screen Scrolls Out Of View", off_on },
-#if LCD_WIDTH > 255
-    {9, S_O(scroll_step), 6, "scroll step", NULL },
-    {9, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
-#elif LCD_WIDTH > 127
-    {8, S_O(scroll_step), 6, "scroll step", NULL },
-    {8, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
-#else
-    {7, S_O(scroll_step), 6, "scroll step", NULL },
-    {7, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
-#endif
-#endif /* HAVE_LCD_BITMAP */
-#ifdef HAVE_LCD_CHARCELLS
-    {3, S_O(jump_scroll), 0, "jump scroll", NULL }, /* 0...5 */
-    {8, S_O(jump_scroll_delay), 50, "jump scroll delay", NULL }, /* 0...250 */
-#endif
-    {1, S_O(scroll_paginated), false, "scroll paginated", off_on },
-
-#ifdef HAVE_LCD_COLOR
-    {LCD_DEPTH,S_O(fg_color),LCD_DEFAULT_FG,"foreground color","rgb"},
-    {LCD_DEPTH,S_O(bg_color),LCD_DEFAULT_BG,"background color","rgb"},
-#endif
-
-    /* more playback */
-    {1, S_O(play_selected), true, "play selected", off_on },
-    {1, S_O(fade_on_stop), true, "volume fade", off_on },
-    {4, S_O(ff_rewind_min_step), FF_REWIND_1000,
-        "scan min step", "1,2,3,4,5,6,8,10,15,20,25,30,45,60" },
-    {4, S_O(ff_rewind_accel), 3, "scan accel", NULL },
-#if CONFIG_CODEC == SWCODEC
-    {3, S_O(buffer_margin), 0, "antiskip",
-        "5s,15s,30s,1min,2min,3min,5min,10min" },
-#else
-    {3, S_O(buffer_margin), 0, "antiskip", NULL },
-#endif
-    /* disk */
-#ifndef HAVE_MMC
-#ifdef HAVE_ATA_POWER_OFF
-    {1, S_O(disk_poweroff), false, "disk poweroff", off_on },
-#endif
-    {8, S_O(disk_spindown), 5, "disk spindown", NULL },
-#endif /* HAVE_MMC */
-
-    /* browser */
-    {3, S_O(dirfilter), SHOW_SUPPORTED,
-        "show files", "all,supported,music,playlists"
-#ifdef HAVE_TAGCACHE
-        ",id3 database"
-#endif
-        },
-    {1, S_O(sort_case), false, "sort case", off_on },
-    {1, S_O(browse_current), false, "follow playlist", off_on },
-    /* playlist */
-    {1, S_O(playlist_viewer_icons), true, "playlist viewer icons", off_on },
-    {1, S_O(playlist_viewer_indices), true,
-        "playlist viewer indices", off_on },
-    {1, S_O(playlist_viewer_track_display), 0,
-        "playlist viewer track display", "track name,full path" },
-    {2, S_O(recursive_dir_insert), RECURSE_OFF,
-        "recursive directory insert", off_on_ask },
-    /* bookmarks */
-    {3, S_O(autocreatebookmark), BOOKMARK_NO, "autocreate bookmarks",
-        "off,on,ask,recent only - on,recent only - ask" },
-    {2, S_O(autoloadbookmark), BOOKMARK_NO,
-        "autoload bookmarks", off_on_ask },
-    {2, S_O(usemrb), BOOKMARK_NO,
-        "use most-recent-bookmarks", "off,on,unique only" },
-#ifdef HAVE_LCD_BITMAP
-    /* peak meter */
-    {5, S_O(peak_meter_clip_hold), 16, "peak meter clip hold", /* 0...25 */
-        "on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90,2min,3min,5min,10min,20min,45min,90min" },
-    {5, S_O(peak_meter_hold), 3, "peak meter hold",
-        "off,200ms,300ms,500ms,1,2,3,4,5,6,7,8,9,10,15,20,30,1min" },
-    {7, S_O(peak_meter_release), 8, "peak meter release", NULL }, /* 0...126 */
-    {1, S_O(peak_meter_dbfs), true, "peak meter dbfs", off_on },
-    {7, S_O(peak_meter_min), 60, "peak meter min", NULL }, /* 0...100 */
-    {7, S_O(peak_meter_max), 0, "peak meter max", NULL }, /* 0...100 */
-#endif
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    {7, S_O(mdb_strength), 0, "mdb strength", NULL},
-    {7, S_O(mdb_harmonics), 0, "mdb harmonics", NULL},
-    {9, S_O(mdb_center), 0, "mdb center", NULL},
-    {9, S_O(mdb_shape), 0, "mdb shape", NULL},
-    {1, S_O(mdb_enable), 0, "mdb enable", off_on},
-#endif
-#if CONFIG_CODEC == MAS3507D
-    {1, S_O(line_in), false, "line in", off_on },
-#endif
-    /* voice */
-    {2, S_O(talk_dir), 0, "talk dir", off_number_spell_hover },
-    {2, S_O(talk_file), 0, "talk file", off_number_spell_hover },
-    {1, S_O(talk_menu), true, "talk menu", off_on },
-
-    {2, S_O(sort_file), 0, "sort files", "alpha,oldest,newest,type" },
-    {2, S_O(sort_dir), 0, "sort dirs", "alpha,oldest,newest" },
-    {1, S_O(id3_v1_first), 0, "id3 tag priority", "v2-v1,v1-v2"},
-
-#ifdef HAVE_RECORDING
-    /* recording */
-    {1, S_O(recscreen_on), false, "recscreen on", off_on },
-    {1, S_O(rec_startup), false, "rec screen on startup", off_on },
-    {4, S_O(rec_timesplit), 0, "rec timesplit", /* 0...15 */
-        "off,00:05,00:10,00:15,00:30,01:00,01:14,01:20,02:00,04:00,06:00,08:00,10:00,12:00,18:00,24:00" },
-    {4, S_O(rec_sizesplit), 0, "rec sizesplit", /* 0...15 */
-        "off,5MB,10MB,15MB,32MB,64MB,75MB,100MB,128MB,256MB,512MB,650MB,700MB,1GB,1.5GB,1.75GB" },
-    {1, S_O(rec_channels), 0, "rec channels", "stereo,mono" },
-    {1, S_O(rec_split_type), 0, "rec split type", "Split, Stop" },
-    {1, S_O(rec_split_method), 0, "rec split method", "Time,Filesize" },
-
+    /* check magic, version */
+    if ((buf[0] != 'R') || (buf[1] != 'b') 
+        || (buf[2] != NVRAM_CONFIG_VERSION))
+        return false;
+    /* check crc32 */
+    crc32 = crc_32(&buf[NVRAM_DATA_START],
+                    max_len-NVRAM_DATA_START-1,0xffffffff);
+    if (memcmp(&crc32,&buf[4],4))
+        return false;
+    /* all good, so read in the settings */
+    var_count = buf[3];
+    buf_pos = NVRAM_DATA_START;
+    for(i=0; (i<nb_settings) && (var_count>0) && (buf_pos<max_len); i++)
     {
-#if defined(HAVE_SPDIF_IN) || defined(HAVE_FMRADIO_IN)
-        2,
-#else
-        1,
-#endif
-        S_O(rec_source), 0 /* 0=mic */, "rec source",
-        "mic,line"
-#ifdef HAVE_SPDIF_IN
-        ",spdif"
-#endif
-#ifdef HAVE_FMRADIO_IN
-        ",fmradio"
-#endif
-    },
-    {5, S_O(rec_prerecord_time), 0, "prerecording time", NULL }, /* 0...30 */
-    {1, S_O(rec_directory), 0, /* rec_base_directory */
-        "rec directory", REC_BASE_DIR ",current" },
-#ifdef CONFIG_BACKLIGHT
-    {2, S_O(cliplight), 0, "cliplight", "off,main,both,remote" },
-#endif
-#if CONFIG_CODEC == MAS3587F
-    {4, S_O(rec_mic_gain), 8, "rec mic gain", NULL },
-    {4, S_O(rec_left_gain), 2 /* 0dB */, "rec left gain", NULL }, /* 0...15 */
-    {4, S_O(rec_right_gain), 2 /* 0dB */, "rec right gain", NULL }, /* 0...15 */
-    {3, S_O(rec_frequency), 0, /* 0=44.1kHz */
-        "rec frequency", "44,48,32,22,24,16" },
-    {3, S_O(rec_quality), 5 /* 192 kBit/s max */, "rec quality", NULL },
-    {1, S_O(rec_editable), false, "editable recordings", off_on },
-#endif /* CONFIG_CODEC == MAS3587F */
-
-#if CONFIG_CODEC == SWCODEC
-#ifdef HAVE_UDA1380
-    {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
-    {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
-    {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
-#elif defined(HAVE_TLV320)
-    /* TLV320 only has no mic boost or 20db mic boost */
-    {1, S_O(rec_mic_gain), 0 /* 0 dB */, "rec mic gain", NULL }, /* 0db or 20db */
-    {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
-    {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
-#elif defined(HAVE_WM8975)
-    {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
-    {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
-    {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
-#elif defined(HAVE_WM8758)
-    {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
-    {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
-    {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
-#elif defined(HAVE_WM8731)
-    {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
-    {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
-    {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
-#endif
-    {REC_FREQ_CFG_NUM_BITS, S_O(rec_frequency), REC_FREQ_DEFAULT,
-        "rec frequency", REC_FREQ_CFG_VAL_LIST },
-    {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT,
-        "rec format", REC_FORMAT_CFG_VAL_LIST },
-    /** Encoder settings start - keep these together **/
-    /* aiff_enc */
-    /* (no settings yet) */
-    /* mp3_enc */
-    {5,S_O(mp3_enc_config.bitrate), MP3_ENC_BITRATE_CFG_DEFAULT,
-        "mp3_enc bitrate", MP3_ENC_BITRATE_CFG_VALUE_LIST },
-    /* wav_enc */
-    /* (no settings yet) */
-    /* wavpack_enc */
-    /* (no settings yet) */
-    /** Encoder settings end **/
-#endif /* CONFIG_CODEC == SWCODEC */
-
-    /* values for the trigger */
-    {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL},
-    {8 | SIGNED, S_O(rec_stop_thres), -45, "trigger stop threshold", NULL},
-    {4, S_O(rec_start_duration), 0, "trigger start duration", trig_durations_conf},
-    {4, S_O(rec_stop_postrec), 2, "trigger stop postrec", trig_durations_conf},
-    {4, S_O(rec_stop_gap), 1, "trigger min gap", trig_durations_conf},
-    {4, S_O(rec_trigger_mode ), 0, "trigger mode", "off,once,repeat"},
-#endif /* HAVE_RECORDING */
-
-#ifdef HAVE_SPDIF_POWER
-    {1, S_O(spdif_enable), false, "spdif enable", off_on},
-#endif
-
-    {2, S_O(next_folder), false, "folder navigation", "off,on,random" },
-    {1, S_O(runtimedb), false, "gather runtime data", off_on },
-
-#if CONFIG_CODEC == SWCODEC
-    {1, S_O(replaygain), false, "replaygain", off_on },
-    {2, S_O(replaygain_type), REPLAYGAIN_ALBUM, "replaygain type",
-        "track,album,track shuffle" },
-    {1, S_O(replaygain_noclip), false, "replaygain noclip", off_on },
-    {8 | SIGNED, S_O(replaygain_preamp), 0, "replaygain preamp", NULL },
-    {2, S_O(beep), 0, "beep", "off,weak,moderate,strong" },
-    {3, S_O(crossfade), 0, "crossfade", "off,shuffle,track skip,shuffle and track skip,always"},
-    {3, S_O(crossfade_fade_in_delay), 0, "crossfade fade in delay", NULL},
-    {3, S_O(crossfade_fade_out_delay), 0, "crossfade fade out delay", NULL},
-    {4, S_O(crossfade_fade_in_duration), 0, "crossfade fade in duration", NULL},
-    {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL},
-    {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"},
-    {1, S_O(crossfeed), false, "crossfeed", off_on },
-    {6, S_O(crossfeed_direct_gain), 15, "crossfeed direct gain", NULL },
-    {7, S_O(crossfeed_cross_gain), 60, "crossfeed cross gain", NULL },
-    {8, S_O(crossfeed_hf_attenuation), 160, "crossfeed hf attenuation", NULL },
-    {11, S_O(crossfeed_hf_cutoff), 700, "crossfeed hf cutoff", NULL },
-
-    /* equalizer */
-    {1, S_O(eq_enabled), false, "eq enabled", off_on },
-    {8, S_O(eq_precut), 0, "eq precut", NULL },
-    /* 0..32768 Hz */
-    {15, S_O(eq_band0_cutoff), 60, "eq band 0 cutoff", NULL },
-    {15, S_O(eq_band1_cutoff), 200, "eq band 1 cutoff", NULL },
-    {15, S_O(eq_band2_cutoff), 800, "eq band 2 cutoff", NULL },
-    {15, S_O(eq_band3_cutoff), 4000, "eq band 3 cutoff", NULL },
-    {15, S_O(eq_band4_cutoff), 12000, "eq band 4 cutoff", NULL },
-    /* 0..64 (or 0.0 to 6.4) */
-    {6, S_O(eq_band0_q), 7, "eq band 0 q", NULL },
-    {6, S_O(eq_band1_q), 10, "eq band 1 q", NULL },
-    {6, S_O(eq_band2_q), 10, "eq band 2 q", NULL },
-    {6, S_O(eq_band3_q), 10, "eq band 3 q", NULL },
-    {6, S_O(eq_band4_q), 7, "eq band 4 q", NULL },
-    /* -240..240 (or -24db to +24db) */
-    {9|SIGNED, S_O(eq_band0_gain), 0, "eq band 0 gain", NULL },
-    {9|SIGNED, S_O(eq_band1_gain), 0, "eq band 1 gain", NULL },
-    {9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL },
-    {9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL },
-    {9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL },
-
-    /* dithering */
-    {1, S_O(dithering_enabled), false, "dithering enabled", off_on },
-#endif
-
-#ifdef HAVE_DIRCACHE
-    {1, S_O(dircache), false, "dircache", off_on },
-    {22, S_O(dircache_size), 0, NULL, NULL },
-#endif
-
-#ifdef HAVE_TAGCACHE
-#ifdef HAVE_TC_RAMCACHE
-    {1, S_O(tagcache_ram), 0, "tagcache_ram", off_on },
-#endif
-    {1, S_O(tagcache_autoupdate), 0, "tagcache_autoupdate", off_on },
-#endif
-
-    {4, S_O(default_codepage), 0, "default codepage",
-        "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,iso8859-9,iso8859-2,sjis,gb2312,ksx1001,big5,utf-8,cp1256" },
-
-    {1, S_O(warnon_erase_dynplaylist), false,
-        "warn when erasing dynamic playlist", off_on },
-
-#ifdef CONFIG_BACKLIGHT
-#ifdef HAS_BUTTON_HOLD
-    {2, S_O(backlight_on_button_hold), 0, "backlight on button hold",
-        "normal,off,on" },
-#endif
-
-#ifdef HAVE_LCD_SLEEP
-    {4, S_O(lcd_sleep_after_backlight_off), 3,
-        "lcd sleep after backlight off",
-        "always,never,5,10,15,20,30,45,60,90" },
-#endif
-#endif /* CONFIG_BACKLIGHT */
-
-#ifdef HAVE_WM8758
-    {1, S_O(eq_hw_enabled), false, "eq hardware enabled", off_on },
-
-    {2, S_O(eq_hw_band0_cutoff), 1, "eq hardware band 0 cutoff", "80Hz,105Hz,135Hz,175Hz" },
-    {5|SIGNED, S_O(eq_hw_band0_gain), 0, "eq hardware band 0 gain", NULL },
-
-    {2, S_O(eq_hw_band1_center), 1, "eq hardware band 1 center", "230Hz,300Hz,385Hz,500Hz" },
-    {1, S_O(eq_hw_band1_bandwidth), 0, "eq hardware band 1 bandwidth", "narrow,wide" },
-    {5|SIGNED, S_O(eq_hw_band1_gain), 0, "eq hardware band 1 gain", NULL },
-
-    {2, S_O(eq_hw_band2_center), 1, "eq hardware band 2 center", "650Hz,850Hz,1.1kHz,1.4kHz" },
-    {1, S_O(eq_hw_band2_bandwidth), 0, "eq hardware band 2 bandwidth", "narrow,wide" },
-    {5|SIGNED, S_O(eq_hw_band2_gain), 0, "eq hardware band 2 gain", NULL },
-
-    {2, S_O(eq_hw_band3_center), 1, "eq hardware band 3 center", "1.8kHz,2.4kHz,3.2kHz,4.1kHz" },
-    {1, S_O(eq_hw_band3_bandwidth), 0, "eq hardware band 3 bandwidth", "narrow,wide" },
-    {5|SIGNED, S_O(eq_hw_band3_gain), 0, "eq hardware band 3 gain", NULL },
-
-    {2, S_O(eq_hw_band4_cutoff), 1, "eq hardware band 4 cutoff", "5.3kHz,6.9kHz,9kHz,11.7kHz" },
-    {5|SIGNED, S_O(eq_hw_band4_gain), 0, "eq hardware band 4 gain", NULL },
-#endif
-    {1, S_O(hold_lr_for_scroll_in_list), true, "hold_lr_for_scroll_in_list", off_on },
-
-    {2, S_O(show_path_in_browser), 0, "show path in browser", "off,current directory,full path" },
-#ifdef HAVE_AGC
-    {4, S_O(rec_agc_preset_mic), 1, "agc mic preset", NULL}, /* 0...5 */
-    {4, S_O(rec_agc_preset_line), 1, "agc line preset", NULL}, /* 0...5 */
-    {8|SIGNED, S_O(rec_agc_maxgain_mic), 104, "agc maximum mic gain", NULL},
-    {8|SIGNED, S_O(rec_agc_maxgain_line), 96, "agc maximum line gain", NULL},
-    {3, S_O(rec_agc_cliptime), 1, "agc cliptime", "0.2s,0.4s,0.6s,0.8,1s"},
-#endif
-
-#ifdef HAVE_REMOTE_LCD
-#ifdef HAS_REMOTE_BUTTON_HOLD
-    {2, S_O(remote_backlight_on_button_hold), 0, "remote backlight on button hold",
-        "normal,off,on" },
-#endif
-#endif
-
-#ifdef HAVE_HEADPHONE_DETECTION
-    {2, S_O(unplug_mode), 0, "pause on headphone unplug", NULL},
-    {4, S_O(unplug_rw), 0, "rewind duration on pause", NULL},
-    {1, S_O(unplug_autoresume), 0, "disable autoresume if phones not present", off_on },
-#endif
-#ifdef CONFIG_TUNER
-    {2, S_O(fm_region), 0, "fm_region", "eu,us,jp,kr" },
-#endif
-
-    {1, S_O(audioscrobbler), false, "Last.fm Logging", off_on},
-
-    /* If values are just added to the end, no need to bump the version. */
-    /* new stuff to be added at the end */
-#ifdef HAVE_RECORDING
-    {2, S_O(rec_trigger_type), 0, "trigger type", "stop,pause,nf stp"},
-#endif
-
-    /* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
-};
-
-/* helper function to extract n (<=32) bits from an arbitrary position
- * counting from LSB to MSB */
-static uint32_t get_bits(
-    const uint32_t *p, /* the start of the bitfield array */
-    unsigned int from, /* bit no. to start reading from */
-    unsigned int size) /* how many bits to read */
-{
-    unsigned int long_index = from / 32;
-    unsigned int bit_index = from % 32;
-    uint32_t result;
-
-    result = p[long_index] >> bit_index;
-
-    if (bit_index + size > 32)     /* crossing longword boundary */
-        result |= p[long_index+1] << (32 - bit_index);
-
-    result &= 0xFFFFFFFF >> (32 - size);
-
-    return result;
+        int nvram_bytes = (settings[i].flags&F_NVRAM_BYTES_MASK)
+                                >>F_NVRAM_MASK_SHIFT;
+        if (nvram_bytes)
+        {
+            memcpy(settings[i].setting,&buf[buf_pos],nvram_bytes);
+            buf_pos += nvram_bytes;
+            var_count--;
+        }
+    }
+    return true;
 }
-
-/* helper function to set n (<=32) bits to an arbitrary position,
- * counting from LSB to MSB */
-static void set_bits(
-    uint32_t *p,       /* the start of the bitfield array */
-    unsigned int from, /* bit no. to start writing into */
-    unsigned int size, /* how many bits to change */
-    uint32_t value)    /* content (LSBs will be taken) */
+static bool write_nvram_data(char* buf, int max_len)
 {
-    unsigned int long_index = from / 32;
-    unsigned int bit_index = from % 32;
-    uint32_t mask;
-
-    mask = 0xFFFFFFFF >> (32 - size);
-    value &= mask;
-    mask <<= bit_index;
-
-    if (bit_index + size > 32)
-        p[long_index+1] =
-            (p[long_index+1] & (0xFFFFFFFF << (bit_index + size - 32)))
-            | (value >> (32 - bit_index));
-
-    p[long_index] = (p[long_index] & ~mask) | (value << bit_index);
+    unsigned crc32 = 0xffffffff;
+    int i = 0, buf_pos = 0;
+    char var_count = 0;
+#ifndef HAVE_RTC_RAM
+    int fd;
+#endif
+    memset(buf,0,max_len);
+    /* magic, version */
+    buf[0] = 'R'; buf[1] = 'b';
+    buf[2] = NVRAM_CONFIG_VERSION;
+    buf_pos = NVRAM_DATA_START;
+    for(i=0; (i<nb_settings) && (buf_pos<max_len); i++)
+    {
+        int nvram_bytes = (settings[i].flags&F_NVRAM_BYTES_MASK)
+                                >>F_NVRAM_MASK_SHIFT;
+        if (nvram_bytes)
+        {
+            memcpy(&buf[buf_pos],settings[i].setting,nvram_bytes);
+            buf_pos += nvram_bytes;
+            var_count++;
+        }
+    }
+    /* count and crc32 */
+    buf[3] = var_count;
+    crc32 = crc_32(&buf[NVRAM_DATA_START],
+                    max_len-NVRAM_DATA_START-1,0xffffffff);
+    memcpy(&buf[4],&crc32,4);
+#ifndef HAVE_RTC_RAM
+    fd = open(NVRAM_FILE,O_CREAT|O_TRUNC|O_WRONLY);
+    if (fd >= 0)
+    {
+        int len = write(fd,buf,max_len);
+        close(fd);
+        if (len < 8)
+            return false;
+    }
+#else
+    /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
+       that it would write a number of bytes at a time since the RTC chip
+       supports that, but this will have to do for now 8-) */
+    for (i=0; i < NVRAM_BLOCK_SIZE; i++ ) {
+        int r = rtc_write(0x14+i, buf[i]);
+        if (r) {
+            DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
+                    14+i, r );
+            return false;
+        }
+    }
+#endif
+    return true;
 }
 
 #ifdef HAVE_LCD_COLOR
@@ -787,223 +258,89 @@
     return 0;
 }
 #endif
-
-/*
- * Calculates the checksum for the config block and returns it
- */
-
-static unsigned short calculate_config_checksum(const unsigned char* buf)
+bool settings_write_config(char* filename)
 {
-    unsigned int i;
-    unsigned char cksum[2];
-    cksum[0] = cksum[1] = 0;
-
-    for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
-        cksum[0] ^= buf[i];
-        cksum[1] ^= buf[i+1];
-    }
-
-    return (cksum[0] << 8) | cksum[1];
-}
-
-/*
- * initialize the config block buffer
- */
-static void init_config_buffer( void )
-{
-    DEBUGF( "init_config_buffer()\n" );
-
-    /* reset to 0 - all unused */
-    memset(config_block, 0, CONFIG_BLOCK_SIZE);
-    /* insert header */
-    config_block[0] = 'R';
-    config_block[1] = 'o';
-    config_block[2] = 'c';
-    config_block[3] = CONFIG_BLOCK_VERSION;
-}
-
-static bool flush_config_block_callback(void)
-{
-    ata_write_sectors(IF_MV2(0,) config_sector, 1, config_block);
+    int i;
+    int fd;
+    char value[MAX_PATH];
+    fd = open(filename,O_CREAT|O_TRUNC|O_WRONLY);
+    if (fd < 0)
+        return false;
+    fdprintf(fd, "# .cfg file created by rockbox %s - "
+                 "http://www.rockbox.org\r\n\r\n", appsversion);
+    for(i=0; i<nb_settings; i++)
+    {
+        if (settings[i].cfg_name == NULL)
+            continue;
+        switch (settings[i].flags&F_T_MASK)
+        {
+            case F_T_INT:
+            case F_T_UINT:
+#ifdef HAVE_LCD_COLOR
+                if (settings[i].flags&F_RGB)
+                {
+                    int colour = *(int*)settings[i].setting;
+                    snprintf(value,MAX_PATH,"%02x%02x%02x",
+                                (int)RGB_UNPACK_RED(colour),
+                                (int)RGB_UNPACK_GREEN(colour),
+                                (int)RGB_UNPACK_BLUE(colour));
+                }
+                else 
+#endif
+                    if (settings[i].cfg_vals == NULL)
+                {
+                    snprintf(value,MAX_PATH,"%d",*(int*)settings[i].setting);
+                }
+                else
+                {
+                    char *s,*end;
+                    char vals[MAX_PATH];
+                    int val = 0;
+                    strncpy(vals,settings[i].cfg_vals,MAX_PATH);
+                    s = strtok_r(vals,",",&end);
+                    while (s)
+                    {
+                        if (val == *(int*)settings[i].setting)
+                        {
+                            strncpy(value,s,MAX_PATH);
+                            break;
+                        }
+                        val++;
+                        s = strtok_r(NULL,",",&end);
+                    }
+                }
+                break;
+            case F_T_BOOL:
+                strcpy(value,*(bool*)settings[i].setting == true?"on":"off");
+                break;
+            case F_T_CHARPTR:
+            case F_T_UCHARPTR:
+                if (((char*)settings[i].setting)[0] == '\0')
+                    break;
+                if (settings[i].filename_setting->prefix)
+                {
+                    snprintf(value,MAX_PATH,"%s%s%s",
+                        settings[i].filename_setting->prefix,
+                        (char*)settings[i].setting,
+                        settings[i].filename_setting->suffix);
+                }
+                else strncpy(value,(char*)settings[i].setting,
+                                settings[i].filename_setting->max_len);
+                break;
+        } /* switch () */
+        if (value[0])
+            fdprintf(fd,"%s: %s\r\n",settings[i].cfg_name,value);
+        value[0] = '\0';
+    } /* for(...) */
+    close(fd);
     return true;
 }
-/*
- * save the config block buffer to disk or RTC RAM
- */
-static int save_config_buffer( void )
+static bool flush_config_block_callback(void)
 {
-    unsigned short chksum;
-#ifdef HAVE_RTC_RAM
-    unsigned int i;
-#endif
-
-    /* update the checksum in the end of the block before saving */
-    chksum = calculate_config_checksum(config_block);
-    config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
-    config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
-
-#ifdef HAVE_RTC_RAM
-    /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
-       that it would write a number of bytes at a time since the RTC chip
-       supports that, but this will have to do for now 8-) */
-    for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
-        int r = rtc_write(0x14+i, config_block[i]);
-        if (r) {
-            DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
-                    14+i, r );
-            return r;
-        }
-    }
-
-#endif
-
-    if (config_sector != 0)
-        register_ata_idle_func(flush_config_block_callback);
-    else
-        return -1;
-
-    return 0;
-}
-
-/*
- * load the config block buffer from disk or RTC RAM
- */
-static int load_config_buffer(int which)
-{
-    unsigned short chksum;
-    bool correct = false;
-
-
-    DEBUGF( "load_config_buffer()\n" );
-
-    if (which & SETTINGS_HD)
-    {
-        if (config_sector != 0) {
-            ata_read_sectors(IF_MV2(0,) config_sector, 1,  config_block);
-            /* calculate the checksum, check it and the header */
-            chksum = calculate_config_checksum(config_block);
-
-            if (config_block[0] == 'R' &&
-                config_block[1] == 'o' &&
-                config_block[2] == 'c' &&
-                config_block[3] == CONFIG_BLOCK_VERSION &&
-                (chksum >> 8) == config_block[RTC_BLOCK_SIZE - 2] &&
-                (chksum & 0xff) == config_block[RTC_BLOCK_SIZE - 1])
-            {
-                DEBUGF( "load_config_buffer: header & checksum test ok\n" );
-                correct = true;
-            }
-        }
-    }
-
-#ifdef HAVE_RTC_RAM
-    if(!correct)
-    {
-        /* If the disk sector was incorrect, reinit the buffer */
-        memset(config_block, 0, CONFIG_BLOCK_SIZE);
-    }
-
-    if (which & SETTINGS_RTC)
-    {
-        unsigned int i;
-        unsigned char rtc_block[RTC_BLOCK_SIZE];
-
-        /* read rtc block */
-        for (i=0; i < RTC_BLOCK_SIZE; i++ )
-            rtc_block[i] = rtc_read(0x14+i);
-
-        chksum = calculate_config_checksum(rtc_block);
-
-        /* if rtc block is ok, use that */
-        if (rtc_block[0] == 'R' &&
-            rtc_block[1] == 'o' &&
-            rtc_block[2] == 'c' &&
-            rtc_block[3] == CONFIG_BLOCK_VERSION &&
-            (chksum >> 8) == rtc_block[RTC_BLOCK_SIZE - 2] &&
-            (chksum & 0xff) == rtc_block[RTC_BLOCK_SIZE - 1])
-        {
-            memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
-            correct = true;
-        }
-    }
-#endif
-
-    if ( !correct ) {
-        /* if checksum is not valid, clear the config buffer */
-        DEBUGF( "load_config_buffer: header & checksum test failed\n" );
-        init_config_buffer();
-        return -1;
-    }
-
-    return 0;
-}
-
-
-/* helper to save content of global_settings into a bitfield,
-   as described per table */
-static void save_bit_table(const struct bit_entry* p_table, int count, int bitstart)
-{
-    uint32_t *p_bitfield = (uint32_t *)config_block; /* 32 bit addr. */
-    uint32_t value; /* 32 bit content */
-    int i;
-    const struct bit_entry* p_run = p_table; /* start after the size info */
-    int curr_bit = bitstart + p_table->bit_size;
-    count--; /* first is excluded from loop */
-
-    for (i=0; i<count; i++)
-    {
-        p_run++;
-        /* could do a memcpy, but that would be endian-dependent */
-        switch(p_run->byte_size)
-        {
-        case 1:
-            value = ((uint8_t *)&global_settings)[p_run->settings_offset];
-            break;
-        case 2:
-            value = ((uint16_t *)&global_settings)[p_run->settings_offset/2];
-            break;
-        case 4:
-            value = ((uint32_t *)&global_settings)[p_run->settings_offset/4];
-            break;
-        default:
-            DEBUGF( "save_bit_table: illegal size!\n" );
-            continue;
-        }
-        set_bits(p_bitfield, curr_bit, p_run->bit_size & 0x3F, value);
-        curr_bit += p_run->bit_size & 0x3F;
-    }
-    set_bits(p_bitfield, bitstart, p_table->bit_size, /* write size */
-        curr_bit); /* = position after last element */
-}
-
-/*
- * figure out the config sector from the partition table and the
- * mounted file system
- */
-void settings_calc_config_sector(void)
-{
-#ifdef SIMULATOR
-    config_sector = 61;
-#else
-    int i;
-    long partition_start;
-    long sector = 0;
-
-    if (fat_startsector(IF_MV(0)) != 0)    /* There is a partition table */
-    {
-        sector = 61;
-        for (i = 0; i < 4; i++)
-        {
-            partition_start = disk_partinfo(i)->start;
-            if (partition_start != 0 && (partition_start - 2) < sector)
-                sector = partition_start - 2;
-        }
-        if (sector < 0)
-            sector = 0;
-    }
-
-    config_sector = sector;
-#endif
+    bool r1, r2;
+    r1 = write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
+    r2 = settings_write_config(CONFIGFILE);
+    return r1 || r2;
 }
 
 /*
@@ -1011,75 +348,34 @@
  */
 int settings_save( void )
 {
-    int i;
+    int elapsed_secs;
 
+    elapsed_secs = (current_tick - lasttime) / HZ;
+    global_settings.runtime += elapsed_secs;
+    lasttime += (elapsed_secs * HZ);
+
+    if ( global_settings.runtime > global_settings.topruntime )
+        global_settings.topruntime = global_settings.runtime;
+#ifdef HAVE_RTC_RAM
+    /* this will be done in the ata_callback if
+       target doesnt have rtc ram */
+    write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
+#endif
+    if(!register_ata_idle_func(flush_config_block_callback))
     {
-        int elapsed_secs;
-
-        elapsed_secs = (current_tick - lasttime) / HZ;
-        global_settings.runtime += elapsed_secs;
-        lasttime += (elapsed_secs * HZ);
-
-        if ( global_settings.runtime > global_settings.topruntime )
-            global_settings.topruntime = global_settings.runtime;
-    }
-
-    /* serialize scalar values into RTC and HD sector, specified via table */
-    save_bit_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), 4*8);
-    save_bit_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), RTC_BLOCK_SIZE*8);
-
-    i = 0xb8;
-    strncpy((char *)&config_block[i], (char *)global_settings.wps_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-    strncpy((char *)&config_block[i], (char *)global_settings.lang_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-    strncpy((char *)&config_block[i], (char *)global_settings.font_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-#ifdef HAVE_REMOTE_LCD
-    strncpy((char *)&config_block[i], (char *)global_settings.rwps_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-#endif
-
-#ifdef CONFIG_TUNER
-    strncpy((char *)&config_block[i], (char *)global_settings.fmr_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-#endif
-
-#if LCD_DEPTH > 1
-    strncpy((char *)&config_block[i], (char *)global_settings.backdrop_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-#endif
-#ifdef HAVE_LCD_BITMAP
-    strncpy((char *)&config_block[i], (char *)global_settings.kbd_file,
-            MAX_FILENAME);
-    i+= MAX_FILENAME;
-#endif
-
-    if(save_config_buffer())
-    {
-        lcd_clear_display();
-#ifdef HAVE_REMOTE_LCD
-        lcd_remote_clear_display();
-#endif
+        int i;
+        FOR_NB_SCREENS(i)
+        {
+            screens[i].clear_display();
 #ifdef HAVE_LCD_CHARCELLS
-        lcd_puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER));
-        lcd_puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER));
+            screens[i].puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER));
+            screens[i].puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER));
 #else
-        lcd_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
-        lcd_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
-        lcd_update();
-#ifdef HAVE_REMOTE_LCD
-        lcd_remote_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
-        lcd_remote_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
-        lcd_remote_update();
+            screens[i].puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
+            screens[i].puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
+            screens[i].update();
 #endif
-#endif
+        }
         sleep(HZ*2);
         return -1;
     }
@@ -1147,6 +443,7 @@
     int i;
 #endif
 
+    DEBUGF( "settings_apply()\n" );
     sound_settings_apply();
 
     audio_set_buffer_margin(global_settings.buffer_margin);
@@ -1207,8 +504,7 @@
     lcd_set_invert_display(global_settings.invert);
     lcd_set_flip(global_settings.flip_display);
     button_set_flip(global_settings.flip_display);
-    if(global_settings.invert || global_settings.flip_display)
-        lcd_update(); /* refresh after flipping the screen */
+    lcd_update(); /* refresh after flipping the screen */
     settings_apply_pm_range();
     peak_meter_init_times(
         global_settings.peak_meter_release, global_settings.peak_meter_hold,
@@ -1239,7 +535,6 @@
         unload_main_backdrop();
     }
     show_main_backdrop();
-
 #endif
 
 #ifdef HAVE_LCD_COLOR
@@ -1344,131 +639,16 @@
 #endif
 }
 
-
-/* helper to load global_settings from a bitfield, as described per table */
-static void load_bit_table(const struct bit_entry* p_table, int count, int bitstart)
-{
-    uint32_t *p_bitfield = (uint32_t *)config_block; /* 32 bit addr. */
-    uint32_t value; /* 32 bit content */
-    int i;
-    int maxbit; /* how many bits are valid in the saved part */
-    const struct bit_entry* p_run = p_table; /* start after the size info */
-    count--; /* first is excluded from loop */
-    maxbit = get_bits(p_bitfield, bitstart, p_table->bit_size);
-    bitstart += p_table->bit_size;
-
-    for (i=0; i<count; i++)
-    {
-        int size;
-        p_run++;
-
-        size = p_run->bit_size & 0x3F; /* mask off abused bits */
-        if (bitstart + size > maxbit)
-            break; /* exit if this is not valid any more in bitfield */
-
-        value = get_bits(p_bitfield, bitstart, size);
-        bitstart += size;
-        if (p_run->bit_size & SIGNED)
-        {   // sign extend the read value
-            unsigned long mask = 0xFFFFFFFF << (size - 1);
-            if (value & mask) /* true if MSB of value is set */
-                value |= mask;
-        }
-
-        /* could do a memcpy, but that would be endian-dependent */
-        switch(p_run->byte_size)
-        {
-        case 1:
-            ((uint8_t *)&global_settings)[p_run->settings_offset] =
-                (unsigned char)value;
-            break;
-        case 2:
-            ((uint16_t *)&global_settings)[p_run->settings_offset/2] =
-                (unsigned short)value;
-            break;
-        case 4:
-            ((uint32_t *)&global_settings)[p_run->settings_offset/4] =
-                (unsigned int)value;
-            break;
-        default:
-            DEBUGF( "load_bit_table: illegal size!\n" );
-            continue;
-        }
-    }
-}
-
-
 /*
  * load settings from disk or RTC RAM
  */
 void settings_load(int which)
 {
-    int i;
     DEBUGF( "reload_all_settings()\n" );
-
-    /* load the buffer from the RTC (resets it to all-unused if the block
-       is invalid) and decode the settings which are set in the block */
-    if (!load_config_buffer(which))
-    {
-        /* load scalar values from RTC and HD sector, specified via table */
-        if (which & SETTINGS_RTC)
-        {
-            load_bit_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), 4*8);
-        }
-        if (which & SETTINGS_HD)
-        {
-            load_bit_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]),
-                RTC_BLOCK_SIZE*8);
-        }
-
-#ifdef HAVE_RECORDING
-    global_settings.recscreen_on = false;
-#endif
-
-#ifdef HAVE_LCD_CONTRAST
-        if ( global_settings.contrast < MIN_CONTRAST_SETTING ||
-             global_settings.contrast > MAX_CONTRAST_SETTING )
-            global_settings.contrast = lcd_default_contrast();
-#endif
-
-#ifdef HAVE_LCD_REMOTE
-        if (global_settings.remote_contrast < MIN_REMOTE_CONTRAST_SETTING ||
-            global_settings.remote_contrast > MAX_REMOTE_CONTRAST_SETTING )
-            global_settings.remote_contrast = lcd_remote_default_contrast();
-#endif
-        i = 0xb8;
-        strncpy((char *)global_settings.wps_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-        strncpy((char *)global_settings.lang_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-        strncpy((char *)global_settings.font_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#ifdef HAVE_REMOTE_LCD
-        strncpy((char *)global_settings.rwps_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#endif
-
-#ifdef CONFIG_TUNER
-        strncpy((char *)global_settings.fmr_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#endif
-
-#if LCD_DEPTH > 1
-        strncpy((char *)global_settings.backdrop_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#endif
-#ifdef HAVE_LCD_BITMAP
-        strncpy((char *)global_settings.kbd_file, (char *)&config_block[i],
-                MAX_FILENAME);
-        i+= MAX_FILENAME;
-#endif
-    }
+    if (which&SETTINGS_RTC)
+        read_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
+    if (which&SETTINGS_HD)
+        settings_load_config(CONFIGFILE,false);
 }
 
 void set_file(char* filename, char* setting, int maxlen)
@@ -1502,94 +682,13 @@
     settings_save();
 }
 
-/* helper to sort a .cfg file entry into a global_settings member,
-   as described per table. Returns the position if found, else 0. */
-static int load_cfg_table(
-    const struct bit_entry* p_table, /* the table which describes the entries */
-    int count, /* number of entries in the table, including the first */
-    const char* name, /* the item to be searched */
-    const char* value, /* the value which got loaded for that item */
-    int hint) /* position to start looking */
-{
-    int i = hint;
-
-    do
-    {
-        if (p_table[i].cfg_name != NULL && !strcasecmp(name, p_table[i].cfg_name))
-        { /* found */
-            int val = 0;
-            if (p_table[i].cfg_val == NULL)
-            {   /* numerical value, just convert the string */
-                val = atoi(value);
-            }
-#if HAVE_LCD_COLOR
-            else if (!strncasecmp(p_table[i].cfg_val,"rgb",4))
-            {
-                val = hex_to_rgb(value);
-            }
-#endif
-            else
-            {   /* set of string values, find the index */
-                const char* item;
-                const char* run;
-                int len = strlen(value);
-
-                item = run = p_table[i].cfg_val;
-
-                while(1)
-                {
-                    /* count the length of the field */
-                    while (*run != ',' && *run != '\0')
-                        run++;
-
-                    if (!strncasecmp(value, item, MAX(run-item, len)))
-                        break; /* match, exit the search */
-
-                    if (*run == '\0') /* reached the end of the choices */
-                        return i; /* return the position, but don't update */
-
-                    val++; /* count the item up */
-                    run++; /* behind the ',' */
-                    item = run;
-                }
-            }
-
-            /* could do a memcpy, but that would be endian-dependent */
-            switch(p_table[i].byte_size)
-            {
-            case 1:
-                ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
-                    (unsigned char)val;
-                break;
-            case 2:
-                ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
-                    (unsigned short)val;
-                break;
-            case 4:
-                ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
-                    (unsigned int)val;
-                break;
-            default:
-                DEBUGF( "illegal size!" );
-                continue;
-            }
-
-            return i; /* return the position */
-        }
-
-        i++;
-        if (i==count)
-            i=1; /* wraparound */
-    } while (i != hint); /* back where we started, all searched */
-
-    return 0; /* indicate not found */
-}
-
-
-bool settings_load_config(const char* file)
+bool settings_load_config(const char* file, bool apply)
 {
     int fd;
     char line[128];
+    char* name;
+    char* value;
+    int i;
 
     fd = open(file, O_RDONLY);
     if (fd < 0)
@@ -1597,180 +696,91 @@
 
     while (read_line(fd, line, sizeof line) > 0)
     {
-        char* name;
-        char* value;
-        const struct bit_entry* table[2] = { rtc_bits, hd_bits };
-        const int ta_size[2] = {
-            sizeof(rtc_bits)/sizeof(rtc_bits[0]),
-            sizeof(hd_bits)/sizeof(hd_bits[0])
-        };
-        int last_table = 0; /* which table was used last round */
-        int last_pos = 1; /* at which position did we succeed */
-        int pos; /* currently returned position */
-
         if (!settings_parseline(line, &name, &value))
             continue;
 
-        /* check for the string values */
-        if (!strcasecmp(name, "wps")) {
-#if LCD_DEPTH > 1
-            unload_wps_backdrop();
-#endif
-            int fd2;
-            if ((fd2 = open(value, O_RDONLY)) >= 0) {
-                close(fd2);
-                set_file(value, (char *)global_settings.wps_file, MAX_FILENAME);
-            }
-        }
-#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
-        else if (!strcasecmp(name, "rwps")) {
-            int fd2;
-            if ((fd2 = open(value, O_RDONLY)) >= 0) {
-                close(fd2);
-                set_file(value, (char *)global_settings.rwps_file, MAX_FILENAME);
-            }
-        }
-#endif
-        else if (!strcasecmp(name, "lang")) {
-            if (!lang_load(value))
+        for(i=0; i<nb_settings; i++)
+        {
+            if (settings[i].cfg_name == NULL)
+                continue;
+            if (!strcasecmp(name,settings[i].cfg_name))
             {
-                set_file(value, (char *)global_settings.lang_file, MAX_FILENAME);
-                talk_init(); /* use voice of same language */
-            }
-        }
-#ifdef CONFIG_TUNER
-        else if (!strcasecmp(name, "fmr")) {
-            set_file(value, global_settings.fmr_file, MAX_FILENAME);
-        }
-#endif
-#ifdef HAVE_LCD_BITMAP
-        else if (!strcasecmp(name, "font")) {
-            if (font_load(value))
-                set_file(value, (char *)global_settings.font_file, MAX_FILENAME);
-        }
-#endif
-#if LCD_DEPTH > 1
-        else if (!strcasecmp(name, "backdrop")) {
-            if (load_main_backdrop(value)) {
-                set_file(value, (char *)global_settings.backdrop_file, MAX_FILENAME);
-                show_main_backdrop();
-            }
-        }
-#endif
-#ifdef HAVE_LCD_BITMAP
-        else if (!strcasecmp(name, "keyboard")) {
-            if (!load_kbd(value))
-                set_file(value, (char *)global_settings.kbd_file, MAX_FILENAME);
-        }
-#endif
-
-
-        /* check for scalar values, using the two tables */
-        pos = load_cfg_table(table[last_table], ta_size[last_table],
-            name, value, last_pos);
-        if (pos) /* success */
-        {
-            last_pos = pos; /* remember as a position hint for next round */
-            continue;
-        }
-
-        last_table = 1-last_table; /* try other table */
-        last_pos = 1; /* search from start */
-        pos = load_cfg_table(table[last_table], ta_size[last_table],
-            name, value, last_pos);
-        if (pos) /* success */
-        {
-            last_pos = pos; /* remember as a position hint for next round */
-            continue;
-        }
-    }
+                switch (settings[i].flags&F_T_MASK)
+                {
+                    case F_T_INT:
+                    case F_T_UINT:
+#ifdef HAVE_LCD_COLOR
+                        if (settings[i].flags&F_RGB)
+                            *(int*)settings[i].setting = hex_to_rgb(value);
+                        else 
+#endif 
+                            if (settings[i].cfg_vals == NULL)
+                        {
+                            *(int*)settings[i].setting = atoi(value);
+                        }
+                        else
+                        {
+                            char *s,*end;
+                            char vals[MAX_PATH];
+                            int val = 0;
+                            strncpy(vals,settings[i].cfg_vals,MAX_PATH);
+                            s = strtok_r(vals,",",&end);
+                            while (s)
+                            {
+                                if (!strcmp(value,s))
+                                {
+                                    *(int*)settings[i].setting = val;
+                                    break;
+                                }
+                                val++;
+                                s = strtok_r(NULL,",",&end);
+                            }
+                        }
+                        break;
+                    case F_T_BOOL:
+                        *(bool*)settings[i].setting = 
+                                !strncmp(value,"off",3)?false:true;
+                        break;
+                    case F_T_CHARPTR:
+                    case F_T_UCHARPTR:
+                    {
+                        char storage[MAX_PATH];
+                        if (settings[i].filename_setting->prefix)
+                        {
+                            int len = strlen(settings[i].filename_setting->prefix);
+                            if (!strncmp(value,settings[i].filename_setting->prefix,len))
+                            {
+                                strncpy(storage,&value[len],MAX_PATH);
+                            }
+                            else strncpy(storage,value,MAX_PATH);
+                        }
+                        else strncpy(storage,value,MAX_PATH);
+                        if (settings[i].filename_setting->suffix)
+                        {
+                            char *s = strcasestr(storage,settings[i].filename_setting->suffix);
+                            if (s) *s = '\0';
+                        }
+                        strncpy((char*)settings[i].setting,storage,
+                                settings[i].filename_setting->max_len);
+                        ((char*)settings[i].setting)
+                            [settings[i].filename_setting->max_len-1] = '\0';
+                        break;
+                    }
+                }
+                break;
+            } /* if (!strcmp(name,settings[i].cfg_name)) */
+        } /* for(...) */
+    } /* while(...) */
 
     close(fd);
-    settings_apply();
     settings_save();
+    if (apply)
+        settings_apply();
     return true;
 }
 
-
-/* helper to save content of global_settings into a file,
-   as described per table */
-static void save_cfg_table(const struct bit_entry* p_table, int count, int fd)
-{
-    long value; /* 32 bit content */
-    int i;
-    const struct bit_entry* p_run = p_table; /* start after the size info */
-    count--; /* first is excluded from loop */
-
-    for (i=0; i<count; i++)
-    {
-        p_run++;
-
-        if (p_run->cfg_name == NULL)
-            continue; /* this value is not to be saved */
-
-        /* could do a memcpy, but that would be endian-dependent */
-        switch(p_run->byte_size)
-        {
-        case 1:
-            if (p_run->bit_size & SIGNED) /* signed? */
-                value = ((char*)&global_settings)[p_run->settings_offset];
-            else
-                value = ((unsigned char*)&global_settings)[p_run->settings_offset];
-            break;
-        case 2:
-            if (p_run->bit_size & SIGNED) /* signed? */
-                value = ((short*)&global_settings)[p_run->settings_offset/2];
-            else
-                value = ((unsigned short*)&global_settings)[p_run->settings_offset/2];
-            break;
-        case 4:
-            value = ((unsigned int*)&global_settings)[p_run->settings_offset/4];
-            break;
-        default:
-            DEBUGF( "illegal size!" );
-            continue;
-        }
-
-        if (p_run->cfg_val == NULL) /* write as number */
-        {
-            fdprintf(fd, "%s: %ld\r\n", p_run->cfg_name, value);
-        }
-#ifdef HAVE_LCD_COLOR
-        else if (!strcasecmp(p_run->cfg_val, "rgb"))
-        {
-            fdprintf(fd, "%s: %02x%02x%02x\r\n", p_run->cfg_name,
-                                                 (int)RGB_UNPACK_RED(value),
-                                                 (int)RGB_UNPACK_GREEN(value),
-                                                 (int)RGB_UNPACK_BLUE(value));
-        }
-#endif
-        else /* write as item */
-        {
-            const char* p = p_run->cfg_val;
-
-            fdprintf(fd, "%s: ", p_run->cfg_name);
-
-            while(value >= 0)
-            {
-                char c = *p++; /* currently processed char */
-                if (c == ',') /* separator */
-                    value--;
-                else if (c == '\0') /* end of string */
-                    break; /* not found */
-                else if (value == 0) /* the right place */
-                    write(fd, &c, 1); /* char by char, this is lame, OK */
-            }
-
-            fdprintf(fd, "\r\n");
-            if (p_run->cfg_val != off_on) /* explaination for non-bool */
-                fdprintf(fd, "# (possible values: %s)\r\n", p_run->cfg_val);
-        }
-    }
-}
-
 bool settings_save_config(void)
 {
-    int fd;
     char filename[MAX_PATH];
 
     create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2
@@ -1779,11 +789,7 @@
     /* allow user to modify filename */
     while (true) {
         if (!kbd_input(filename, sizeof filename)) {
-            fd = creat(filename, O_WRONLY);
-            if (fd < 0)
-                gui_syncsplash(HZ, true, str(LANG_FAILED));
-            else
-                break;
+            break;
         }
         else {
             gui_syncsplash(HZ, true, str(LANG_MENU_SETTING_CANCEL));
@@ -1791,145 +797,43 @@
         }
     }
 
-    fdprintf(fd, "# .cfg file created by rockbox %s - "
-                 "http://www.rockbox.org\r\n#\r\n#\r\n# wps / rwps / language"
-                 " / font / fmpreset / backdrop \r\n#\r\n", appsversion);
-
-    if (global_settings.wps_file[0] != 0)
-        fdprintf(fd, "wps: %s/%s.wps\r\n", WPS_DIR,
-                 global_settings.wps_file);
-
-#ifdef HAVE_REMOTE_LCD
-    if (global_settings.rwps_file[0] != 0)
-        fdprintf(fd, "rwps: %s/%s.rwps\r\n", WPS_DIR,
-                 global_settings.rwps_file);
-#endif
-
-    if (global_settings.lang_file[0] != 0)
-        fdprintf(fd, "lang: %s/%s.lng\r\n", LANG_DIR,
-                 global_settings.lang_file);
-
-#ifdef HAVE_LCD_BITMAP
-    if (global_settings.font_file[0] != 0)
-        fdprintf(fd, "font: %s/%s.fnt\r\n", FONT_DIR,
-                 global_settings.font_file);
-#endif
-
-#if LCD_DEPTH > 1
-    if (global_settings.backdrop_file[0] != 0)
-        fdprintf(fd, "backdrop: %s/%s.bmp\r\n", BACKDROP_DIR,
-                 global_settings.backdrop_file);
-#endif
-
-#ifdef CONFIG_TUNER
-    if (global_settings.fmr_file[0] != 0)
-        fdprintf(fd, "fmr: %s/%s.fmr\r\n", FMPRESET_PATH,
-                 global_settings.fmr_file);
-#endif
-
-#ifdef HAVE_LCD_BITMAP
-    if (global_settings.kbd_file[0] != 0)
-        fdprintf(fd, "keyboard: %s/%s.kbd\r\n", ROCKBOX_DIR,
-                 global_settings.kbd_file);
-#endif
-
-    /* here's the action: write values to file, specified via table */
-    save_cfg_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), fd);
-    save_cfg_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), fd);
-
-    close(fd);
-
-    gui_syncsplash(HZ, true, str(LANG_SETTINGS_SAVED));
+    if (settings_write_config(filename))
+        gui_syncsplash(HZ, true, str(LANG_SETTINGS_SAVED));
+    else gui_syncsplash(HZ, true, str(LANG_FAILED));
     return true;
 }
 
 
-/* helper to load defaults from table into global_settings members */
-static void default_table(const struct bit_entry* p_table, int count)
-{
-    int i;
-
-    for (i=1; i<count; i++) /* exclude the first, the size placeholder */
-    {
-        /* could do a memcpy, but that would be endian-dependent */
-        switch(p_table[i].byte_size)
-        {
-        case 1:
-            ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
-                (unsigned char)p_table[i].default_val;
-            break;
-        case 2:
-            ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
-                (unsigned short)p_table[i].default_val;
-            break;
-        case 4:
-            ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
-                (unsigned int)p_table[i].default_val;
-            break;
-        default:
-            DEBUGF( "illegal size!" );
-            continue;
-        }
-    }
-}
-
 
 /*
  * reset all settings to their default value
  */
 void settings_reset(void) {
 
+    int i;
     DEBUGF( "settings_reset()\n" );
 
-    /* read defaults from table(s) into global_settings */
-    default_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]));
-    default_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]));
-
-    /* do some special cases not covered by table */
-    global_settings.volume      = sound_default(SOUND_VOLUME);
-    global_settings.balance     = sound_default(SOUND_BALANCE);
-    global_settings.bass        = sound_default(SOUND_BASS);
-    global_settings.treble      = sound_default(SOUND_TREBLE);
-    global_settings.channel_config = sound_default(SOUND_CHANNELS);
-    global_settings.stereo_width = sound_default(SOUND_STEREO_WIDTH);
-#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
-    global_settings.loudness    = sound_default(SOUND_LOUDNESS);
-    global_settings.avc         = sound_default(SOUND_AVC);
-    global_settings.mdb_strength = sound_default(SOUND_MDB_STRENGTH);
-    global_settings.mdb_harmonics = sound_default(SOUND_MDB_HARMONICS);
-    global_settings.mdb_center = sound_default(SOUND_MDB_CENTER);
-    global_settings.mdb_shape = sound_default(SOUND_MDB_SHAPE);
-    global_settings.mdb_enable = sound_default(SOUND_MDB_ENABLE);
-    global_settings.superbass = sound_default(SOUND_SUPERBASS);
-#endif
-#ifdef HAVE_LCD_CONTRAST
-    global_settings.contrast = lcd_default_contrast();
-#endif
-#ifdef HAVE_LCD_REMOTE
-    global_settings.remote_contrast = lcd_remote_default_contrast();
-#endif
-
-#ifdef CONFIG_TUNER
-    global_settings.fmr_file[0] = '\0';
-#endif
-    global_settings.wps_file[0] = '\0';
-#ifdef HAVE_REMOTE_LCD
-    global_settings.rwps_file[0] = '\0';
-#endif
-    global_settings.font_file[0] = '\0';
-    global_settings.lang_file[0] = '\0';
-#if LCD_DEPTH > 1
-    global_settings.backdrop_file[0] = '\0';
-#endif
-#ifdef HAVE_LCD_COLOR
-    global_settings.fg_color = LCD_DEFAULT_FG;
-    global_settings.bg_color = LCD_DEFAULT_BG;
-#endif
-#ifdef HAVE_LCD_BITMAP
-    global_settings.kbd_file[0] = '\0';
-#endif
-    global_settings.hold_lr_for_scroll_in_list = true;
-
+    for(i=0; i<nb_settings; i++)
+    {
+        switch (settings[i].flags&F_T_MASK)
+        {
+            case F_T_INT:
+            case F_T_UINT:
+                if (settings[i].flags&F_T_SOUND)
+                    *(int*)settings[i].setting = 
+                            sound_default(settings[i].sound_setting->setting);
+                else *(int*)settings[i].setting = settings[i].default_val.int_;
+                break;
+            case F_T_BOOL:
+                *(bool*)settings[i].setting = settings[i].default_val.bool_;
+                break;
+            case F_T_CHARPTR:
+            case F_T_UCHARPTR:
+                strncpy((char*)settings[i].setting,
+                        settings[i].default_val.charptr,MAX_FILENAME);
+                break;
+        }
+    } /* for(...) */
 #if defined (HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
     enc_global_settings_reset();
 #endif
diff --git a/apps/settings.h b/apps/settings.h
index b5c673f..eee24f1 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -54,6 +54,9 @@
 #define REC_BASE_DIR "/recordings"
 #define EQS_DIR     ROCKBOX_DIR "/eqs"
 #define CODECS_DIR  ROCKBOX_DIR"/codecs"
+#define FMPRESET_PATH ROCKBOX_DIR "/fmpresets"
+
+#define CONFIGFILE  ROCKBOX_DIR "/config.cfg"
 
 #define MAX_FILENAME 20
 
@@ -547,7 +550,6 @@
 
 /* prototypes */
 
-void settings_calc_config_sector(void);
 int settings_save(void);
 void settings_load(int which);
 void settings_reset(void);
@@ -556,7 +558,7 @@
 void settings_apply_pm_range(void);
 void settings_display(void);
 
-bool settings_load_config(const char* file);
+bool settings_load_config(const char* file, bool apply);
 bool settings_save_config(void);
 bool set_bool_options(const char* string, bool* variable,
                       const char* yes_str, int yes_voice,
diff --git a/apps/settings_list.c b/apps/settings_list.c
new file mode 100644
index 0000000..313524b
--- /dev/null
+++ b/apps/settings_list.c
@@ -0,0 +1,608 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id:  $
+ *
+ * Copyright (C) 2007 Jonathan Gordon
+ *
+ * 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 "config.h"
+#include <stdbool.h>
+
+#include "lang.h"
+#include "lcd.h"
+#include "settings.h"
+#include "settings_list.h"
+#include "sound.h"
+
+/* some sets of values which are used more than once, to save memory */
+static const char off_on[] = "off,on";
+static const char off_on_ask[] = "off,on,ask";
+static const char off_number_spell_hover[] = "off,number,spell,hover";
+#ifdef HAVE_LCD_BITMAP
+static const char graphic_numeric[] = "graphic,numeric";
+#endif
+
+#ifdef HAVE_RECORDING
+/* keep synchronous to trig_durations and
+   trigger_times in settings_apply_trigger */
+static const char trig_durations_conf [] =
+                  "0s,1s,2s,5s,10s,15s,20s,25s,30s,1min,2min,5min,10min";
+/* these should be in the config.h files */
+#if CONFIG_CODEC == MAS3587F
+# define DEFAULT_REC_MIC_GAIN 8
+# define DEFAULT_REC_LEFT_GAIN 2
+# define DEFAULT_REC_RIGHT_GAIN 2
+#elif CONFIG_CODEC == SWCODEC
+# ifdef HAVE_UDA1380
+#  define DEFAULT_REC_MIC_GAIN 16
+#  define DEFAULT_REC_LEFT_GAIN 0
+#  define DEFAULT_REC_RIGHT_GAIN 0
+# elif defined(HAVE_TLV320)
+#  define DEFAULT_REC_MIC_GAIN 0
+#  define DEFAULT_REC_LEFT_GAIN 0
+#  define DEFAULT_REC_RIGHT_GAIN 0
+# elif defined(HAVE_WM8975)
+#  define DEFAULT_REC_MIC_GAIN 16
+#  define DEFAULT_REC_LEFT_GAIN 0
+#  define DEFAULT_REC_RIGHT_GAIN 0
+# elif defined(HAVE_WM8758)
+#  define DEFAULT_REC_MIC_GAIN 16
+#  define DEFAULT_REC_LEFT_GAIN 0
+#  define DEFAULT_REC_RIGHT_GAIN 0
+# elif defined(HAVE_WM8731)
+#  define DEFAULT_REC_MIC_GAIN 16
+#  define DEFAULT_REC_LEFT_GAIN 0
+#  define DEFAULT_REC_RIGHT_GAIN 0
+# endif
+#endif
+
+#endif /* HAVE_RECORDING */
+
+#if defined(CONFIG_BACKLIGHT)
+static const char backlight_times_conf [] =
+                  "off,on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90";
+#endif
+
+
+#define GS(a) &global_settings.a
+
+#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
+/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h
+     and you may need to update it if you edit this file */
+
+#define UNUSED {.RESERVED=NULL}
+#define INT(a) {.int_ = a}
+#define UINT(a) {.uint_ = a}
+#define BOOL(a) {.bool_ = a}
+#define CHARPTR(a) {.charptr = a}
+#define UCHARPTR(a) {.ucharptr = a}
+#define NODEFAULT INT(0)
+
+#define SOUND_SETTING(flags,var,setting) \
+        {flags|F_T_INT|F_T_SOUND, GS(var), NODEFAULT,#var,NULL,\
+            {.sound_setting=(struct sound_setting[]){{setting}}} }
+
+#define BOOL_SETTING(flags,var,default,name,cfgvals,yes,no,opt_cb) \
+        {flags|F_T_BOOL, GS(var), BOOL(default),name,cfgvals,  \
+            {.bool_setting=(struct bool_setting[]){{opt_cb,yes,no}}} }
+
+#define OFFON_SETTING(flags,var,default,name,cb) \
+        {flags|F_T_BOOL, GS(var), BOOL(default),name,off_on,  \
+            {.bool_setting=(struct bool_setting[])             \
+            {{cb,LANG_SET_BOOL_YES,LANG_SET_BOOL_NO}}} }
+
+#define SYSTEM_SETTING(flags,var,default) \
+        {flags|F_T_INT, GS(var), INT(default), NULL, NULL, UNUSED}
+        
+#define FILENAME_SETTING(flags,var,name,default,prefix,suffix,len) \
+        {flags|F_T_UCHARPTR, GS(var), CHARPTR(default),name,NULL,\
+            {.filename_setting=(struct filename_setting[]){{prefix,suffix,len}}} }
+const struct settings_list settings[] = {
+    /* sound settings */
+    SOUND_SETTING(0,volume,SOUND_VOLUME),
+    SOUND_SETTING(0,balance,SOUND_BALANCE),
+    SOUND_SETTING(0,bass,SOUND_BASS),
+    SOUND_SETTING(0,treble,SOUND_TREBLE),
+#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
+    { F_T_INT, GS(loudness), INT(0), "loudness", NULL, UNUSED },
+    { F_T_INT, GS(avc), INT(0), "auto volume", "off,20ms,2,4,8", UNUSED },
+    OFFON_SETTING(0,superbass,false,"superbass",NULL),
+#endif
+    { F_T_INT, GS(channel_config), INT(0), "channels",
+         "stereo,mono,custom,mono left,mono right,karaoke", UNUSED },
+    { F_T_INT, GS(stereo_width), INT(100), "stereo width", NULL, UNUSED },
+    /* playback */
+    OFFON_SETTING(0,resume,false,"resume", NULL),
+    OFFON_SETTING(0,playlist_shuffle,false,"shuffle", NULL),
+    SYSTEM_SETTING(NVRAM(4),resume_index,-1),
+    SYSTEM_SETTING(NVRAM(4),resume_first_index,0),
+    SYSTEM_SETTING(NVRAM(4),resume_offset,-1),
+    SYSTEM_SETTING(NVRAM(4),resume_seed,-1),
+    {F_T_INT, GS(repeat_mode), INT(REPEAT_ALL), "repeat",
+         "off,all,one,shuffle,ab" , UNUSED},
+    /* LCD */
+#ifdef HAVE_LCD_CONTRAST
+    {F_T_INT, GS(contrast), INT(DEFAULT_CONTRAST_SETTING),
+         "contrast", NULL , UNUSED},
+#endif
+#ifdef CONFIG_BACKLIGHT
+    {F_T_INT, GS(backlight_timeout), INT(6),
+        "backlight timeout",backlight_times_conf , UNUSED},
+#ifdef CONFIG_CHARGING
+    {F_T_INT, GS(backlight_timeout_plugged), INT(11),
+        "backlight timeout plugged",backlight_times_conf , UNUSED},
+#endif
+#endif /* CONFIG_BACKLIGHT */
+#ifdef HAVE_LCD_BITMAP
+    OFFON_SETTING(0,invert,false,"invert", NULL),
+    OFFON_SETTING(0,flip_display,false,"flip display", NULL),
+    /* display */
+    OFFON_SETTING(0,invert_cursor,true,"invert cursor", NULL),
+    OFFON_SETTING(0,statusbar,true,"statusbar", NULL),
+    OFFON_SETTING(0,scrollbar,true,"scrollbar", NULL),
+#if CONFIG_KEYPAD == RECORDER_PAD
+    OFFON_SETTING(0,buttonbar,true,"buttonbar", NULL),
+#endif
+    {F_T_INT,GS(volume_type),INT(0),"volume display",graphic_numeric,UNUSED},
+    {F_T_INT,GS(battery_display),INT(0),"battery display",graphic_numeric,UNUSED},
+    {F_T_INT,GS(timeformat),INT(0),"time format","24hour,12hour",UNUSED},
+#endif /* HAVE_LCD_BITMAP */
+    OFFON_SETTING(0,show_icons,true,"show icons", NULL),
+    /* system */
+    {F_T_INT,GS(poweroff),INT(10),"idle poweroff",
+        "off,1,2,3,4,5,6,7,8,9,10,15,30,45,60",UNUSED},
+    SYSTEM_SETTING(NVRAM(4),runtime,0),
+    SYSTEM_SETTING(NVRAM(4),topruntime,0),
+#if MEM > 1
+    {F_T_INT,GS(max_files_in_playlist),INT(10000),
+        "max files in playlist",NULL,UNUSED},
+    {F_T_INT,GS(max_files_in_dir),INT(400),
+        "max files in dir",NULL,UNUSED},
+#else
+    {F_T_INT,GS(max_files_in_playlist),INT(1000),
+        "max files in playlist",NULL,UNUSED},
+    {F_T_INT,GS(max_files_in_dir),INT(200),
+        "max files in dir",NULL,UNUSED},
+#endif
+    {F_T_INT,GS(battery_capacity),INT(BATTERY_CAPACITY_DEFAULT),
+        "battery capacity",NULL,UNUSED},
+#ifdef CONFIG_CHARGING
+    OFFON_SETTING(0,car_adapter_mode,false,"car adapter mode", NULL),
+#endif
+    /* tuner */
+#ifdef CONFIG_TUNER
+    OFFON_SETTING(0,fm_force_mono,false,"force fm mono", NULL),
+    SYSTEM_SETTING(NVRAM(4),last_frequency,0),
+#endif
+
+#if BATTERY_TYPES_COUNT > 1
+    {F_T_INT,GS(battery_type),INT(0),
+        "battery type","alkaline,nimh",UNUSED},
+#endif
+#ifdef HAVE_REMOTE_LCD
+    /* remote lcd */
+    {F_T_INT,GS(remote_contrast),INT(DEFAULT_REMOTE_CONTRAST_SETTING),
+        "remote contrast",NULL,UNUSED},
+    OFFON_SETTING(0,remote_invert,false,"remote invert", NULL),
+    OFFON_SETTING(0,remote_flip_display,false,"remote flip display", NULL),
+    {F_T_INT,GS(remote_backlight_timeout),INT(6),
+        "remote backlight timeout",backlight_times_conf,UNUSED},
+#ifdef CONFIG_CHARGING
+    {F_T_INT,GS(remote_backlight_timeout_plugged),INT(11),
+        "remote backlight timeout plugged",backlight_times_conf,UNUSED},
+#endif
+#ifdef HAVE_REMOTE_LCD_TICKING
+    OFFON_SETTING(0,remote_reduce_ticking,false,"remote reduce ticking", NULL),
+#endif
+#endif
+
+#ifdef CONFIG_BACKLIGHT
+    OFFON_SETTING(0,bl_filter_first_keypress,false,
+        "backlight filters first keypress", NULL),
+#ifdef HAVE_REMOTE_LCD
+    OFFON_SETTING(0,remote_bl_filter_first_keypress,false,
+        "backlight filters first remote keypress", NULL),
+#endif
+#endif /* CONFIG_BACKLIGHT */
+
+/** End of old RTC config block **/
+
+#ifdef CONFIG_BACKLIGHT
+    OFFON_SETTING(0,caption_backlight,false,"caption backlight",NULL),
+#ifdef HAVE_REMOTE_LCD
+    OFFON_SETTING(0,remote_caption_backlight,false,"remote caption backlight",NULL),
+#endif
+#endif /* CONFIG_BACKLIGHT */
+#ifdef HAVE_BACKLIGHT_BRIGHTNESS
+    {F_T_INT,GS(brightness), INT(DEFAULT_BRIGHTNESS_SETTING), "brightness", NULL ,UNUSED},
+#endif
+#ifdef HAVE_BACKLIGHT_PWM_FADING
+    /* backlight fading */
+    {F_T_INT,GS(backlight_fade_in),INT(1),
+        "backlight fade in","off,500ms,1s,2s",UNUSED},
+    {F_T_INT,GS(backlight_fade_out),INT(1),
+        "backlight fade out","off,500ms,1s,2s,3s,4s,5s,10s",UNUSED},
+#endif
+    {F_T_INT,GS(scroll_speed),INT(9),"scroll speed",NULL,UNUSED},
+    {F_T_INT,GS(scroll_delay),INT(100),"scroll delay",NULL,UNUSED},
+    {F_T_INT,GS(bidir_limit),INT(50),"bidir limit",NULL,UNUSED},
+#ifdef HAVE_REMOTE_LCD
+    {F_T_INT,GS(remote_scroll_speed),INT(9),"remote scroll speed",NULL,UNUSED},
+    {F_T_INT,GS(remote_scroll_step),INT(6),"remote scroll step",NULL,UNUSED},
+    {F_T_INT,GS(remote_scroll_delay),INT(100),"remote scroll delay",NULL,UNUSED},
+    {F_T_INT,GS(remote_bidir_limit),INT(50),"remote bidir limit",NULL,UNUSED},
+#endif
+#ifdef HAVE_LCD_BITMAP
+    OFFON_SETTING(0,offset_out_of_view,false,"Screen Scrolls Out Of View",NULL),
+    {F_T_INT,GS(scroll_step),INT(6),"scroll step",NULL,UNUSED},
+    {F_T_INT,GS(screen_scroll_step),INT(16),"screen scroll step",NULL,UNUSED},
+#endif /* HAVE_LCD_BITMAP */
+    OFFON_SETTING(0,scroll_paginated,false,"scroll paginated",NULL),
+#ifdef HAVE_LCD_COLOR
+    {F_T_INT|F_RGB,GS(fg_color),INT(LCD_DEFAULT_FG),"foreground color",NULL,UNUSED},
+    {F_T_INT|F_RGB,GS(bg_color),INT(LCD_DEFAULT_BG),"background color",NULL,UNUSED},
+#endif
+    /* more playback */
+    OFFON_SETTING(0,play_selected,true,"play selected",NULL),
+    OFFON_SETTING(0,fade_on_stop,true,"volume fade",NULL),
+    {F_T_INT,GS(ff_rewind_min_step),INT(FF_REWIND_1000),
+        "scan min step","1,2,3,4,5,6,8,10,15,20,25,30,45,60",UNUSED},
+    {F_T_INT,GS(ff_rewind_accel),INT(3),"scan accel",NULL,UNUSED},
+#if CONFIG_CODEC == SWCODEC
+    {F_T_INT,GS(buffer_margin),INT(0),"antiskip",
+        "5s,15s,30s,1min,2min,3min,5min,10min",UNUSED},
+#else
+    {F_T_INT,GS(buffer_margin),INT(0),"antiskip",NULL,UNUSED},
+#endif
+    /* disk */
+#ifndef HAVE_MMC
+#ifdef HAVE_ATA_POWER_OFF
+    OFFON_SETTING(0,disk_poweroff,false,"disk poweroff",NULL),
+#endif
+    {F_T_INT,GS(disk_spindown),INT(5),"disk spindown",NULL,UNUSED},
+#endif /* HAVE_MMC */
+    /* browser */
+    {F_T_INT,GS(dirfilter),INT(SHOW_SUPPORTED),"show files",
+        "all,supported,music,playlists"
+#ifdef HAVE_TAGCACHE
+        ",id3 database"
+#endif
+       ,UNUSED},
+    OFFON_SETTING(0,sort_case,false,"sort case",NULL),
+    OFFON_SETTING(0,browse_current,false,"follow playlist",NULL),
+    OFFON_SETTING(0,playlist_viewer_icons,true,
+        "playlist viewer icons",NULL),
+    OFFON_SETTING(0,playlist_viewer_indices,true,
+        "playlist viewer indices",NULL),
+    {F_T_INT,GS(recursive_dir_insert),INT(RECURSE_OFF),
+        "recursive directory insert",off_on_ask,UNUSED},
+    /* bookmarks */
+    {F_T_INT,GS(autocreatebookmark),INT(BOOKMARK_NO),"autocreate bookmarks",
+        "off,on,ask,recent only - on,recent only - ask",UNUSED},
+    {F_T_INT,GS(autoloadbookmark),INT(BOOKMARK_NO),
+        "autoload bookmarks",off_on_ask,UNUSED},
+    {F_T_INT,GS(usemrb),INT(BOOKMARK_NO),
+        "use most-recent-bookmarks","off,on,unique only",UNUSED},
+#ifdef HAVE_LCD_BITMAP
+    /* peak meter */
+    {F_T_INT,GS(peak_meter_clip_hold),INT(16),"peak meter clip hold",
+        "on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90,2min"
+        ",3min,5min,10min,20min,45min,90min",UNUSED},
+    {F_T_INT,GS(peak_meter_hold),INT(3),"peak meter hold",
+        "off,200ms,300ms,500ms,1,2,3,4,5,6,7,8,9,10,15,20,30,1min",UNUSED},
+    {F_T_INT,GS(peak_meter_release),INT(8),"peak meter release",NULL,UNUSED},
+    OFFON_SETTING(0,peak_meter_dbfs,true,"peak meter dbfs",NULL),
+    {F_T_INT,GS(peak_meter_min),INT(60),"peak meter min",NULL,UNUSED},
+    {F_T_INT,GS(peak_meter_max),INT(0),"peak meter max",NULL,UNUSED},
+#endif
+#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
+    {F_T_INT,GS(mdb_strength),INT(0),"mdb strength",NULL,UNUSED},
+    {F_T_INT,GS(mdb_harmonics),INT(0),"mdb harmonics",NULL,UNUSED},
+    {F_T_INT,GS(mdb_center),INT(0),"mdb center",NULL,UNUSED},
+    {F_T_INT,GS(mdb_shape),INT(0),"mdb shape",NULL,UNUSED},
+    OFFON_SETTING(0,mdb_enable,false,"mdb enable",NULL),
+#endif
+#if CONFIG_CODEC == MAS3507D
+    OFFON_SETTING(0,line_in,false,"line in",NULL),
+#endif
+    /* voice */
+    {F_T_INT,GS(talk_dir),INT(0),"talk dir",off_number_spell_hover,UNUSED},
+    {F_T_INT,GS(talk_file),INT(0),"talk file",off_number_spell_hover,UNUSED},
+    OFFON_SETTING(0,talk_menu,true,"talk menu",NULL),
+
+    {F_T_INT,GS(sort_file),INT(0),"sort files","alpha,oldest,newest,type",UNUSED},
+    {F_T_INT,GS(sort_dir),INT(0),"sort dirs","alpha,oldest,newest",UNUSED},
+    BOOL_SETTING(0,id3_v1_first,false,"id3 tag priority","v2-v1,v1-v2",
+        LANG_ID3_V2_FIRST,LANG_ID3_V1_FIRST,NULL),
+
+#ifdef HAVE_RECORDING
+    /* recording */
+    OFFON_SETTING(0,recscreen_on,false,"recscreen on",NULL),
+    OFFON_SETTING(0,rec_startup,false,"rec screen on startup",NULL),
+    {F_T_INT,GS(rec_timesplit),INT(0),"rec timesplit",
+        "off,00:05,00:10,00:15,00:30,01:00,01:14,01:20,02:00,"
+        "04:00,06:00,08:00,10:00,12:00,18:00,24:00",UNUSED},
+    {F_T_INT,GS(rec_sizesplit),INT(0),"rec sizesplit",
+        "off,5MB,10MB,15MB,32MB,64MB,75MB,100MB,128MB,"
+        "256MB,512MB,650MB,700MB,1GB,1.5GB,1.75GB",UNUSED},
+    {F_T_INT,GS(rec_channels),INT(0),"rec channels","stereo,mono",UNUSED},
+    {F_T_INT,GS(rec_split_type),INT(0),"rec split type","Split, Stop",UNUSED},
+    {F_T_INT,GS(rec_split_method),INT(0),"rec split method","Time,Filesize",UNUSED},
+    {F_T_INT,GS(rec_source),INT(0),"rec source","mic,line"
+#ifdef HAVE_SPDIF_IN
+        ",spdif"
+#endif
+#ifdef HAVE_FMRADIO_IN
+        ",fmradio"
+#endif
+    ,UNUSED},
+    {F_T_INT,GS(rec_prerecord_time),INT(0),"prerecording time",NULL,UNUSED},
+    {F_T_INT,GS(rec_directory),INT(0),"rec directory",REC_BASE_DIR ",current",UNUSED},
+#ifdef CONFIG_BACKLIGHT
+    {F_T_INT,GS(cliplight),INT(0),"cliplight","off,main,both,remote",UNUSED},
+#endif
+    {F_T_INT,GS(rec_mic_gain),INT(DEFAULT_REC_MIC_GAIN),
+        "rec mic gain",NULL,UNUSED},
+    {F_T_INT,GS(rec_left_gain),INT(DEFAULT_REC_LEFT_GAIN),
+        "rec left gain",NULL,UNUSED},
+    {F_T_INT,GS(rec_right_gain),INT(DEFAULT_REC_RIGHT_GAIN),
+        "rec right gain",NULL,UNUSED},
+#if CONFIG_CODEC == MAS3587F
+    {F_T_INT,GS(rec_frequency),INT(0),"rec frequency","44,48,32,22,24,16",UNUSED},
+    {F_T_INT,GS(rec_quality),INT(5),"rec quality",NULL,UNUSED},
+    OFFON_SETTING(0,rec_editable,false,"editable recordings",NULL),
+#endif /* CONFIG_CODEC == MAS3587F */
+#if CONFIG_CODEC == SWCODEC
+    {F_T_INT,GS(rec_frequency),INT(REC_FREQ_DEFAULT),
+        "rec frequency",REC_FREQ_CFG_VAL_LIST,UNUSED},
+    {F_T_INT,GS(rec_format),INT(REC_FORMAT_DEFAULT),
+        "rec format",REC_FORMAT_CFG_VAL_LIST,UNUSED},
+    /** Encoder settings start - keep these together **/
+    /* aiff_enc */
+    /* (no settings yet) */
+    /* mp3_enc */
+    {F_T_INT,GS(mp3_enc_config.bitrate),INT(MP3_ENC_BITRATE_CFG_DEFAULT),
+        "mp3_enc bitrate",MP3_ENC_BITRATE_CFG_VALUE_LIST,UNUSED},
+    /* wav_enc */
+    /* (no settings yet) */
+    /* wavpack_enc */
+    /* (no settings yet) */
+    /** Encoder settings end **/
+#endif /* CONFIG_CODEC == SWCODEC */
+    /* values for the trigger */
+    {F_T_INT,GS(rec_start_thres),INT(-35),
+        "trigger start threshold",NULL,UNUSED},
+    {F_T_INT,GS(rec_stop_thres),INT(-45),
+        "trigger stop threshold",NULL,UNUSED},
+    {F_T_INT,GS(rec_start_duration),INT(0),
+        "trigger start duration",trig_durations_conf,UNUSED},
+    {F_T_INT,GS(rec_stop_postrec),INT(2),
+        "trigger stop postrec",trig_durations_conf,UNUSED},
+    {F_T_INT,GS(rec_stop_gap),INT(1),
+        "trigger min gap",trig_durations_conf,UNUSED},
+    {F_T_INT,GS(rec_trigger_mode),INT(0),
+        "trigger mode","off,once,repeat",UNUSED},
+#endif /* HAVE_RECORDING */
+
+#ifdef HAVE_SPDIF_POWER
+    OFFON_SETTING(0,spdif_enable,false,"spdif enable",NULL),
+#endif
+    {F_T_INT,GS(next_folder),INT(FOLDER_ADVANCE_OFF),
+        "folder navigation","off,on,random",UNUSED},
+    OFFON_SETTING(0,runtimedb,false,"gather runtime data",NULL),
+
+#if CONFIG_CODEC == SWCODEC
+    OFFON_SETTING(0,replaygain,false,"replaygain",NULL),
+    {F_T_INT,GS(replaygain_type),INT(REPLAYGAIN_ALBUM),
+        "replaygain type","track,album,track shuffle",UNUSED},
+    OFFON_SETTING(0,replaygain_noclip,false,"replaygain noclip",NULL),
+    {F_T_INT,GS(replaygain_preamp),INT(0),"replaygain preamp",NULL,UNUSED},
+    {F_T_INT,GS(beep),INT(0),"beep","off,weak,moderate,strong",UNUSED},
+    {F_T_INT,GS(crossfade),INT(0),"crossfade",
+        "off,shuffle,track skip,shuffle and track skip,always",UNUSED},
+    {F_T_INT,GS(crossfade_fade_in_delay),INT(0),
+        "crossfade fade in delay",NULL,UNUSED},
+    {F_T_INT,GS(crossfade_fade_out_delay),INT(0),
+        "crossfade fade out delay",NULL,UNUSED},
+    {F_T_INT,GS(crossfade_fade_in_duration),INT(0),
+        "crossfade fade in duration",NULL,UNUSED},
+    {F_T_INT,GS(crossfade_fade_out_duration),INT(0),
+        "crossfade fade out duration",NULL,UNUSED},
+    {F_T_INT,GS(crossfade_fade_out_mixmode),INT(0),
+        "crossfade fade out mode","crossfade,mix",UNUSED},
+    {F_T_INT,GS(crossfade),INT(0),"crossfade",
+        "off,shuffle,track skip,shuffle and track skip,always",UNUSED},
+    OFFON_SETTING(0,crossfeed,false,"crossfeed",NULL),
+    {F_T_INT,GS(crossfeed_direct_gain),INT(15),
+        "crossfeed direct gain",NULL,UNUSED},
+    {F_T_INT,GS(crossfeed_cross_gain),INT(60),
+        "crossfeed cross gain",NULL,UNUSED},
+    {F_T_INT,GS(crossfeed_hf_attenuation),INT(160),
+        "crossfeed hf attenuation",NULL,UNUSED},
+    {F_T_INT,GS(crossfeed_hf_cutoff),INT(700),
+        "crossfeed hf cutoff",NULL,UNUSED},
+
+    /* equalizer */
+    OFFON_SETTING(0,eq_enabled,false,"eq enabled",NULL),
+    {F_T_INT,GS(eq_precut),INT(0),
+        "eq precut",NULL,UNUSED},
+    /* 0..32768 Hz */
+    {F_T_INT,GS(eq_band0_cutoff),INT(0),
+        "eq band 0 cutoff",NULL,UNUSED},
+    {F_T_INT,GS(eq_band1_cutoff),INT(200),
+        "eq band 1 cutoff",NULL,UNUSED},
+    {F_T_INT,GS(eq_band2_cutoff),INT(800),
+        "eq band 2 cutoff",NULL,UNUSED},
+    {F_T_INT,GS(eq_band3_cutoff),INT(4000),
+        "eq band 3 cutoff",NULL,UNUSED},
+    {F_T_INT,GS(eq_band4_cutoff),INT(12000),
+        "eq band 4 cutoff",NULL,UNUSED},
+    /* 0..64 (or 0.0 to 6.4) */
+    {F_T_INT,GS(eq_band0_q),INT(7),
+        "eq band 0 q",NULL,UNUSED},
+    {F_T_INT,GS(eq_band1_q),INT(10),
+        "eq band 1 q",NULL,UNUSED},
+    {F_T_INT,GS(eq_band2_q),INT(10),
+        "eq band 2 q",NULL,UNUSED},
+    {F_T_INT,GS(eq_band3_q),INT(10),
+        "eq band 3 q",NULL,UNUSED},
+    {F_T_INT,GS(eq_band4_q),INT(7),
+        "eq band 4 q",NULL,UNUSED},
+    /* -240..240 (or -24db to +24db) */
+    {F_T_INT,GS(eq_band0_gain),INT(0),
+        "eq band 0 gain",NULL,UNUSED},
+    {F_T_INT,GS(eq_band1_gain),INT(0),
+        "eq band 1 gain",NULL,UNUSED},
+    {F_T_INT,GS(eq_band2_gain),INT(0),
+        "eq band 2 gain",NULL,UNUSED},
+    {F_T_INT,GS(eq_band3_gain),INT(0),
+        "eq band 3 gain",NULL,UNUSED},
+    {F_T_INT,GS(eq_band4_gain),INT(0),
+        "eq band 4 gain",NULL,UNUSED},
+
+    /* dithering */
+    OFFON_SETTING(0,dithering_enabled,false,"dithering enabled",NULL),
+#endif
+#ifdef HAVE_DIRCACHE
+    OFFON_SETTING(0,dircache,false,"dircache",NULL),
+    SYSTEM_SETTING(NVRAM(4),dircache_size,0),
+#endif
+
+#ifdef HAVE_TAGCACHE
+#ifdef HAVE_TC_RAMCACHE
+    OFFON_SETTING(0,tagcache_ram,false,"tagcache_ram",NULL),
+#endif
+    OFFON_SETTING(0,tagcache_autoupdate,false,"tagcache_autoupdate",NULL),
+#endif
+
+    {F_T_INT,GS(default_codepage),INT(0),"default codepage",
+        "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,"
+        "iso8859-9,iso8859-2,sjis,gb2312,ksx1001,big5,utf-8,cp1256",UNUSED},
+
+    OFFON_SETTING(0,warnon_erase_dynplaylist,false,
+        "warn when erasing dynamic playlist",NULL),
+
+#ifdef CONFIG_BACKLIGHT
+#ifdef HAS_BUTTON_HOLD
+    {F_T_INT,GS(backlight_on_button_hold),INT(0),
+        "backlight on button hold","normal,off,on",UNUSED},
+#endif
+
+#ifdef HAVE_LCD_SLEEP
+    {F_T_INT,GS(lcd_sleep_after_backlight_off),INT(3),
+        "lcd sleep after backlight off",
+        "always,never,5,10,15,20,30,45,60,90",UNUSED},
+#endif
+#endif /* CONFIG_BACKLIGHT */
+
+#ifdef HAVE_WM8758
+    OFFON_SETTING(0,eq_hw_enabled,false,
+        "eq hardware enabled",NULL),
+
+    {F_T_INT,GS(eq_hw_band0_cutoff),INT(1),
+        "eq hardware band 0 cutoff",
+        "80Hz,105Hz,135Hz,175Hz",UNUSED},
+    {F_T_INT,GS(eq_hw_band0_gain),INT(0),
+        "eq hardware band 0 gain",NULL,UNUSED},
+
+    {F_T_INT,GS(eq_hw_band1_center),INT(1),
+        "eq hardware band 1 center",
+        "230Hz,300Hz,385Hz,500Hz",UNUSED},
+    {F_T_INT,GS(eq_hw_band1_bandwidth),INT(0),
+        "eq hardware band 1 bandwidth","narrow,wide",UNUSED},
+    {F_T_INT,GS(eq_hw_band1_gain),INT(0),
+        "eq hardware band 1 gain",NULL,UNUSED},
+
+    {F_T_INT,GS(eq_hw_band2_center),INT(1),
+        "eq hardware band 2 center",
+        "650Hz,850Hz,1.1kHz,1.4kHz",UNUSED},
+    {F_T_INT,GS(eq_hw_band2_bandwidth),INT(0),
+        "eq hardware band 2 bandwidth","narrow,wide",UNUSED},
+    {F_T_INT,GS(eq_hw_band2_gain),INT(0),
+        "eq hardware band 1 gain",NULL,UNUSED},
+
+    {F_T_INT,GS(eq_hw_band3_center),INT(1),
+        "eq hardware band 3 center",
+        "1.8kHz,2.4kHz,3.2kHz,4.1kHz",UNUSED},
+    {F_T_INT,GS(eq_hw_band3_bandwidth),INT(0),
+        "eq hardware band 3 bandwidth","narrow,wide",UNUSED},
+    {F_T_INT,GS(eq_hw_band3_gain),INT(0),
+        "eq hardware band 3 gain",NULL,UNUSED},
+
+    {F_T_INT,GS(eq_hw_band4_cutoff),INT(1),
+        "eq hardware band 4 cutoff",
+        "5.3kHz,6.9kHz,9kHz,11.7kHz",UNUSED},
+    {F_T_INT,GS(eq_hw_band4_gain),INT(0),
+        "eq hardware band 0 gain",NULL,UNUSED},
+#endif
+
+    OFFON_SETTING(0,hold_lr_for_scroll_in_list,true,
+        "hold_lr_for_scroll_in_list",NULL),
+    {F_T_INT,GS(show_path_in_browser),INT(SHOW_PATH_OFF),
+        "show path in browser","off,current directory,full path",UNUSED},
+
+#ifdef HAVE_AGC
+    {F_T_INT,GS(rec_agc_preset_mic),INT(1),"agc mic preset",NULL,UNUSED},
+    {F_T_INT,GS(rec_agc_preset_line),INT(1),"agc line preset",NULL,UNUSED},
+    {F_T_INT,GS(rec_agc_maxgain_mic),INT(104),
+        "agc maximum mic gain",NULL,UNUSED},
+    {F_T_INT,GS(rec_agc_maxgain_line),INT(96),
+        "agc maximum line gain",NULL,UNUSED},
+    {F_T_INT,GS(rec_agc_cliptime),INT(1),
+        "agc cliptime","0.2s,0.4s,0.6s,0.8,1s",UNUSED},
+#endif
+
+#ifdef HAVE_REMOTE_LCD
+#ifdef HAS_REMOTE_BUTTON_HOLD
+    {F_T_INT,GS(remote_backlight_on_button_hold),INT(0),
+        "remote backlight on button hold","normal,off,on",UNUSED},
+#endif
+#endif
+#ifdef HAVE_HEADPHONE_DETECTION
+    {F_T_INT,GS(unplug_mode),INT(0),"pause on headphone unplug",NULL,UNUSED},
+    {F_T_INT,GS(unplug_rw),INT(0),"rewind duration on pause",NULL,UNUSED},
+    OFFON_SETTING(0,unplug_autoresume,false,
+        "disable autoresume if phones not present",NULL),
+#endif
+#ifdef CONFIG_TUNER
+    {F_T_INT,GS(fm_region),INT(0),"fm_region","eu,us,jp,kr",UNUSED},
+#endif
+
+    OFFON_SETTING(0,audioscrobbler,false,"Last.fm Logging",NULL),
+
+#ifdef HAVE_RECORDING
+    {F_T_INT,GS(rec_trigger_type),INT(0),"trigger type","stop,pause,nf stp",UNUSED},
+#endif
+
+    /** settings not in the old config blocks **/
+#ifdef CONFIG_TUNER
+    FILENAME_SETTING(0,fmr_file,"fmr","",FMPRESET_PATH "/",".fmr",MAX_FILENAME+1),
+#endif
+    FILENAME_SETTING(0,font_file,"font","",FONT_DIR "/",".fnt",MAX_FILENAME+1),
+    FILENAME_SETTING(0,wps_file, "wps","",WPS_DIR "/",".wps",MAX_FILENAME+1),
+    FILENAME_SETTING(0,lang_file,"lang","",LANG_DIR "/",".lng",MAX_FILENAME+1),
+#ifdef HAVE_REMOTE_LCD
+    FILENAME_SETTING(0,rwps_file,"rwps","",WPS_DIR "/",".rwps",MAX_FILENAME+1),
+#endif
+#if LCD_DEPTH > 1
+    FILENAME_SETTING(0,backdrop_file,"backdrop","",BACKDROP_DIR "/",".bmp",MAX_FILENAME+1),
+#endif
+#ifdef HAVE_LCD_BITMAP
+    FILENAME_SETTING(0,lang_file,"kbd","",ROCKBOX_DIR "/",".kbd",MAX_FILENAME+1),
+#endif
+
+};
+
+const int nb_settings = sizeof(settings)/sizeof(*settings);
diff --git a/apps/settings_list.h b/apps/settings_list.h
new file mode 100644
index 0000000..01e8cea
--- /dev/null
+++ b/apps/settings_list.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id:  $
+ *
+ * Copyright (C) 2007 Jonathan Gordon
+ *
+ * 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.
+ *
+ ****************************************************************************/
+#ifndef __SETTINGSLIST_H
+#define __SETTINGSLIST_H
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <limits.h>
+#include "inttypes.h"
+
+union storage_type {
+    int int_;
+    unsigned int uint_;
+    bool bool_;
+    char *charptr;
+    unsigned char *ucharptr;
+};
+/* the variable type for the setting */
+#define F_T_INT      1
+#define F_T_UINT     2
+#define F_T_BOOL     3
+#define F_T_CHARPTR  4
+#define F_T_UCHARPTR 5
+#define F_T_MASK     0x7
+
+struct sound_setting {
+    int setting; /* from the enum in firmware/sound.h */
+};
+#define F_T_SOUND    0x8 /* this variable uses the set_sound stuff,         \
+                            | with one of the above types (usually F_T_INT) \
+                            These settings get the default from sound_default(setting); */
+struct bool_setting {
+    void (*option_callback)(bool);
+    int lang_yes;
+    int lang_no;
+};
+#define F_BOOL_SETTING F_T_BOOL|0x10
+#define F_RGB 0x20
+
+struct int_setting {
+    void (*option_callback)(int);
+    int min;
+    int max;
+    int step;
+};
+#define F_NVRAM_BYTES_MASK     0xE00 /*0-4 bytes can be stored */
+#define F_NVRAM_MASK_SHIFT     9
+#define NVRAM_CONFIG_VERSION 1
+/* Above define should be bumped if
+- a new NVRAM setting is added between 2 other NVRAM settings
+- number of bytes for a NVRAM setting is changed
+- a NVRAM setting is removed
+*/
+
+struct filename_setting {
+    const char* prefix;
+    const char* suffix;
+    int max_len;
+};
+#define F_FILENAME 0x40
+struct settings_list {
+    uint32_t             flags;   /* ____ ____ ____ ____ ____ NNN_ _FRB STTT */
+    void                *setting;
+    union storage_type   default_val;
+    const char          *cfg_name; /* this settings name in the cfg file   */
+    const char          *cfg_vals; /*comma seperated legal values, or NULL */
+                                   /* used with F_T_UCHARPTR this is the folder prefix */
+    union {
+        void *RESERVED; /* to stop compile errors, will be removed */
+        struct sound_setting *sound_setting; /* use F_T_SOUND for this */
+        struct bool_setting  *bool_setting; /* F_BOOL_SETTING */
+        struct filename_setting *filename_setting; /* use F_FILENAME */
+    };
+};
+
+#ifndef PLUGIN
+/* not needed for plugins and just causes compile error,
+   possibly fix proberly later */
+extern const struct settings_list  settings[];
+extern const int nb_settings;
+
+#endif
+
+#endif
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index fef7592..04fd64b 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -1844,6 +1844,7 @@
         case YESNO_YES:
             settings_reset();
             settings_apply();
+            settings_save();
             break;
         case YESNO_NO:
             break;
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 4e41ef2..4dd0fdc 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -81,7 +81,7 @@
 #ifdef HAVE_LBA48
 static bool lba48 = false; /* set for 48 bit addressing */
 #endif
-static long ata_stack[DEFAULT_STACK_SIZE/sizeof(long)];
+static long ata_stack[(DEFAULT_STACK_SIZE*3)/sizeof(long)];
 static const char ata_thread_name[] = "ata";
 static struct event_queue ata_queue;
 static bool initialized = false;
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c
index 7382788..a549624 100644
--- a/firmware/drivers/ata_mmc.c
+++ b/firmware/drivers/ata_mmc.c
@@ -92,9 +92,9 @@
 
 #ifdef HAVE_HOTSWAP
 static bool mmc_monitor_enabled = true;
-static long mmc_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)];
+static long mmc_stack[((DEFAULT_STACK_SIZE*2) + 0x800)/sizeof(long)];
 #else
-static long mmc_stack[DEFAULT_STACK_SIZE/sizeof(long)];
+static long mmc_stack[(DEFAULT_STACK_SIZE*2)/sizeof(long)];
 #endif
 static const char mmc_thread_name[] = "mmc";
 static struct event_queue mmc_queue;