summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/SOURCES2
-rw-r--r--apps/action.c75
-rw-r--r--apps/bookmark.c107
-rw-r--r--apps/codec_thread.c12
-rw-r--r--apps/cuesheet.c61
-rw-r--r--apps/debug_menu.c51
-rw-r--r--apps/enc_config.c2
-rw-r--r--apps/filetree.c36
-rw-r--r--apps/filetypes.c117
-rw-r--r--apps/filetypes.h2
-rw-r--r--apps/gui/bitmap/list-skinned.c3
-rw-r--r--apps/gui/bitmap/list.c76
-rw-r--r--apps/gui/folder_select.c3
-rw-r--r--apps/gui/icon.c64
-rw-r--r--apps/gui/list.c13
-rw-r--r--apps/gui/list.h6
-rw-r--r--apps/gui/mask_select.c62
-rw-r--r--apps/gui/option_select.c16
-rw-r--r--apps/gui/skin_engine/skin_parser.c12
-rw-r--r--apps/gui/skin_engine/skin_tokens.c3
-rw-r--r--apps/gui/statusbar-skinned.c1
-rw-r--r--apps/gui/wps.c5
-rw-r--r--apps/gui/yesno.c35
-rw-r--r--apps/keymaps/keymap-fiiom3k.c14
-rw-r--r--apps/keymaps/keymap-hm60x.c2
-rw-r--r--apps/keymaps/keymap-hm801.c2
-rw-r--r--apps/keymaps/keymap-ihifi.c2
-rw-r--r--apps/keymaps/keymap-ipod.c3
-rw-r--r--apps/keymaps/keymap-m3.c4
-rw-r--r--apps/keymaps/keymap-ma.c2
-rw-r--r--apps/keymaps/keymap-mpio-hd200.c6
-rw-r--r--apps/keymaps/keymap-mpio-hd300.c5
-rw-r--r--apps/keymaps/keymap-sansa-connect.c7
-rw-r--r--apps/keymaps/keymap-shanlingq1.c13
-rw-r--r--apps/keymaps/keymap-touchscreen.c2
-rw-r--r--apps/keymaps/keymap-vibe500.c4
-rw-r--r--apps/keymaps/keymap-x5.c4
-rw-r--r--apps/keymaps/keymap-ypz5.c406
-rw-r--r--apps/lang/dansk.lang14
-rw-r--r--apps/lang/english-us.lang325
-rw-r--r--apps/lang/english.lang154
-rw-r--r--apps/lang/magyar.lang860
-rw-r--r--apps/lang/nederlands.lang406
-rw-r--r--apps/lang/polski.lang126
-rw-r--r--apps/language.c4
-rw-r--r--apps/main.c5
-rw-r--r--apps/menu.c35
-rw-r--r--apps/menus/eq_menu.c36
-rw-r--r--apps/menus/eq_menu.h3
-rw-r--r--apps/misc.c27
-rw-r--r--apps/onplay.c3
-rw-r--r--apps/open_plugin.c333
-rw-r--r--apps/open_plugin.h26
-rw-r--r--apps/playback.c3
-rw-r--r--apps/playlist.c27
-rw-r--r--apps/playlist_catalog.c12
-rw-r--r--apps/playlist_viewer.c6
-rw-r--r--apps/plugin.c6
-rw-r--r--apps/plugin.h9
-rw-r--r--apps/plugins/2048.c11
-rw-r--r--apps/plugins/announce_status.c16
-rw-r--r--apps/plugins/blackjack.c16
-rw-r--r--apps/plugins/bubbles.c4
-rw-r--r--apps/plugins/calculator.c2
-rw-r--r--apps/plugins/chessbox/chessbox.c1
-rw-r--r--apps/plugins/doom/p_ceilng.c3
-rw-r--r--apps/plugins/doom/p_floor.c1
-rw-r--r--apps/plugins/goban/goban.c1
-rw-r--r--apps/plugins/imageviewer/imageviewer.c2
-rw-r--r--apps/plugins/imageviewer/jpeg/jpeg_decoder.c11
-rw-r--r--apps/plugins/invadrox.c10
-rw-r--r--apps/plugins/keybox.c2
-rw-r--r--apps/plugins/lib/SOURCES2
-rw-r--r--apps/plugins/lib/arg_helper.c310
-rw-r--r--apps/plugins/lib/arg_helper.h60
-rw-r--r--apps/plugins/lib/helper.c6
-rw-r--r--apps/plugins/lib/helper.h2
-rw-r--r--apps/plugins/lib/icon_helper.c (renamed from firmware/target/arm/tatung/tpj1022/button-tpj1022.c)43
-rw-r--r--apps/plugins/lib/icon_helper.h (renamed from firmware/target/arm/tatung/tpj1022/backlight-target.h)17
-rw-r--r--apps/plugins/lrcplayer.c5
-rw-r--r--apps/plugins/lua/lauxlib.c6
-rw-r--r--apps/plugins/lua/lcode.c6
-rw-r--r--apps/plugins/lua/lmathlib.c5
-rw-r--r--apps/plugins/lua/lparser.c2
-rwxr-xr-xapps/plugins/lua/rbdefines_helper.pl1
-rw-r--r--apps/plugins/lua/rockaux.c2
-rw-r--r--apps/plugins/lua/rocklua.c12
-rw-r--r--apps/plugins/lua/strftime.c4
-rw-r--r--apps/plugins/lua/tlsf_helper.c2
-rw-r--r--apps/plugins/lua_scripts/return2WPS.lua19
-rw-r--r--apps/plugins/main_menu_config.c2
-rw-r--r--apps/plugins/metronome.c2
-rw-r--r--apps/plugins/mikmod/mikmod.c4
-rw-r--r--apps/plugins/mpegplayer/libmpeg2/header.c1
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.c4
-rw-r--r--apps/plugins/open_plugins.c49
-rw-r--r--apps/plugins/pictureflow/pictureflow.c16
-rw-r--r--apps/plugins/properties.c40
-rw-r--r--apps/plugins/random_folder_advance_config.c51
-rw-r--r--apps/plugins/resistor.c6
-rw-r--r--apps/plugins/rocklife.c1
-rw-r--r--apps/plugins/rockpaint.c1
-rw-r--r--apps/plugins/test_disk.c2
-rw-r--r--apps/plugins/test_viewports.c2
-rw-r--r--apps/plugins/vbrfix.c2
-rw-r--r--apps/recorder/icons.c8
-rw-r--r--apps/recorder/icons.h24
-rw-r--r--apps/recorder/jpeg_common.h4
-rw-r--r--apps/recorder/pcm_record.c48
-rw-r--r--apps/recorder/peakmeter.c13
-rw-r--r--apps/root_menu.c141
-rw-r--r--apps/settings.c39
-rw-r--r--apps/settings_list.c104
-rw-r--r--apps/tagcache.c1448
-rw-r--r--apps/tagcache.h17
-rw-r--r--apps/tagnavi.config84
-rw-r--r--apps/tagtree.c1
-rw-r--r--apps/talk.c72
-rw-r--r--apps/tree.c26
-rw-r--r--apps/usb_keymaps.c1
-rw-r--r--apps/voice_thread.c11
-rw-r--r--bootloader/SOURCES2
-rw-r--r--bootloader/common.c85
-rw-r--r--bootloader/main-pp.c17
-rw-r--r--bootloader/tpj1022.c103
-rw-r--r--bootloader/xduoox3.c155
-rw-r--r--docs/CREDITS1
-rw-r--r--docs/usb-api.md144
-rw-r--r--firmware/SOURCES21
-rw-r--r--firmware/common/adler32.c97
-rw-r--r--firmware/common/crc32.c22
-rw-r--r--firmware/common/disk.c7
-rw-r--r--firmware/common/file_internal.c13
-rw-r--r--firmware/common/inflate.c759
-rw-r--r--firmware/common/pathfuncs.c51
-rw-r--r--firmware/common/vuprintf.c1
-rw-r--r--firmware/core_alloc.c19
-rw-r--r--firmware/drivers/audio/ak4376.c22
-rw-r--r--firmware/drivers/audio/eros_qn_codec.c24
-rw-r--r--firmware/drivers/isp1583.c6
-rw-r--r--firmware/drivers/lcd-16bit-common.c17
-rw-r--r--firmware/drivers/lcd-bitmap-common.c5
-rw-r--r--firmware/drivers/m66591.c4
-rw-r--r--firmware/drivers/usb-designware.c548
-rw-r--r--firmware/export/audiohw.h5
-rw-r--r--firmware/export/config.h17
-rw-r--r--firmware/export/config/android.h3
-rw-r--r--firmware/export/config/cowond2.h3
-rw-r--r--firmware/export/config/erosqnative.h10
-rw-r--r--firmware/export/config/fiiom3k.h7
-rw-r--r--firmware/export/config/nokian8xx.h3
-rw-r--r--firmware/export/config/nokian900.h3
-rw-r--r--firmware/export/config/pandora.h3
-rw-r--r--firmware/export/config/samsungypr0.h4
-rw-r--r--firmware/export/config/samsungypz5.h204
-rw-r--r--firmware/export/config/sansam200v4.h3
-rw-r--r--firmware/export/config/sdlapp.h3
-rw-r--r--firmware/export/config/shanlingq1.h7
-rw-r--r--firmware/export/config/tatungtpj1022.h151
-rw-r--r--firmware/export/config/xduoox3.h2
-rw-r--r--firmware/export/eros_qn_codec.h13
-rw-r--r--firmware/export/erosqlinux_codec.h11
-rw-r--r--firmware/export/logf.h2
-rw-r--r--firmware/export/pathfuncs.h1
-rw-r--r--firmware/export/usb-designware.h3
-rw-r--r--firmware/export/usb.h2
-rw-r--r--firmware/export/usb_core.h12
-rw-r--r--firmware/export/usb_drv.h11
-rw-r--r--firmware/include/adler32.h (renamed from firmware/target/arm/imx233/samsung-ypz5/debug-ypz5.c)16
-rw-r--r--firmware/include/inflate.h (renamed from firmware/target/arm/imx233/samsung-ypz5/ftl-target.h)33
-rw-r--r--firmware/kernel/thread.c7
-rw-r--r--firmware/libc/atoi.c5
-rw-r--r--firmware/logf.c11
-rw-r--r--firmware/pcm_sw_volume.c125
-rw-r--r--firmware/powermgmt.c7
-rw-r--r--firmware/screendump.c4
-rw-r--r--firmware/system.c6
-rw-r--r--firmware/target/arm/as3525/audio-as3525.c1
-rw-r--r--firmware/target/arm/as3525/debug-as3525.c7
-rw-r--r--firmware/target/arm/as3525/usb-as3525.c13
-rw-r--r--firmware/target/arm/as3525/usb-drv-as3525.c11
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/audio-target.h31
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/backlight-target.h28
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/backlight-ypz5.c149
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/button-target.h59
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/button-ypz5.c273
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/fmradio-target.h31
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/lcd-target.h25
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/lcd-ypz5.c295
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/powermgmt-target.h37
-rw-r--r--firmware/target/arm/imx233/samsung-ypz5/powermgmt-ypz5.c48
-rw-r--r--firmware/target/arm/imx233/touchscreen-imx233.c27
-rw-r--r--firmware/target/arm/ipod/backlight-mini1g_mini2g.c7
-rw-r--r--firmware/target/arm/ipod/backlight-target.h2
-rw-r--r--firmware/target/arm/pp/system-pp502x.c2
-rw-r--r--firmware/target/arm/pp/system-target.h6
-rw-r--r--firmware/target/arm/pp/usb-fw-pp502x.c6
-rw-r--r--firmware/target/arm/rk27xx/usb-drv-rk27xx.c4
-rw-r--r--firmware/target/arm/tatung/app.lds2
-rw-r--r--firmware/target/arm/tatung/boot.lds2
-rw-r--r--firmware/target/arm/tatung/tpj1022/adc-target.h35
-rw-r--r--firmware/target/arm/tatung/tpj1022/backlight-tpj1022.c46
-rw-r--r--firmware/target/arm/tatung/tpj1022/button-target.h51
-rw-r--r--firmware/target/arm/tatung/tpj1022/lcd-tpj1022.c85
-rw-r--r--firmware/target/arm/tatung/tpj1022/power-tpj1022.c63
-rw-r--r--firmware/target/arm/tatung/tpj1022/powermgmt-tpj1022.c62
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c10
-rw-r--r--firmware/target/arm/usb-drv-arc.c4
-rw-r--r--firmware/target/arm/usb-s3c6400x.c4
-rw-r--r--firmware/target/arm/usb-tcc.c4
-rw-r--r--firmware/target/hosted/backtrace-glibc.c2
-rw-r--r--firmware/target/hosted/filesystem-win32.c7
-rw-r--r--firmware/target/hosted/pcm-alsa.c9
-rw-r--r--firmware/target/hosted/rtc.c3
-rw-r--r--firmware/target/hosted/system-hosted.c2
-rw-r--r--firmware/target/mips/ingenic_jz47xx/usb-jz4740.c4
-rw-r--r--firmware/target/mips/ingenic_jz47xx/usb-jz4760.c4
-rw-r--r--firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c17
-rw-r--r--firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c12
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c4
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c2
-rw-r--r--firmware/target/mips/ingenic_x1000/msc-x1000.c14
-rw-r--r--firmware/target/mips/ingenic_x1000/msc-x1000.h2
-rw-r--r--firmware/target/mips/ingenic_x1000/pcm-x1000.c9
-rw-r--r--firmware/target/mips/ingenic_x1000/usb-x1000.c11
-rw-r--r--firmware/target/mips/ingenic_x1000/x1000/ost.h10
-rw-r--r--firmware/usbstack/usb_class_driver.h7
-rw-r--r--firmware/usbstack/usb_core.c329
-rw-r--r--firmware/usbstack/usb_hid.c56
-rw-r--r--firmware/usbstack/usb_hid.h2
-rw-r--r--firmware/usbstack/usb_serial.c41
-rw-r--r--firmware/usbstack/usb_serial.h2
-rw-r--r--firmware/usbstack/usb_storage.c30
-rw-r--r--firmware/usbstack/usb_storage.h2
-rw-r--r--lib/rbcodec/codecs/codecs.make2
-rw-r--r--lib/rbcodec/codecs/liba52/downmix.c3
-rw-r--r--lib/rbcodec/codecs/wavpack_enc.c1
-rw-r--r--lib/rbcodec/dsp/crossfeed.c1
-rw-r--r--lib/rbcodec/metadata/asap.c102
-rw-r--r--lib/rbcodec/metadata/asf.c44
-rw-r--r--lib/rbcodec/metadata/flac.c12
-rw-r--r--lib/rbcodec/metadata/id3tags.c3
-rw-r--r--lib/rbcodec/metadata/metadata_common.c52
-rw-r--r--lib/rbcodec/metadata/mp3data.c15
-rw-r--r--lib/rbcodec/metadata/mp4.c108
-rw-r--r--lib/rbcodec/metadata/smaf.c53
-rw-r--r--lib/rbcodec/metadata/vtx.c36
-rw-r--r--lib/skin_parser/skin_parser.c5
-rw-r--r--manual/appendix/config_file_options.tex2
-rw-r--r--manual/credits.pl2
-rw-r--r--manual/getting_started/xduoox3_install.tex4
-rw-r--r--manual/platform/keymap-shanlingq1.tex6
-rw-r--r--manual/preamble.tex8
-rw-r--r--manual/rockbox_interface/main.tex2
-rw-r--r--rbutil/rbutilqt/themesinstallwindow.cpp1
-rw-r--r--rbutil/rbutilqt/themesinstallwindow.h3
-rw-r--r--tools/builds.pm17
-rwxr-xr-xtools/configure59
-rw-r--r--tools/iriver.c89
-rwxr-xr-xtools/rockboxdev.sh2
-rw-r--r--tools/scramble.c4
-rwxr-xr-xtools/updatelang34
-rwxr-xr-xtools/voice.pl2
-rw-r--r--uisimulator/buttonmap/fiio-m3k.c4
-rw-r--r--utils/reggen-ng/x1000.reggen4
-rw-r--r--utils/themeeditor/resources/targetdb9
266 files changed, 6368 insertions, 5620 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 6fdaea3ca8..1628524805 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -272,8 +272,6 @@ keymaps/keymap-ma.c
keymaps/keymap-nwz.c
#elif CONFIG_KEYPAD == SONY_NWZA860_PAD
keymaps/keymap-nwza860.c
-#elif CONFIG_KEYPAD == SAMSUNG_YPZ5_PAD
-keymaps/keymap-ypz5.c
#elif CONFIG_KEYPAD == IHIFI_PAD
keymaps/keymap-ihifi.c
#elif CONFIG_KEYPAD == IHIFI_770_PAD
diff --git a/apps/action.c b/apps/action.c
index 5533c00241..b31c4fa927 100644
--- a/apps/action.c
+++ b/apps/action.c
@@ -405,6 +405,7 @@ static inline bool get_action_touchscreen(action_last_t *last, action_cur_t *cur
}
last->button = cur->button;
+ last->tick = current_tick;
cur->action = ACTION_TOUCHSCREEN;
return true;
}
@@ -684,13 +685,25 @@ static inline int do_auto_softlock(action_last_t *last, action_cur_t *cur)
{
do_key_lock(true);
-#if defined(HAVE_TOUCHPAD)
+#if defined(HAVE_TOUCHPAD) || defined(HAVE_TOUCHSCREEN)
/* if the touchpad is supposed to be off and the current buttonpress
* is from the touchpad, nullify both button and action. */
if (!has_flag(action_last.softlock_mask, SEL_ACTION_ENABLED) ||
has_flag(action_last.softlock_mask, SEL_ACTION_NOTOUCH))
{
+#if defined(HAVE_TOUCHPAD)
cur->button = touchpad_filter(cur->button);
+#endif
+#if defined(HAVE_TOUCHSCREEN)
+ const int touch_fakebuttons =
+ BUTTON_TOPLEFT | BUTTON_TOPMIDDLE | BUTTON_TOPRIGHT |
+ BUTTON_LEFT | BUTTON_CENTER | BUTTON_RIGHT |
+ BUTTON_BOTTOMLEFT | BUTTON_BOTTOMMIDDLE | BUTTON_BOTTOMRIGHT;
+ if (has_flag(cur->button, BUTTON_TOUCHSCREEN))
+ cur->button = BUTTON_NONE;
+ else
+ cur->button &= ~touch_fakebuttons;
+#endif
if (cur->button == BUTTON_NONE)
{
action = ACTION_NONE;
@@ -1008,6 +1021,7 @@ static int get_action_worker(action_last_t *last, action_cur_t *cur)
if (get_action_touchscreen(last, cur))
{
+ do_softlock(last, cur);
return cur->action;
}
@@ -1214,41 +1228,44 @@ void set_selective_softlock_actions(bool selective, unsigned int mask)
}
}
-
-void action_autosoftlock_init(void)
+/* look for an action in the given context, return button which triggers it.
+ * (note: pre_button isn't taken into account here) */
+static int find_button_for_action(int context, int action)
{
- action_cur_t cur;
- int i = 0;
+ const struct button_mapping *items;
+ int i;
- if (action_last.unlock_combo == BUTTON_NONE)
+ do
{
- /* search CONTEXT_WPS, should be here */
- cur.items = get_context_mapping(CONTEXT_WPS);
- while (cur.items[i].button_code != BUTTON_NONE)
+ items = get_context_mapping(context);
+ if (items == NULL)
+ break;
+
+ for (i = 0; items[i].button_code != BUTTON_NONE; ++i)
{
- if (cur.items[i].action_code == ACTION_STD_KEYLOCK)
- {
- action_last.unlock_combo = cur.items[i].button_code;
- break;
- }
- i = i + 1;
+ if (items[i].action_code == action)
+ return items[i].button_code;
}
- /* not there... let's try std
- * I doubt any targets will need this, but... */
- if (action_last.unlock_combo == BUTTON_NONE)
+ /* get chained context, if none it will be CONTEXT_STOPSEARCHING */
+ context = items[i].action_code;
+ } while (context != (int)CONTEXT_STOPSEARCHING);
+
+ return BUTTON_NONE;
+}
+
+void action_autosoftlock_init(void)
+{
+ /* search in WPS and STD contexts for the keylock button combo */
+ static const int contexts[2] = { CONTEXT_WPS, CONTEXT_STD };
+
+ for (int i = 0; i < 2; ++i)
+ {
+ int button = find_button_for_action(contexts[i], ACTION_STD_KEYLOCK);
+ if (button != BUTTON_NONE)
{
- i = 0;
- cur.items = get_context_mapping(CONTEXT_STD);
- while (cur.items[i].button_code != BUTTON_NONE)
- {
- if (cur.items[i].action_code == ACTION_STD_KEYLOCK)
- {
- action_last.unlock_combo = cur.items[i].button_code;
- break;
- }
- i = i + 1;
- }
+ action_last.unlock_combo = button;
+ break;
}
}
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 07751c2d4c..70dbd8075d 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -75,10 +75,10 @@ static struct {
bool shuffle;
/* optional values */
int pitch;
- int speed;
+ int speed;
} bm;
-static bool add_bookmark(const char* bookmark_file_name, const char* bookmark,
+static bool add_bookmark(const char* bookmark_file_name, const char* bookmark,
bool most_recent);
static char* create_bookmark(void);
static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id);
@@ -275,7 +275,7 @@ static bool get_playlist_and_track(const char *bookmark, char **pl_start,
/* This function adds a bookmark to a file. */
/* Returns true on successful bookmark add. */
/* ------------------------------------------------------------------------*/
-static bool add_bookmark(const char* bookmark_file_name, const char* bookmark,
+static bool add_bookmark(const char* bookmark_file_name, const char* bookmark,
bool most_recent)
{
int temp_bookmark_file = 0;
@@ -466,7 +466,7 @@ bool bookmark_autoload(const char* file)
else
{
int ret = select_bookmark(global_bookmark_file_name, true, &bookmark);
-
+
if (bookmark != NULL)
{
if (!play_bookmark(bookmark))
@@ -475,7 +475,7 @@ bool bookmark_autoload(const char* file)
splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
}
- /* Act as if autoload was done even if it failed, since the
+ /* Act as if autoload was done even if it failed, since the
* user did make an active selection.
*/
return true;
@@ -520,7 +520,7 @@ bool bookmark_load(const char* file, bool autoload)
{
splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
}
-
+
return false;
}
}
@@ -541,7 +541,7 @@ static int get_bookmark_count(const char* bookmark_file_name)
{
read_count++;
}
-
+
close(file);
return read_count;
}
@@ -563,25 +563,25 @@ static int buffer_bookmarks(struct bookmark_list* bookmarks, int first_line)
/* Entire file fits in buffer */
first_line = 0;
}
-
+
bookmarks->start = first_line;
bookmarks->count = 0;
bookmarks->reload = false;
-
+
while(read_line(file, global_read_buffer, sizeof(global_read_buffer)) > 0)
{
read_count++;
-
+
if (read_count >= first_line)
{
dest -= strlen(global_read_buffer) + 1;
-
+
if (dest < ((char*) bookmarks) + sizeof(*bookmarks)
+ (sizeof(char*) * (bookmarks->count + 1)))
{
break;
}
-
+
strcpy(dest, global_read_buffer);
bookmarks->items[bookmarks->count] = dest;
bookmarks->count++;
@@ -604,22 +604,22 @@ static const char* get_bookmark_info(int list_index,
{
if (index == 0)
{
- return list_index % 2 == 0
+ return list_index % 2 == 0
? (char*) str(LANG_BOOKMARK_DONT_RESUME) : " ";
}
-
+
index--;
}
- if (bookmarks->reload || (index >= bookmarks->start + bookmarks->count)
+ if (bookmarks->reload || (index >= bookmarks->start + bookmarks->count)
|| (index < bookmarks->start))
{
int read_index = index;
-
+
/* Using count as a guide on how far to move could possibly fail
* sometimes. Use byte count if that is a problem?
*/
-
+
if (read_index != 0)
{
/* Move count * 3 / 4 items in the direction the user is moving,
@@ -627,31 +627,31 @@ static const char* get_bookmark_info(int list_index,
*/
int offset = bookmarks->count;
int max = bookmarks->total_count - (bookmarks->count / 2);
-
+
if (read_index < bookmarks->start)
{
offset *= 3;
}
-
+
read_index = index - offset / 4;
if (read_index > max)
{
read_index = max;
}
-
+
if (read_index < 0)
{
read_index = 0;
}
}
-
+
if (buffer_bookmarks(bookmarks, read_index) <= index)
{
return "";
}
}
-
+
if (!parse_bookmark(bookmarks->items[index - bookmarks->start], true, true))
{
return list_index % 2 == 0 ? (char*) str(LANG_BOOKMARK_INVALID) : " ";
@@ -662,12 +662,12 @@ static const char* get_bookmark_info(int list_index,
char *name;
char *format;
int len = strlen(global_temp_buffer);
-
+
if (bookmarks->show_playlist_name && len > 0)
{
name = global_temp_buffer;
len--;
-
+
if (name[len] != '/')
{
strrsplt(name, '.');
@@ -689,7 +689,7 @@ static const char* get_bookmark_info(int list_index,
name = global_filename;
format = "%s";
}
-
+
strrsplt(global_filename, '.');
snprintf(buffer, buffer_len, format, name, global_filename);
return buffer;
@@ -751,12 +751,12 @@ static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume
gui_synclist_init(&list, &get_bookmark_info, (void*) bookmarks, false, 2, NULL);
if(global_settings.talk_menu)
gui_synclist_set_voice_callback(&list, bookmark_list_voice_cb);
- gui_synclist_set_title(&list, str(LANG_BOOKMARK_SELECT_BOOKMARK),
+ gui_synclist_set_title(&list, str(LANG_BOOKMARK_SELECT_BOOKMARK),
Icon_Bookmark);
while (!exit)
{
-
+
if (refresh)
{
int count = get_bookmark_count(bookmark_file_name);
@@ -805,17 +805,17 @@ static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume
if (action == ACTION_STD_CONTEXT)
{
MENUITEM_STRINGLIST(menu_items, ID2P(LANG_BOOKMARK_CONTEXT_MENU),
- NULL, ID2P(LANG_BOOKMARK_CONTEXT_RESUME),
+ NULL, ID2P(LANG_BOOKMARK_CONTEXT_RESUME),
ID2P(LANG_BOOKMARK_CONTEXT_DELETE));
- static const int menu_actions[] =
+ static const int menu_actions[] =
{
ACTION_STD_OK, ACTION_BMS_DELETE
};
int selection = do_menu(&menu_items, NULL, NULL, false);
-
+
refresh = true;
- if (selection >= 0 && selection <=
+ if (selection >= 0 && selection <=
(int) (sizeof(menu_actions) / sizeof(menu_actions[0])))
{
action = menu_actions[selection];
@@ -842,7 +842,7 @@ static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume
case ACTION_BMS_DELETE:
if (item >= 0)
- {
+ {
const char *lines[]={
ID2P(LANG_REALLY_DELETE)
};
@@ -854,7 +854,7 @@ static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume
const struct text_message yes_message={yes_lines, 1};
if(gui_syncyesno_run(&message, &yes_message, NULL)==YESNO_YES)
- {
+ {
delete_bookmark(bookmark_file_name, item);
bookmarks->reload = true;
}
@@ -1002,12 +1002,12 @@ static const char* skip_token(const char* s)
{
s++;
}
-
+
if (*s)
{
s++;
}
-
+
return s;
}
@@ -1033,11 +1033,11 @@ static bool parse_bookmark(const char *bookmark, const bool parse_filenames, con
{
const char* s = bookmark;
const char* end;
-
+
#define GET_INT_TOKEN(var) s = int_token(s, &var)
#define GET_LONG_TOKEN(var) s = long_token(s, &var)
#define GET_BOOL_TOKEN(var) var = (atoi(s)!=0); s = skip_token(s)
-
+
/* if new format bookmark, extract the optional content flags,
otherwise treat as an original format bookmark */
int opt_flags = 0;
@@ -1047,7 +1047,7 @@ static bool parse_bookmark(const char *bookmark, const bool parse_filenames, con
s++;
GET_INT_TOKEN(opt_flags);
}
-
+
/* extract all original bookmark tokens */
GET_INT_TOKEN(bm.resume_index);
GET_LONG_TOKEN(bm.resume_offset);
@@ -1057,18 +1057,18 @@ static bool parse_bookmark(const char *bookmark, const bool parse_filenames, con
GET_LONG_TOKEN(bm.resume_time);
GET_INT_TOKEN(bm.repeat_mode);
GET_BOOL_TOKEN(bm.shuffle);
-
+
/* extract all optional bookmark tokens */
if (opt_flags & BM_PITCH)
GET_INT_TOKEN(bm.pitch);
if (opt_flags & BM_SPEED)
GET_INT_TOKEN(bm.speed);
-
+
if (*s == 0)
{
return false;
}
-
+
end = strchr(s, ';');
/* extract file names */
@@ -1077,7 +1077,7 @@ static bool parse_bookmark(const char *bookmark, const bool parse_filenames, con
size_t len = (end == NULL) ? strlen(s) : (size_t) (end - s);
len = MIN(TEMP_BUF_SIZE - 1, len);
strlcpy(global_temp_buffer, s, len + 1);
-
+
if (end != NULL)
{
end++;
@@ -1093,7 +1093,7 @@ static bool parse_bookmark(const char *bookmark, const bool parse_filenames, con
strlcpy(global_filename, end, MAX_PATH);
}
}
-
+
return true;
}
@@ -1103,12 +1103,10 @@ static bool parse_bookmark(const char *bookmark, const bool parse_filenames, con
/* Changing this function could result in how the bookmarks are stored. */
/* it would be here that the centralized/decentralized bookmark code */
/* could be placed. */
-/* Always returns true */
+/* Returns true if the file name is generated, false if it was too long */
/* ----------------------------------------------------------------------- */
static bool generate_bookmark_file_name(const char *in)
{
- int len = strlen(in);
-
/* if this is a root dir MP3, rename the bookmark file root_dir.bmark */
/* otherwise, name it based on the in variable */
if (!strcmp("/", in))
@@ -1121,15 +1119,24 @@ static bool generate_bookmark_file_name(const char *in)
path_strip_volume(in, &filename, true);
bool volume_root = *filename == '\0';
#endif
- strcpy(global_bookmark_file_name, in);
- if(global_bookmark_file_name[len-1] == '/')
+ size_t len = strlcpy(global_bookmark_file_name, in, MAX_PATH);
+ if(len >= MAX_PATH)
+ return false;
+
+ if(global_bookmark_file_name[len-1] == '/') {
+ global_bookmark_file_name[len-1] = '\0';
len--;
+ }
+
#ifdef HAVE_MULTIVOLUME
if (volume_root)
- strcpy(&global_bookmark_file_name[len], "/volume_dir.bmark");
+ len = strlcat(global_bookmark_file_name, "/volume_dir.bmark", MAX_PATH);
else
#endif
- strcpy(&global_bookmark_file_name[len], ".bmark");
+ len = strlcat(global_bookmark_file_name, ".bmark", MAX_PATH);
+
+ if(len >= MAX_PATH)
+ return false;
}
return true;
diff --git a/apps/codec_thread.c b/apps/codec_thread.c
index 807c0b6e8e..999b844349 100644
--- a/apps/codec_thread.c
+++ b/apps/codec_thread.c
@@ -183,14 +183,16 @@ const char * get_codec_filename(int cod_spec)
/* Can choose decoder or encoder if one available */
int type = cod_spec & CODEC_TYPE_MASK;
int afmt = cod_spec & CODEC_AFMT_MASK;
-
+ int tmp_fmt = afmt;
if ((unsigned)afmt >= AFMT_NUM_CODECS)
+ {
type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
-
+ tmp_fmt = AFMT_UNKNOWN;
+ }
fname = (type == CODEC_TYPE_ENCODER) ?
- audio_formats[afmt].codec_enc_root_fn :
- audio_formats[afmt].codec_root_fn;
-
+ audio_formats[tmp_fmt].codec_enc_root_fn :
+ audio_formats[tmp_fmt].codec_root_fn;
+
logf("%s: %d - %s",
(type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
afmt, fname ? fname : "<unknown>");
diff --git a/apps/cuesheet.c b/apps/cuesheet.c
index a9180a70d4..be89ef96cf 100644
--- a/apps/cuesheet.c
+++ b/apps/cuesheet.c
@@ -64,7 +64,7 @@ static bool search_for_cuesheet(const char *path, struct cuesheet_file *cue_file
{
strcpy(cuepath, CUE_DIR);
if (strlcat(cuepath, slash, MAX_PATH) >= MAX_PATH)
- goto skip; /* overflow */
+ goto skip; /* overflow */
char *dot = strrchr(cuepath, '.');
strcpy(dot, ".cue");
if (!file_exists(cuepath))
@@ -118,6 +118,53 @@ static char *get_string(const char *line)
return start;
}
+static unsigned long parse_cue_index(const char *line)
+{
+ /* assumes strncmp(line, "INDEX 01", 8) & NULL terminated string */
+ /* INDEX 01 MM:SS:FF\0 (00:00:00\0 - 99:99:99\0)*/
+ const unsigned field_m[3] = {60 * 1000, 1000, 13}; /* MM:SS:~FF*/
+ const char f_sep = ':';
+ int field = -1;
+ unsigned long offset = 0; /* ms from start of track */
+ unsigned long value = 0;
+ while (*line)
+ {
+ if (!isdigit(*line)) /* search for numbers */
+ {
+ line++;
+ continue;
+ }
+
+ while (isdigit(*line))
+ {
+ value = 10 * value + (*line - '0');
+ if (value > 99) /* Sanity check bail early */
+ return 0;
+ line++;
+ }
+
+ if (field < 0) /*Filter INDEX 01*/
+ {
+ /* safe to assume value == 1 */
+ }
+ else if (field <= 2)
+ {
+ while(*line && *line != f_sep)
+ line++;
+
+ if (*line || field == 2) /* if *line valid we found f_sep */
+ offset += (unsigned long) field_m[field] * value;
+ }
+ else
+ break;
+
+ value = 0;
+ field++;
+ }
+
+ return offset;
+}
+
/* parse cuesheet "cue_file" and store the information in "cue" */
bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
{
@@ -204,6 +251,7 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
}
else if (!strncmp(s, "INDEX 01", 8))
{
+#if 0
s = strchr(s,' ');
s = skip_whitespace(s);
s = strchr(s,' ');
@@ -213,6 +261,9 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
cue->tracks[cue->track_count-1].offset += 1000 * atoi(s);
s = strchr(s,':') + 1;
cue->tracks[cue->track_count-1].offset += 13 * atoi(s);
+#else
+ cue->tracks[cue->track_count-1].offset = parse_cue_index(s);
+#endif
}
else if (!strncmp(s, "TITLE", 5)
|| !strncmp(s, "PERFORMER", 9)
@@ -254,7 +305,7 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
break;
}
- if (dest)
+ if (dest)
{
if (char_enc == CHAR_ENC_ISO_8859_1)
{
@@ -266,7 +317,7 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
{
strlcpy(dest, string, count);
}
- }
+ }
}
if (is_embedded)
{
@@ -454,7 +505,7 @@ bool display_cuesheet_content(char* filename)
bool curr_cuesheet_skip(struct cuesheet *cue, int direction, unsigned long curr_pos)
{
int track = cue_find_current_track(cue, curr_pos);
-
+
if (direction >= 0 && track == cue->track_count - 1)
{
/* we want to get out of the cuesheet */
@@ -469,7 +520,7 @@ bool curr_cuesheet_skip(struct cuesheet *cue, int direction, unsigned long curr_
to previous cuesheet segment. If skipping backward after
DEFAULT_SKIP_TRESH seconds have elapsed, skip to the start of the
current cuesheet segment */
- if (direction == 1 ||
+ if (direction == 1 ||
((curr_pos - cue->tracks[track].offset) < DEFAULT_SKIP_TRESH))
{
track += direction;
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 02dc19359b..33970da581 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1726,6 +1726,7 @@ static bool dbg_disk_info(void)
#ifdef HAVE_DIRCACHE
static int dircache_callback(int btn, struct gui_synclist *lists)
{
+ (void)lists;
struct dircache_info info;
dircache_get_info(&info);
@@ -1737,6 +1738,7 @@ static int dircache_callback(int btn, struct gui_synclist *lists)
splash(HZ/2, "Rebuilding cache");
dircache_suspend();
*(int *)lists->data = dircache_resume();
+ /* Fallthrough */
case ACTION_UNKNOWN:
btn = ACTION_NONE;
break;
@@ -1776,7 +1778,6 @@ static int dircache_callback(int btn, struct gui_synclist *lists)
btn = ACTION_REDRAW;
return btn;
- (void)lists;
}
static bool dbg_dircache_info(void)
@@ -2241,6 +2242,51 @@ static bool cpu_boost_log(void)
lcd_setfont(FONT_UI);
return false;
}
+
+static bool cpu_boost_log_dump(void)
+{
+ int fd;
+#if CONFIG_RTC
+ struct tm *nowtm;
+ char fname[MAX_PATH];
+#endif
+
+ int count = cpu_boost_log_getcount();
+ char *str = cpu_boost_log_getlog_first();
+
+ splashf(HZ, "Boost Log File Dumped");
+
+ /* nothing to print ? */
+ if(count == 0)
+ return false;
+
+#if CONFIG_RTC
+ nowtm = get_time();
+ snprintf(fname, MAX_PATH, "%s/boostlog_%04d%02d%02d%02d%02d%02d.txt", ROCKBOX_DIR,
+ nowtm->tm_year + 1900, nowtm->tm_mon + 1, nowtm->tm_mday,
+ nowtm->tm_hour, nowtm->tm_min, nowtm->tm_sec);
+ fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC);
+#else
+ fd = open(ROCKBOX_DIR "/boostlog.txt", O_CREAT|O_WRONLY|O_TRUNC, 0666);
+#endif
+ if(-1 != fd) {
+ for (int i = 0; i < count; i++)
+ {
+ if (!str)
+ str = cpu_boost_log_getlog_next();
+ if (str)
+ {
+ fdprintf(fd, "%s\n", str);
+ str = NULL;
+ }
+ }
+
+ close(fd);
+ return true;
+ }
+
+ return false;
+}
#endif
#if (defined(HAVE_WHEEL_ACCELERATION) && (CONFIG_KEYPAD==IPOD_4G_PAD) \
@@ -2603,7 +2649,8 @@ static const struct {
#endif
#endif /* HAVE_USBSTACK */
#ifdef CPU_BOOST_LOGGING
- {"cpu_boost log",cpu_boost_log},
+ {"Show cpu_boost log",cpu_boost_log},
+ {"Dump cpu_boost log",cpu_boost_log_dump},
#endif
#if (defined(HAVE_WHEEL_ACCELERATION) && (CONFIG_KEYPAD==IPOD_4G_PAD) \
&& !defined(IPOD_MINI) && !defined(SIMULATOR))
diff --git a/apps/enc_config.c b/apps/enc_config.c
index 66aaac22e6..65ef65667a 100644
--- a/apps/enc_config.c
+++ b/apps/enc_config.c
@@ -115,7 +115,7 @@ static void mp3_enc_convert_config(struct encoder_config *cfg,
}
else
{
- if ((unsigned)global_settings.mp3_enc_config.bitrate > MP3_ENC_NUM_BITR)
+ if ((unsigned)global_settings.mp3_enc_config.bitrate >= MP3_ENC_NUM_BITR)
global_settings.mp3_enc_config.bitrate = MP3_ENC_BITRATE_CFG_DEFAULT;
cfg->mp3_enc.bitrate = mp3_enc_bitr[global_settings.mp3_enc_config.bitrate];
}
diff --git a/apps/filetree.c b/apps/filetree.c
index 5c6443cc34..efe5e80a0f 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -435,7 +435,8 @@ static void ft_load_font(char *file)
int ft_enter(struct tree_context* c)
{
int rc = GO_TO_PREVIOUS;
- char buf[MAX_PATH];
+ static char buf[MAX_PATH];
+
struct entry* file = tree_get_entry_at(c, c->selected_item);
if (!file)
{
@@ -628,32 +629,19 @@ int ft_enter(struct tree_context* c)
rolo_load(buf);
break;
#endif
+ case FILE_ATTR_CUE:
+ display_cuesheet_content(buf);
+ break;
/* plugin file */
case FILE_ATTR_ROCK:
- case FILE_ATTR_LUA:
- case FILE_ATTR_OPX:
{
- char *plugin = buf, *argument = NULL, lua_path[MAX_PATH];
- int ret;
-
- if ((file_attr & FILE_ATTR_MASK) == FILE_ATTR_LUA) {
- snprintf(lua_path, sizeof(lua_path)-1, "%s/lua.rock", VIEWERS_DIR); /* Use a #define here ? */
- plugin = lua_path;
- argument = buf;
- }
- else if ((file_attr & FILE_ATTR_MASK) == FILE_ATTR_OPX) {
- snprintf(lua_path, sizeof(lua_path)-1, "%s/open_plugins.rock", VIEWERS_DIR); /* Use a #define here ? */
- plugin = lua_path;
- argument = buf;
- }
-
+ char *plugin = buf, *argument = NULL;
if (global_settings.party_mode && audio_status()) {
splash(HZ, ID2P(LANG_PARTY_MODE));
break;
}
- ret = plugin_load(plugin, argument);
- switch (ret)
+ switch (plugin_load(plugin, argument))
{
case PLUGIN_GOTO_WPS:
play = true;
@@ -678,14 +666,12 @@ int ft_enter(struct tree_context* c)
}
break;
}
- case FILE_ATTR_CUE:
- display_cuesheet_content(buf);
- break;
default:
{
const char* plugin;
-
+ char plugin_path[MAX_PATH];
+ const char *argument = buf;
if (global_settings.party_mode && audio_status()) {
splash(HZ, ID2P(LANG_PARTY_MODE));
break;
@@ -698,10 +684,10 @@ int ft_enter(struct tree_context* c)
return rc;
}
- plugin = filetype_get_plugin(file);
+ plugin = filetype_get_plugin(file, plugin_path, sizeof(plugin_path));
if (plugin)
{
- switch (plugin_load(plugin,buf))
+ switch (plugin_load(plugin, argument))
{
case PLUGIN_USB_CONNECTED:
rc = GO_TO_FILEBROWSER;
diff --git a/apps/filetypes.c b/apps/filetypes.c
index 7f7c198cb5..d68bab3daa 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -185,7 +185,8 @@ static int filetype_count = 0;
static unsigned char highest_attr = 0;
static int viewer_count = 0;
-static int strdup_handle, strdup_bufsize, strdup_cur_idx;
+static int strdup_handle, strdup_cur_idx;
+static size_t strdup_bufsize;
static int move_callback(int handle, void* current, void* new)
{
/*could compare to strdup_handle, but ops is only used once */
@@ -337,6 +338,29 @@ void read_viewer_theme_file(void)
custom_icons_loaded = true;
}
+static void read_viewers_config(void)
+{
+ int fd = open(VIEWERS_CONFIG, O_RDONLY);
+ if(fd < 0)
+ return;
+
+ off_t filesz = filesize(fd);
+ if(filesz <= 0)
+ goto out;
+
+ /* estimate bufsize with the filesize, will not be larger */
+ strdup_bufsize = (size_t)filesz;
+ strdup_handle = core_alloc_ex("filetypes", strdup_bufsize, &ops);
+ if(strdup_handle <= 0)
+ goto out;
+
+ read_config(fd);
+ core_shrink(strdup_handle, core_get_data(strdup_handle), strdup_cur_idx);
+
+ out:
+ close(fd);
+}
+
void filetype_init(void)
{
/* set the directory item first */
@@ -345,29 +369,15 @@ void filetype_init(void)
filetypes[0].attr = 0;
filetypes[0].icon = Icon_Folder;
- /* estimate bufsize with the filesize, will not be larger */
viewer_count = 0;
filetype_count = 1;
- int fd = open(VIEWERS_CONFIG, O_RDONLY);
- if (fd < 0)
- return;
-
- strdup_bufsize = filesize(fd);
- strdup_handle = core_alloc_ex("filetypes", strdup_bufsize, &ops);
- if (strdup_handle <= 0)
- {
- close(fd);
- return;
- }
read_builtin_types();
- read_config(fd);
- close(fd);
+ read_viewers_config();
read_viewer_theme_file();
#ifdef HAVE_LCD_COLOR
read_color_theme_file();
#endif
- core_shrink(strdup_handle, core_get_data(strdup_handle), strdup_cur_idx);
}
/* remove all white spaces from string */
@@ -521,17 +531,37 @@ int filetype_get_icon(int attr)
return filetypes[index].icon;
}
-char* filetype_get_plugin(const struct entry* file)
+char* filetype_get_plugin(const struct entry* file, char *buffer, size_t buffer_len)
{
- static char plugin_name[MAX_PATH];
int index = find_attr(file->attr);
- if (index < 0)
+ if (index < 0 || !buffer)
return NULL;
- if (filetypes[index].plugin == NULL)
+ struct file_type *ft_indexed = &filetypes[index];
+
+ /* attempt to find a suitable viewer by file extension */
+ if(ft_indexed->plugin == NULL && ft_indexed->extension != NULL)
+ {
+ struct file_type *ft;
+ int i = filetype_count;
+ while (--i > index)
+ {
+ ft = &filetypes[i];
+ if (ft->plugin == NULL || ft->extension == NULL)
+ continue;
+ else if (strcmp(ft->extension, ft_indexed->extension) == 0)
+ {
+ /*splashf(HZ*3, "Found %d %s %s", i, ft->extension, ft->plugin);*/
+ ft_indexed = ft;
+ break;
+ }
+ }
+ }
+ if (ft_indexed->plugin == NULL)
return NULL;
- snprintf(plugin_name, MAX_PATH, "%s/%s.%s",
- PLUGIN_DIR, filetypes[index].plugin, ROCK_EXTENSION);
- return plugin_name;
+
+ snprintf(buffer, buffer_len, "%s/%s." ROCK_EXTENSION,
+ PLUGIN_DIR, ft_indexed->plugin);
+ return buffer;
}
bool filetype_supported(int attr)
@@ -564,39 +594,32 @@ static int openwith_get_talk(int selected_item, void * data)
{
(void)data;
char viewer_filename[MAX_FILENAME];
- snprintf(viewer_filename, MAX_FILENAME, "%s.%s",
- filetypes[viewers[selected_item]].plugin, ROCK_EXTENSION);
+ snprintf(viewer_filename, MAX_FILENAME, "%s." ROCK_EXTENSION,
+ filetypes[viewers[selected_item]].plugin);
talk_file_or_spell(PLUGIN_DIR, viewer_filename,
NULL, false);
return 0;
}
-static int openwith_action_callback(int action, struct gui_synclist *lists)
-{
- struct cb_data *info = (struct cb_data *)lists->data;
- int i;
- if (action == ACTION_STD_OK)
- {
- char plugin[MAX_PATH];
- i = viewers[gui_synclist_get_sel_pos(lists)];
- snprintf(plugin, MAX_PATH, "%s/%s.%s",
- PLUGIN_DIR, filetypes[i].plugin, ROCK_EXTENSION);
- plugin_load(plugin, info->current_file);
- return ACTION_STD_CANCEL;
- }
- return action;
-}
-
int filetype_list_viewers(const char* current_file)
{
struct simplelist_info info;
- struct cb_data data = { current_file };
- simplelist_info_init(&info, str(LANG_ONPLAY_OPEN_WITH), viewer_count, &data);
- info.action_callback = openwith_action_callback;
+ simplelist_info_init(&info, str(LANG_ONPLAY_OPEN_WITH), viewer_count, NULL);
info.get_name = openwith_get_name;
info.get_icon = global_settings.show_icons?openwith_get_icon:NULL;
info.get_talk = openwith_get_talk;
- return simplelist_show_list(&info);
+
+ int ret = simplelist_show_list(&info);
+
+ if (info.selection >= 0) /* run user selected viewer */
+ {
+ char plugin[MAX_PATH];
+ int i = viewers[info.selection];
+ snprintf(plugin, MAX_PATH, "%s/%s." ROCK_EXTENSION,
+ PLUGIN_DIR, filetypes[i].plugin);
+ plugin_load(plugin, current_file);
+ }
+ return ret;
}
int filetype_load_plugin(const char* plugin, const char* file)
@@ -621,7 +644,7 @@ int filetype_load_plugin(const char* plugin, const char* file)
}
if (i >= filetype_count)
return PLUGIN_ERROR;
- snprintf(plugin_name, MAX_PATH, "%s/%s.%s",
- PLUGIN_DIR, filetypes[i].plugin, ROCK_EXTENSION);
+ snprintf(plugin_name, MAX_PATH, "%s/%s." ROCK_EXTENSION,
+ PLUGIN_DIR, filetypes[i].plugin);
return plugin_load(plugin_name, file);
}
diff --git a/apps/filetypes.h b/apps/filetypes.h
index 23f259b3ca..efe9f3f5df 100644
--- a/apps/filetypes.h
+++ b/apps/filetypes.h
@@ -73,7 +73,7 @@ int filetype_get_color(const char* name, int attr);
#endif
int filetype_get_icon(int attr);
/* return the plugin filename associated with the file */
-char* filetype_get_plugin(const struct entry* file);
+char* filetype_get_plugin(const struct entry* file, char *buffer, size_t buffer_len);
/* returns true if the attr is supported */
bool filetype_supported(int attr);
diff --git a/apps/gui/bitmap/list-skinned.c b/apps/gui/bitmap/list-skinned.c
index c5429738ed..a67ac8cb0a 100644
--- a/apps/gui/bitmap/list-skinned.c
+++ b/apps/gui/bitmap/list-skinned.c
@@ -197,6 +197,9 @@ bool skinlist_draw(struct screen *display, struct gui_synclist *list)
wps.data = listcfg[screen]->data;
display_lines = skinlist_get_line_count(screen, list);
label = (char *)SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->label);
+ if (!label)
+ return false;
+
display->set_viewport(parent);
display->clear_viewport();
current_item = list->selected_item;
diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index a82595fb37..ff0f5a29c1 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -50,7 +50,6 @@
static struct viewport list_text[NB_SCREENS], title_text[NB_SCREENS];
#ifdef HAVE_TOUCHSCREEN
-static int y_offset;
static bool hide_selection;
#endif
@@ -170,12 +169,9 @@ void list_draw(struct screen *display, struct gui_synclist *list)
end = start + nb_lines;
#ifdef HAVE_TOUCHSCREEN
- if (list->selected_item == 0 || (list->nb_items < nb_lines))
- y_offset = 0; /* reset in case it's a new list */
-
- int draw_offset = y_offset;
+ int draw_offset = list_start_item * linedes.height - list->y_pos;
/* draw some extra items to not have empty lines at the top and bottom */
- if (y_offset > 0)
+ if (draw_offset > 0)
{
/* make it negative for more consistent apparence when switching
* directions */
@@ -183,7 +179,7 @@ void list_draw(struct screen *display, struct gui_synclist *list)
if (start > 0)
start--;
}
- else if (y_offset < 0)
+ else if (draw_offset < 0)
end++;
#else
#define draw_offset 0
@@ -359,8 +355,7 @@ static enum {
SCROLL_KINETIC, /* state after releasing swipe */
} scroll_mode;
-static int scrollbar_scroll(struct gui_synclist * gui_list,
- int y)
+static int scrollbar_scroll(struct gui_synclist * gui_list, int y)
{
const int screen = screens[SCREEN_MAIN].screen_type;
const int nb_lines = list_get_nb_lines(gui_list, screen);
@@ -368,12 +363,9 @@ static int scrollbar_scroll(struct gui_synclist * gui_list,
if (nb_lines < gui_list->nb_items)
{
/* scrollbar scrolling is still line based */
- y_offset = 0;
- int scrollbar_size = nb_lines*gui_list->line_height[screen];
+ int scrollbar_size = nb_lines * gui_list->line_height[screen];
int actual_y = y - list_text[screen].y;
-
- int new_selection = (actual_y * gui_list->nb_items)
- / scrollbar_size;
+ int new_selection = (actual_y * gui_list->nb_items) / scrollbar_size;
int start_item = new_selection - nb_lines/2;
if(start_item < 0)
@@ -382,6 +374,7 @@ static int scrollbar_scroll(struct gui_synclist * gui_list,
start_item = gui_list->nb_items - nb_lines;
gui_list->start_item[screen] = start_item;
+ gui_list->y_pos = start_item * gui_list->line_height[screen];
return ACTION_REDRAW;
}
@@ -471,9 +464,11 @@ static void kinetic_force_stop(void)
/* helper for gui/list.c to cancel scrolling if a normal button event comes
* through dpad or keyboard or whatever */
-void _gui_synclist_stop_kinetic_scrolling(void)
+void _gui_synclist_stop_kinetic_scrolling(struct gui_synclist * gui_list)
{
- y_offset = 0;
+ const enum screen_type screen = screens[SCREEN_MAIN].screen_type;
+ gui_list->y_pos = gui_list->start_item[screen] * gui_list->line_height[screen];
+
if (scroll_mode == SCROLL_KINETIC)
kinetic_force_stop();
scroll_mode = SCROLL_NONE;
@@ -515,22 +510,25 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
int new_start_item = -1;
int line_diff = 0;
- /* don't scroll at the edges of the list */
- if ((old_start == 0 && difference > 0)
- || (old_start == (gui_list->nb_items - nb_lines) && difference < 0))
- {
- y_offset = 0;
- gui_list->start_item[screen] = old_start;
- return scroll_mode != SCROLL_KINETIC; /* stop kinetic at the edges */
- }
+ /* Track whether we hit the end of the list for sake of kinetic scroll */
+ bool hit_end = true;
- /* add up y_offset over time and translate to lines
- * if scrolled enough */
- y_offset += difference;
- if (abs(y_offset) > line_height)
+ /* Move the y position and clamp it (funny things happen otherwise...) */
+ gui_list->y_pos -= difference;
+ if(gui_list->y_pos < 0)
+ gui_list->y_pos = 0;
+ else if(gui_list->y_pos > (gui_list->nb_items - nb_lines) * line_height)
+ gui_list->y_pos = (gui_list->nb_items - nb_lines) * line_height;
+ else
+ hit_end = false;
+
+ /* Get the list y position. When pos_y differs by a line height or more,
+ * we need to scroll the list by adjusting the start item accordingly */
+ int cur_y = gui_list->start_item[screen] * line_height;
+ int diff_y = cur_y - gui_list->y_pos;
+ if (abs(diff_y) >= line_height)
{
- line_diff = y_offset/line_height;
- y_offset -= line_diff * line_height;
+ line_diff = diff_y/line_height;
}
if(line_diff != 0)
@@ -547,9 +545,14 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
gui_list->start_item[screen] = new_start_item;
/* keep selected item in sync */
gui_list->selected_item = new_start_item + selection_offset;
+ if(gui_list->selected_size > 1)
+ gui_list->selected_item -= (gui_list->selected_item % gui_list->selected_size);
}
- return true;
+ if(hit_end)
+ return scroll_mode != SCROLL_KINETIC;
+ else
+ return true;
}
static int kinetic_callback(struct timeout *tmo)
@@ -730,13 +733,16 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
if(!skinlist_get_item(&screens[screen], list, adj_x, adj_y, &line))
{
/* selection needs to be corrected if items are only partially visible */
- line = (adj_y - y_offset) / line_height;
+ int cur_y = list->start_item[screen] * line_height;
+ line = (adj_y - (cur_y - list->y_pos)) / line_height;
if (list_display_title(list, screen))
line -= 1; /* adjust for the list title */
}
if (list_start_item+line >= list->nb_items)
return ACTION_NONE;
list->selected_item = list_start_item+line;
+ if(list->selected_size > 1)
+ list->selected_item -= (list->selected_item % list->selected_size);
gui_synclist_speak_item(list);
}
@@ -754,7 +760,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
if (click_loc & LIST)
{
/* held a single line for a while, bring up the context menu */
- gui_synclist_select_item(list, list_start_item + line);
+ gui_synclist_select_item(list, list->selected_item);
/* don't sent context repeatedly */
action_wait_for_release();
initial_touch = true;
@@ -766,7 +772,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
initial_touch = true;
if (click_loc & LIST)
{ /* release on list item enters it */
- gui_synclist_select_item(list, list_start_item + line);
+ gui_synclist_select_item(list, list->selected_item);
return ACTION_STD_OK;
}
else if (click_loc & TITLE_TEXT)
@@ -835,7 +841,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
hide_selection = true;
/* similarly to swipe scroll, using the scrollbar grabs
* focus so the click location is irrelevant */
- scrollbar_scroll(list, adj_y);
+ scrollbar_scroll(list, y);
if (action & BUTTON_REL)
scroll_mode = SCROLL_NONE;
break;
diff --git a/apps/gui/folder_select.c b/apps/gui/folder_select.c
index f2830fb8fd..706b166941 100644
--- a/apps/gui/folder_select.c
+++ b/apps/gui/folder_select.c
@@ -165,7 +165,10 @@ static struct folder* load_folder(struct folder* parent, char *folder)
}
char *name = folder_alloc_from_end(len+1);
if (!name)
+ {
+ closedir(dir);
return NULL;
+ }
memcpy(name, (char *)entry->d_name, len+1);
child_count++;
first_child = name;
diff --git a/apps/gui/icon.c b/apps/gui/icon.c
index 25c0b372fa..9fe7090f4a 100644
--- a/apps/gui/icon.c
+++ b/apps/gui/icon.c
@@ -74,13 +74,13 @@ static struct iconset {
(*(inbuilt_iconset[screen])) : iconsets[Iconset_user][screen].bmp).width
/* x,y in letters, not pixles */
-void screen_put_icon(struct screen * display,
+void screen_put_icon(struct screen * display,
int x, int y, enum themable_icons icon)
{
screen_put_icon_with_offset(display, x, y, 0, 0, icon);
}
-void screen_put_icon_with_offset(struct screen * display,
+void screen_put_icon_with_offset(struct screen * display,
int x, int y, int off_x, int off_y,
enum themable_icons icon)
{
@@ -107,7 +107,7 @@ void screen_put_iconxy(struct screen * display,
const int height = ICON_HEIGHT(screen);
const int is_rtl = lang_is_rtl();
const struct bitmap *iconset;
-
+
if (icon <= Icon_NOICON)
{
if (is_rtl)
@@ -119,7 +119,7 @@ void screen_put_iconxy(struct screen * display,
{
iconset = &iconsets[Iconset_viewers][screen].bmp;
icon -= Icon_Last_Themeable;
- if (!iconsets[Iconset_viewers][screen].loaded ||
+ if (!iconsets[Iconset_viewers][screen].loaded ||
(global_status.viewer_icon_count * height > iconset->height) ||
(icon * height + height > iconset->height))
{
@@ -174,43 +174,54 @@ static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL, NULL};
static void load_icons(const char* filename, enum Iconset iconset,
enum screen_type screen)
{
- int size_read;
+ ssize_t size_read;
+ ssize_t buf_size;
+ int fd;
int bmpformat = (FORMAT_ANY|FORMAT_DITHER|FORMAT_TRANSPARENT);
struct iconset *ic = &iconsets[iconset][screen];
- int fd;
-
+
ic->loaded = false;
+ ic->handle = 0;
if (filename[0] && filename[0] != '-')
{
char path[MAX_PATH];
-
+
snprintf(path, sizeof(path), ICON_DIR "/%s.bmp", filename);
fd = open(path, O_RDONLY);
if (fd < 0)
return;
- size_t buf_size = read_bmp_fd(fd, &ic->bmp, 0,
+ buf_size = read_bmp_fd(fd, &ic->bmp, 0,
bmpformat|FORMAT_RETURN_SIZE, NULL);
- ic->handle = core_alloc_ex(filename, buf_size, &buflib_ops);
+ if (buf_size > 0)
+ ic->handle = core_alloc_ex(filename, (size_t) buf_size, &buflib_ops);
+
if (ic->handle <= 0)
{
- close(fd);
- return;
+ /* error */
+ goto finished;
}
lseek(fd, 0, SEEK_SET);
ic->bmp.data = core_get_data(ic->handle);
ic->handle_locked = 1;
size_read = read_bmp_fd(fd, &ic->bmp, buf_size, bmpformat, NULL);
- close(fd);
ic->handle_locked = 0;
+ if (size_read < 0)
+ {
+ /* error */
+ size_read = 0;
+ }
/* free unused alpha channel, if any */
core_shrink(ic->handle, ic->bmp.data, size_read);
- if (size_read <= 0)
+ if (size_read == 0)
ic->handle = core_free(ic->handle);
else
ic->loaded = true;
+finished:
+ close(fd);
+ return;
}
}
@@ -234,31 +245,30 @@ void icons_init(void)
{
load_icons(global_settings.icon_file, Iconset_user, SCREEN_MAIN);
- if (global_settings.viewers_icon_file[0] &&
- global_settings.viewers_icon_file[0] != '-')
+ if (global_settings.viewers_icon_file[0] == '-' ||
+ global_settings.viewers_icon_file[0] == '\0')
{
- load_icons(global_settings.viewers_icon_file,
- Iconset_viewers, SCREEN_MAIN);
- read_viewer_theme_file();
+ load_icons(DEFAULT_VIEWER_BMP, Iconset_viewers, SCREEN_MAIN);
}
else
{
- load_icons(DEFAULT_VIEWER_BMP, Iconset_viewers, SCREEN_MAIN);
+ load_icons(global_settings.viewers_icon_file,
+ Iconset_viewers, SCREEN_MAIN);
+ read_viewer_theme_file();
}
-
#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
- load_icons(global_settings.remote_icon_file,
+ load_icons(global_settings.remote_icon_file,
Iconset_user, SCREEN_REMOTE);
-
- if (global_settings.remote_viewers_icon_file[0] &&
- global_settings.remote_viewers_icon_file[0] != '-')
+
+ if (global_settings.remote_viewers_icon_file[0] == '-' ||
+ global_settings.remote_viewers_icon_file[0] == '\0')
{
- load_icons(global_settings.remote_viewers_icon_file,
+ load_icons(DEFAULT_REMOTE_VIEWER_BMP,
Iconset_viewers, SCREEN_REMOTE);
}
else
{
- load_icons(DEFAULT_REMOTE_VIEWER_BMP,
+ load_icons(global_settings.remote_viewers_icon_file,
Iconset_viewers, SCREEN_REMOTE);
}
#endif
diff --git a/apps/gui/list.c b/apps/gui/list.c
index 36dbe44445..13a850bd7b 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -152,6 +152,9 @@ void gui_synclist_init(struct gui_synclist * gui_list,
gui_list->callback_speak_item = NULL;
gui_list->nb_items = 0;
gui_list->selected_item = 0;
+#ifdef HAVE_TOUCHSCREEN
+ gui_list->y_pos = 0;
+#endif
FOR_NB_SCREENS(i)
{
gui_list->start_item[i] = 0;
@@ -282,6 +285,9 @@ static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list,
gui_list->start_item[screen] = bottom;
else
gui_list->start_item[screen] = new_start_item;
+#ifdef HAVE_TOUCHSCREEN
+ gui_list->y_pos = gui_list->start_item[SCREEN_MAIN] * gui_list->line_height[SCREEN_MAIN];
+#endif
}
static void edge_beep(struct gui_synclist * gui_list, bool wrap)
@@ -417,6 +423,10 @@ static void gui_list_select_at_offset(struct gui_synclist * gui_list,
gui_list->selected_size);
gui_list->selected_item = gui_list->start_item[i] + nb_lines;
}
+
+#ifdef HAVE_TOUCHSCREEN
+ gui_list->y_pos = gui_list->start_item[SCREEN_MAIN] * gui_list->line_height[SCREEN_MAIN];
+#endif
}
return;
}
@@ -667,7 +677,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
action = *actionptr = gui_synclist_do_touchscreen(lists);
else if (action > ACTION_TOUCHSCREEN_MODE)
/* cancel kinetic if we got a normal button event */
- _gui_synclist_stop_kinetic_scrolling();
+ _gui_synclist_stop_kinetic_scrolling(lists);
#endif
/* Disable the skin redraw callback */
@@ -748,6 +758,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
return true;
}
*actionptr = ACTION_TREE_PGLEFT;
+ /* fallthrough */
case ACTION_TREE_PGLEFT:
if(pgleft_allow_cancel && (lists->offset_position[0] == 0))
{
diff --git a/apps/gui/list.h b/apps/gui/list.h
index 3a613d0a67..64ff3e3fdd 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -118,6 +118,10 @@ struct gui_synclist
bool scroll_all;
int nb_items;
int selected_item;
+#ifdef HAVE_TOUCHSCREEN
+ /* absolute Y coordinate, used for smooth scrolling */
+ int y_pos;
+#endif
int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */
/* the number of lines that are selected at the same time */
int selected_size;
@@ -229,7 +233,7 @@ int skinlist_get_line_count(enum screen_type screen, struct gui_synclist *list);
/* this needs to be fixed if we ever get more than 1 touchscreen on a target */
extern unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list);
/* only for private use in gui/list.c */
-extern void _gui_synclist_stop_kinetic_scrolling(void);
+extern void _gui_synclist_stop_kinetic_scrolling(struct gui_synclist * gui_list);
#endif
/* If the list has a pending postponed scheduled announcement, that
diff --git a/apps/gui/mask_select.c b/apps/gui/mask_select.c
index e22ba7dd03..c39b3583ac 100644
--- a/apps/gui/mask_select.c
+++ b/apps/gui/mask_select.c
@@ -79,11 +79,14 @@ static int calculate_mask_r(struct category *root, int mask)
while (i < root->children_count)
{
struct child *this = &root->children[i];
- if (this->state == SELECTED)
- mask |= this->key_value;
+ if (this)
+ {
+ if (this->state == SELECTED)
+ mask |= this->key_value;
- else if (this->state == EXPANDED)
- mask = calculate_mask_r(this->category, mask);
+ else if (this->state == EXPANDED)
+ mask = calculate_mask_r(this->category, mask);
+ }
i++;
}
return mask;
@@ -97,7 +100,7 @@ static int count_items(struct category *start)
for (i=0; i<start->children_count; i++)
{
struct child *foo = &start->children[i];
- if (foo->state == EXPANDED)
+ if (foo && foo->state == EXPANDED)
count += count_items(foo->category);
count++;
}
@@ -120,7 +123,7 @@ static struct child* find_index(struct category *start,
return foo;
}
i++;
- if (foo->state == EXPANDED)
+ if (foo && foo->state == EXPANDED)
{
struct child *bar = find_index(foo->category, index - i, parent);
if (bar)
@@ -141,7 +144,7 @@ static int item_action_callback(int action, struct gui_synclist *list)
struct category *parent;
struct child *this = find_index(root, list->selected_item, &parent);
- if (action == ACTION_STD_OK)
+ if (action == ACTION_STD_OK && this)
{
switch (this->state)
{
@@ -194,16 +197,18 @@ static const char * item_get_name(int selected_item, void * data,
for(int i = 0; i <= parent->depth; i++)
strcat(buffer, "\t\0");
- /* state of selection needs icons so if icons are disabled use text*/
- if (!global_settings.show_icons)
- {
- if (this->state == SELECTED)
- strcat(buffer, "+\0");
- else
- strcat(buffer," \0");
- }
- strlcat(buffer, P2STR((const unsigned char *)this->name), buffer_len);
-
+ if (this)
+ {
+ /* state of selection needs icons so if icons are disabled use text*/
+ if (!global_settings.show_icons)
+ {
+ if (this->state == SELECTED)
+ strcat(buffer, "+\0");
+ else
+ strcat(buffer," \0");
+ }
+ strlcat(buffer, P2STR((const unsigned char *)this->name), buffer_len);
+ }
return buffer;
}
@@ -212,7 +217,7 @@ static int item_get_talk(int selected_item, void *data)
struct category *root = (struct category*)data;
struct category *parent;
struct child *this = find_index(root, selected_item , &parent);
- if (global_settings.talk_menu)
+ if (global_settings.talk_menu && this)
{
long id = P2ID((const unsigned char *)(this->name));
if(id>=0)
@@ -234,16 +239,19 @@ static enum themable_icons item_get_icon(int selected_item, void * data)
struct category *parent;
struct child *this = find_index(root, selected_item, &parent);
- switch (this->state)
+ if (this)
{
- case SELECTED:
- return Icon_Submenu;
- case COLLAPSED:
- return Icon_NOICON;
- case EXPANDED:
- return Icon_Submenu_Entered;
- default:
- return Icon_NOICON;
+ switch (this->state)
+ {
+ case SELECTED:
+ return Icon_Submenu;
+ case COLLAPSED:
+ return Icon_NOICON;
+ case EXPANDED:
+ return Icon_Submenu_Entered;
+ default:
+ return Icon_NOICON;
+ }
}
return Icon_NOICON;
}
diff --git a/apps/gui/option_select.c b/apps/gui/option_select.c
index ff257a4925..9f1f0a64e3 100644
--- a/apps/gui/option_select.c
+++ b/apps/gui/option_select.c
@@ -60,7 +60,7 @@ static const char *option_get_timestring(char *buf, int buf_len,
/* these two vars are needed so arbitrary values can be added to the
TABLE_SETTING settings if the F_ALLOW_ARBITRARY_VALS flag is set */
static int table_setting_oldval = 0, table_setting_array_position = 0;
-const char *option_get_valuestring(const struct settings_list *setting,
+const char *option_get_valuestring(const struct settings_list *setting,
char *buffer, int buf_len,
intptr_t temp_var)
{
@@ -202,7 +202,7 @@ void option_talk_value(const struct settings_list *setting, int value, bool enqu
}
}
}
-
+
static int option_talk(int selected_item, void * data)
{
struct settings_list *setting = (struct settings_list *)data;
@@ -320,7 +320,7 @@ static int selection_to_val(const struct settings_list *setting, int selection)
else if ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)
{
const struct table_setting *info = setting->table_setting;
- if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
+ if (setting->flags&F_ALLOW_ARBITRARY_VALS &&
table_setting_array_position != -1 &&
(selection >= table_setting_array_position))
{
@@ -361,7 +361,7 @@ static int selection_to_val(const struct settings_list *setting, int selection)
return max- (selection * step);
}
-static const char * value_setting_get_name_cb(int selected_item,
+static const char * value_setting_get_name_cb(int selected_item,
void * data,
char *buffer,
size_t buffer_len)
@@ -492,16 +492,16 @@ bool option_screen(const struct settings_list *setting,
title = (char*)setting->cfg_vals;
else
title = P2STR(option_title);
-
+
gui_synclist_set_title(&lists, title, Icon_Questionmark);
gui_synclist_set_icon_callback(&lists, NULL);
if(global_settings.talk_menu)
gui_synclist_set_voice_callback(&lists, option_talk);
-
+
val_to_selection(setting, oldvalue, &nb_items, &selected, &function);
gui_synclist_set_nb_items(&lists, nb_items);
gui_synclist_select_item(&lists, selected);
-
+
gui_synclist_limit_scroll(&lists, true);
gui_synclist_draw(&lists);
/* talk the item */
@@ -551,7 +551,7 @@ bool option_screen(const struct settings_list *setting,
{
if (var_type == F_T_INT || var_type == F_T_UINT)
*(int*)setting->setting = *variable;
- else
+ else
*(bool*)setting->setting = (*variable==1);
}
settings_save();
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index 7bcd25d258..4ebdcab722 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -768,7 +768,7 @@ static int parse_setting_and_lang(struct skin_element *element,
#ifndef __PCTOOL__
i = lang_english_to_id(temp);
if (i < 0)
- return WPS_ERROR_INVALID_PARAM;
+ i = LANG_LAST_INDEX_IN_ARRAY;
#endif
}
else if (element->params_count > 1)
@@ -1856,8 +1856,14 @@ static int load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char*
return fd;
}
#ifndef __PCTOOL__
- size_t buf_size = read_bmp_fd(fd, bitmap, 0,
- format|FORMAT_RETURN_SIZE, NULL);
+ int buf_size = read_bmp_fd(fd, bitmap, 0,
+ format|FORMAT_RETURN_SIZE, NULL);
+ if(buf_size < 0)
+ {
+ close(fd);
+ return buf_size;
+ }
+
handle = core_alloc_ex(bitmap->data, buf_size, &buflib_ops);
if (handle <= 0)
{
diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c
index a0de45d3e3..a4c9af7539 100644
--- a/apps/gui/skin_engine/skin_tokens.c
+++ b/apps/gui/skin_engine/skin_tokens.c
@@ -821,7 +821,8 @@ const char *get_token_value(struct gui_wps *gwps,
return (char*)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
case SKIN_TOKEN_TRANSLATEDSTRING:
- return (char*)P2STR(ID2P(token->value.i));
+ return token->value.i < LANG_LAST_INDEX_IN_ARRAY ?
+ (char*)P2STR(ID2P(token->value.i)) : "<ERR>";
case SKIN_TOKEN_PLAYLIST_ENTRIES:
numeric_ret = playlist_amount();
diff --git a/apps/gui/statusbar-skinned.c b/apps/gui/statusbar-skinned.c
index 9b10ad4dce..63f3197faa 100644
--- a/apps/gui/statusbar-skinned.c
+++ b/apps/gui/statusbar-skinned.c
@@ -270,6 +270,7 @@ char* sb_create_from_settings(enum screen_type screen)
{
case STATUSBAR_TOP:
y = STATUSBAR_HEIGHT;
+ /* Fallthrough */
case STATUSBAR_BOTTOM:
height = screens[screen].lcdheight - STATUSBAR_HEIGHT;
break;
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index 35716087c2..cdb34ab447 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -223,6 +223,7 @@ bool ffwd_rew(int button)
{
case ACTION_WPS_SEEKFWD:
direction = 1;
+ /* Fallthrough */
case ACTION_WPS_SEEKBACK:
if (skin_get_global_state()->ff_rewind)
{
@@ -583,7 +584,7 @@ void wps_do_playpause(bool updatewps)
state->paused = true;
pause_action(true, updatewps);
settings_save();
-#if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
+#if !defined(HAVE_SW_POWEROFF)
call_storage_idle_notifys(true); /* make sure resume info is saved */
#endif
}
@@ -629,7 +630,7 @@ long gui_wps_show(void)
about to shut down. lets save the settings. */
if (state->paused) {
settings_save();
-#if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
+#if !defined(HAVE_SW_POWEROFF)
call_storage_idle_notifys(true);
#endif
}
diff --git a/apps/gui/yesno.c b/apps/gui/yesno.c
index 669f8ca09a..a79b8ae644 100644
--- a/apps/gui/yesno.c
+++ b/apps/gui/yesno.c
@@ -28,6 +28,7 @@
#include "talk.h"
#include "settings.h"
#include "viewport.h"
+#include "appevents.h"
struct gui_yesno
@@ -142,6 +143,16 @@ static bool gui_yesno_draw_result(struct gui_yesno * yn, enum yesno_res result)
return(true);
}
+static void gui_yesno_ui_update(unsigned short id, void *event_data, void *user_data)
+{
+ (void)id;
+ (void)event_data;
+
+ struct gui_yesno* yn = (struct gui_yesno*)user_data;
+ FOR_NB_SCREENS(i)
+ gui_yesno_draw(&yn[i]);
+}
+
enum yesno_res gui_syncyesno_run(const struct text_message * main_message,
const struct text_message * yes_message,
const struct text_message * no_message)
@@ -164,10 +175,20 @@ enum yesno_res gui_syncyesno_run(const struct text_message * main_message,
gui_yesno_draw(&(yn[i]));
}
+#ifdef HAVE_TOUCHSCREEN
+ /* switch to point mode because that's more intuitive */
+ enum touchscreen_mode old_mode = touchscreen_get_mode();
+ touchscreen_set_mode(TOUCHSCREEN_POINT);
+#endif
+
/* make sure to eat any extranous keypresses */
action_wait_for_release();
button_clear_queue();
+ /* hook into UI update events to avoid the dialog disappearing
+ * in case the skin decides to do a full refresh */
+ add_event_ex(GUI_EVENT_NEED_UI_UPDATE, false, gui_yesno_ui_update, &yn[0]);
+
while (result==-1)
{
/* Repeat the question every 5secs (more or less) */
@@ -211,8 +232,11 @@ enum yesno_res gui_syncyesno_run(const struct text_message * main_message,
/* ignore some SYS events that can happen */
continue;
default:
- if(default_event_handler(button) == SYS_USB_CONNECTED)
- return(YESNO_USB);
+ if(default_event_handler(button) == SYS_USB_CONNECTED) {
+ result = YESNO_USB;
+ goto exit;
+ }
+
result = YESNO_NO;
}
}
@@ -235,7 +259,12 @@ enum yesno_res gui_syncyesno_run(const struct text_message * main_message,
viewportmanager_theme_undo(i, true);
}
- return(result);
+ exit:
+ remove_event_ex(GUI_EVENT_NEED_UI_UPDATE, gui_yesno_ui_update, &yn[0]);
+#ifdef HAVE_TOUCHSCREEN
+ touchscreen_set_mode(old_mode);
+#endif
+ return result;
}
diff --git a/apps/keymaps/keymap-fiiom3k.c b/apps/keymaps/keymap-fiiom3k.c
index 94d2dbc172..4cd2691d33 100644
--- a/apps/keymaps/keymap-fiiom3k.c
+++ b/apps/keymaps/keymap-fiiom3k.c
@@ -92,6 +92,11 @@ static const struct button_mapping button_context_tree[] = {
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST)
}; /* button_context_tree */
+static const struct button_mapping button_context_bmark[] = {
+ {ACTION_BMS_DELETE, BUTTON_PLAY, BUTTON_NONE},
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_TREE),
+}; /* button_context_bmark */
+
static const struct button_mapping button_context_list[] = {
{ACTION_LISTTREE_PGUP, BUTTON_LEFT, BUTTON_NONE},
{ACTION_LISTTREE_PGUP, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
@@ -170,7 +175,11 @@ static const struct button_mapping button_context_yesnoscreen[] = {
{ACTION_YESNO_ACCEPT, BUTTON_SELECT, BUTTON_NONE},
{ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE},
{ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
- LAST_ITEM_IN_LIST
+ {ACTION_STD_CANCEL, BUTTON_RIGHT, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_LEFT, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_VOL_UP, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_VOL_DOWN, BUTTON_NONE},
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_yesnoscreen */
static const struct button_mapping button_context_keyboard[] = {
@@ -270,8 +279,9 @@ const struct button_mapping* get_context_mapping(int context)
return button_context_wps;
case CONTEXT_TREE:
case CONTEXT_MAINMENU:
- case CONTEXT_BOOKMARKSCREEN:
return button_context_tree;
+ case CONTEXT_BOOKMARKSCREEN:
+ return button_context_bmark;
case CONTEXT_LIST:
return button_context_list;
case CONTEXT_SETTINGS:
diff --git a/apps/keymaps/keymap-hm60x.c b/apps/keymaps/keymap-hm60x.c
index 1050ec7f31..2e1f3dd516 100644
--- a/apps/keymaps/keymap-hm60x.c
+++ b/apps/keymaps/keymap-hm60x.c
@@ -176,7 +176,7 @@ static const struct button_mapping button_context_tree_scroll_lr[] = {
/** Yes/No Screen **/
static const struct button_mapping button_context_yesnoscreen[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_SELECT, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings_yesnoscreen */
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
diff --git a/apps/keymaps/keymap-hm801.c b/apps/keymaps/keymap-hm801.c
index b69656a3f1..1f0a49c90c 100644
--- a/apps/keymaps/keymap-hm801.c
+++ b/apps/keymaps/keymap-hm801.c
@@ -202,7 +202,7 @@ static const struct button_mapping button_context_tree_scroll_lr[] = {
/** Yes/No Screen **/
static const struct button_mapping button_context_yesnoscreen[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_SELECT, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings_yesnoscreen */
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
diff --git a/apps/keymaps/keymap-ihifi.c b/apps/keymaps/keymap-ihifi.c
index 0d574c19e6..147c2f5f62 100644
--- a/apps/keymaps/keymap-ihifi.c
+++ b/apps/keymaps/keymap-ihifi.c
@@ -175,7 +175,7 @@ static const struct button_mapping button_context_tree_scroll_lr[] = {
/** Yes/No Screen **/
static const struct button_mapping button_context_yesnoscreen[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings_yesnoscreen */
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
diff --git a/apps/keymaps/keymap-ipod.c b/apps/keymaps/keymap-ipod.c
index ca52b6b216..e3a17fffba 100644
--- a/apps/keymaps/keymap-ipod.c
+++ b/apps/keymaps/keymap-ipod.c
@@ -114,7 +114,8 @@ static const struct button_mapping button_context_settings[] = {
static const struct button_mapping button_context_yesno[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_SELECT, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ { ACTION_STD_CANCEL, BUTTON_PLAY, BUTTON_NONE },
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_yesno */
static const struct button_mapping button_context_bmark[] = {
diff --git a/apps/keymaps/keymap-m3.c b/apps/keymaps/keymap-m3.c
index 6192d7ff6b..bcd96d664b 100644
--- a/apps/keymaps/keymap-m3.c
+++ b/apps/keymaps/keymap-m3.c
@@ -379,12 +379,12 @@ static const struct button_mapping remote_button_context_wps[] = {
/** Yes/No Screen **/
static const struct button_mapping button_context_yesnoscreen[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_yesnoscreen */
static const struct button_mapping remote_button_context_yesnoscreen[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_RC_PLAY, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* remote_button_context_yesnoscreen */
diff --git a/apps/keymaps/keymap-ma.c b/apps/keymaps/keymap-ma.c
index e1740b697b..28220d9f50 100644
--- a/apps/keymaps/keymap-ma.c
+++ b/apps/keymaps/keymap-ma.c
@@ -183,7 +183,7 @@ static const struct button_mapping button_context_tree_scroll_lr[] = {
/** Yes/No Screen **/
static const struct button_mapping button_context_yesnoscreen[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings_yesnoscreen */
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
diff --git a/apps/keymaps/keymap-mpio-hd200.c b/apps/keymaps/keymap-mpio-hd200.c
index 71b3190384..019d4bfac4 100644
--- a/apps/keymaps/keymap-mpio-hd200.c
+++ b/apps/keymaps/keymap-mpio-hd200.c
@@ -105,8 +105,10 @@ static const struct button_mapping button_context_settings[] = {
static const struct button_mapping button_context_yesno[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_FUNC, BUTTON_NONE },
{ ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE },
+ { ACTION_STD_CANCEL, BUTTON_VOL_UP, BUTTON_NONE },
+ { ACTION_STD_CANCEL, BUTTON_VOL_DOWN, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_yesno */
static const struct button_mapping button_context_bmark[] = {
@@ -269,7 +271,7 @@ static const struct button_mapping button_rc_context_yesno[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_RC_FUNC, BUTTON_NONE },
{ ACTION_YESNO_ACCEPT, BUTTON_RC_PLAY, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_yesno */
static const struct button_mapping button_rc_context_radio[] = {
diff --git a/apps/keymaps/keymap-mpio-hd300.c b/apps/keymaps/keymap-mpio-hd300.c
index cdb617bed0..7941d1704b 100644
--- a/apps/keymaps/keymap-mpio-hd300.c
+++ b/apps/keymaps/keymap-mpio-hd300.c
@@ -109,8 +109,11 @@ static const struct button_mapping button_context_settings[] = {
static const struct button_mapping button_context_yesno[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_ENTER, BUTTON_NONE },
{ ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE },
+ { ACTION_STD_CANCEL, BUTTON_REW, BUTTON_NONE },
+ { ACTION_STD_CANCEL, BUTTON_FF, BUTTON_NONE },
+ { ACTION_STD_CANCEL, BUTTON_REC, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_yesno */
static const struct button_mapping button_context_bmark[] = {
diff --git a/apps/keymaps/keymap-sansa-connect.c b/apps/keymaps/keymap-sansa-connect.c
index 6a6d5de955..b339744b0f 100644
--- a/apps/keymaps/keymap-sansa-connect.c
+++ b/apps/keymaps/keymap-sansa-connect.c
@@ -70,7 +70,12 @@ static const struct button_mapping button_context_wps[] = {
static const struct button_mapping button_context_yesno[] = {
{ACTION_YESNO_ACCEPT, BUTTON_SELECT, BUTTON_NONE},
- LAST_ITEM_IN_LIST
+ {ACTION_STD_CANCEL, BUTTON_PREV, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_NEXT, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_VOL_UP, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_VOL_DOWN, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_yesno */
static const struct button_mapping button_context_settings_time[] = {
diff --git a/apps/keymaps/keymap-shanlingq1.c b/apps/keymaps/keymap-shanlingq1.c
index 4745139e7a..4caaa36fd2 100644
--- a/apps/keymaps/keymap-shanlingq1.c
+++ b/apps/keymaps/keymap-shanlingq1.c
@@ -30,8 +30,11 @@
static const struct button_mapping button_context_standard[] = {
{ACTION_STD_PREV, BUTTON_PREV, BUTTON_NONE},
+ {ACTION_STD_PREVREPEAT, BUTTON_PREV|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_STD_NEXT, BUTTON_NEXT, BUTTON_NONE},
+ {ACTION_STD_NEXTREPEAT, BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_STD_OK, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY},
+ {ACTION_STD_CONTEXT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY},
{ACTION_STD_CANCEL, BUTTON_POWER|BUTTON_REL, BUTTON_POWER},
LAST_ITEM_IN_LIST
}; /* button_context_standard */
@@ -57,6 +60,13 @@ static const struct button_mapping button_context_list[] = {
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_list */
+static const struct button_mapping button_context_yesno[] = {
+ /* note: touchscreen buttons are usable in addition to physical keys */
+ {ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_yesno */
+
const struct button_mapping* target_get_context_mapping(int context)
{
switch (context)
@@ -70,8 +80,9 @@ const struct button_mapping* target_get_context_mapping(int context)
case CONTEXT_CUSTOM|CONTEXT_TREE:
case CONTEXT_MAINMENU:
case CONTEXT_BOOKMARKSCREEN:
- //return button_context_tree;
case CONTEXT_LIST:
return button_context_list;
+ case CONTEXT_YESNOSCREEN:
+ return button_context_yesno;
}
}
diff --git a/apps/keymaps/keymap-touchscreen.c b/apps/keymaps/keymap-touchscreen.c
index 6163cb054c..c70aea2651 100644
--- a/apps/keymaps/keymap-touchscreen.c
+++ b/apps/keymaps/keymap-touchscreen.c
@@ -179,8 +179,6 @@ static const struct button_mapping button_context_mainmenu[] =
static const struct button_mapping button_context_yesno[] = {
- { ACTION_YESNO_ACCEPT, BUTTON_TOPRIGHT, BUTTON_NONE },
- { ACTION_YESNO_ACCEPT, BUTTON_BOTTOMLEFT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM2|CONTEXT_YESNOSCREEN)
}; /* button_context_settings_yesno */
diff --git a/apps/keymaps/keymap-vibe500.c b/apps/keymaps/keymap-vibe500.c
index 49f77628ce..5116ec8575 100644
--- a/apps/keymaps/keymap-vibe500.c
+++ b/apps/keymaps/keymap-vibe500.c
@@ -113,7 +113,9 @@ static const struct button_mapping button_context_settings[] = {
static const struct button_mapping button_context_yesno[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_OK, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ { ACTION_STD_CANCEL, BUTTON_PLAY, BUTTON_NONE },
+ { ACTION_STD_CANCEL, BUTTON_REC, BUTTON_NONE },
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_yesno */
static const struct button_mapping button_context_bmark[] = {
diff --git a/apps/keymaps/keymap-x5.c b/apps/keymaps/keymap-x5.c
index fb2fbfa605..249df7bf3c 100644
--- a/apps/keymaps/keymap-x5.c
+++ b/apps/keymaps/keymap-x5.c
@@ -405,12 +405,12 @@ static const struct button_mapping remote_button_context_wps[] = {
/** Yes/No Screen **/
static const struct button_mapping button_context_yesnoscreen[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_SELECT, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings_yesnoscreen */
static const struct button_mapping remote_button_context_yesnoscreen[] = {
{ ACTION_YESNO_ACCEPT, BUTTON_RC_PLAY, BUTTON_NONE },
- LAST_ITEM_IN_LIST
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* remote_button_context_settings_yesnoscreen */
diff --git a/apps/keymaps/keymap-ypz5.c b/apps/keymaps/keymap-ypz5.c
deleted file mode 100644
index edeebbac3f..0000000000
--- a/apps/keymaps/keymap-ypz5.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id$
- *
- * Copyright (C) 2013 Lorenzo Miori
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-
-/* Button Code Definitions for the Creative Zen Vision target */
-/* Copied from ZVM target for now... */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "config.h"
-#include "action.h"
-#include "button.h"
-#include "settings.h"
-
-/*
- * The format of the list is as follows
- * { Action Code, Button code, Prereq button code }
- * if there's no need to check the previous button's value, use BUTTON_NONE
- * Insert LAST_ITEM_IN_LIST at the end of each mapping
- */
-
-/* CONTEXT_CUSTOM's used in this file...
-
-CONTEXT_CUSTOM|CONTEXT_TREE = the standard list/tree defines (without directions)
-CONTEXT_CUSTOM|CONTEXT_SETTINGS = the direction keys for the eq/col picker screens
- i.e where up/down is inc/dec
- CONTEXT_SETTINGS = up/down is prev/next, l/r is inc/dec
-
-*/
-
-static const struct button_mapping button_context_standard[] = {
- { ACTION_STD_PREV, BUTTON_UP|BUTTON_REL, BUTTON_NONE },
- { ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_STD_NEXT, BUTTON_DOWN|BUTTON_REL, BUTTON_NONE },
- { ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
-
- { ACTION_STD_PREV, BUTTON_FF|BUTTON_REL, BUTTON_NONE },
- { ACTION_STD_PREVREPEAT, BUTTON_FF|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_STD_NEXT, BUTTON_REW|BUTTON_REL, BUTTON_NONE },
- { ACTION_STD_NEXTREPEAT, BUTTON_REW|BUTTON_REPEAT, BUTTON_NONE },
-
- { ACTION_STD_CANCEL, BUTTON_BACK|BUTTON_REL, BUTTON_NONE },
-
- { ACTION_STD_CONTEXT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT },
-
- //{ ACTION_STD_QUICKSCREEN, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK },
- { ACTION_STD_MENU, BUTTON_BACK|BUTTON_REPEAT, BUTTON_NONE },
-
- { ACTION_STD_OK, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
-// { ACTION_STD_OK, BUTTON_RIGHT, BUTTON_NONE },
-
- LAST_ITEM_IN_LIST
-}; /* button_context_standard */
-
-
-static const struct button_mapping button_context_wps[] = {
- { ACTION_WPS_PLAY, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
- //{ ACTION_WPS_STOP, BUTTON_POWER|BUTTON_REPEAT, BUTTON_NONE },
-
- { ACTION_WPS_SKIPNEXT, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT },
- { ACTION_WPS_SKIPPREV, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT },
-
- { ACTION_WPS_SEEKBACK, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_WPS_SEEKFWD, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_WPS_STOPSEEK, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT|BUTTON_REPEAT },
- { ACTION_WPS_STOPSEEK, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT|BUTTON_REPEAT },
-
- { ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE },
- { ACTION_WPS_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_WPS_VOLUP, BUTTON_VOL_UP, BUTTON_NONE },
-
- //{ ACTION_WPS_PITCHSCREEN, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK },
-
- { ACTION_WPS_QUICKSCREEN, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK },
- { ACTION_WPS_MENU, BUTTON_BACK|BUTTON_REL, BUTTON_BACK },
- { ACTION_WPS_VIEW_PLAYLIST, BUTTON_POWER, BUTTON_NONE },
- { ACTION_WPS_CONTEXT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT },
-
- { ACTION_WPS_HOTKEY, BUTTON_BACK|BUTTON_REL, BUTTON_NONE },
- { ACTION_WPS_BROWSE, BUTTON_SELECT|BUTTON_REL, BUTTON_BACK },
- LAST_ITEM_IN_LIST
-}; /* button_context_wps */
-
-static const struct button_mapping button_context_list[] = {
-#ifdef HAVE_VOLUME_IN_LIST
- { ACTION_LIST_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_LIST_VOLUP, BUTTON_VOL_UP, BUTTON_NONE },
- { ACTION_LIST_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE },
- { ACTION_LIST_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
-#endif
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
-}; /* button_context_list */
-
-static const struct button_mapping button_context_tree[] = {
- //{ ACTION_TREE_WPS, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
- //{ ACTION_TREE_STOP, BUTTON_POWER, BUTTON_NONE },
- //{ ACTION_TREE_STOP, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
- //{ ACTION_TREE_STOP, BUTTON_POWER|BUTTON_REPEAT, BUTTON_NONE },
- //{ ACTION_TREE_HOTKEY, BUTTON_BACK|BUTTON_REL, BUTTON_NONE },
-
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST)
-}; /* button_context_tree */
-
-static const struct button_mapping button_context_listtree_scroll_without_combo[] = {
- { ACTION_NONE, BUTTON_LEFT, BUTTON_NONE },
- { ACTION_STD_CANCEL, BUTTON_BACK|BUTTON_REL, BUTTON_BACK },
- { ACTION_TREE_ROOT_INIT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_LEFT },
- { ACTION_TREE_PGLEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_NONE, BUTTON_RIGHT, BUTTON_NONE },
- { ACTION_STD_OK, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT },
- { ACTION_TREE_PGRIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_TREE),
-};
-
-static const struct button_mapping button_context_settings[] = {
- { ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE },
- { ACTION_SETTINGS_INCREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE },
- { ACTION_SETTINGS_DECREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE },
- { ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_LEFT },
- { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
- { ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_RIGHT },
- { ACTION_SETTINGS_RESET, BUTTON_POWER, BUTTON_NONE },
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
-}; /* button_context_settings */
-
-static const struct button_mapping button_context_settings_right_is_inc[] = {
- { ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE },
- { ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE },
- { ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_STD_PREV, BUTTON_UP, BUTTON_NONE },
- { ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
- { ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_BACK, BUTTON_NONE },
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
-}; /* button_context_settingsgraphical */
-
-static const struct button_mapping button_context_yesno[] = {
- { ACTION_YESNO_ACCEPT, BUTTON_SELECT, BUTTON_NONE },
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
-}; /* button_context_settings_yesno */
-
-static const struct button_mapping button_context_colorchooser[] = {
- { ACTION_STD_OK, BUTTON_BACK|BUTTON_REL, BUTTON_NONE },
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_SETTINGS),
-}; /* button_context_colorchooser */
-
-static const struct button_mapping button_context_eq[] = {
- { ACTION_STD_OK, BUTTON_SELECT|BUTTON_REL, BUTTON_NONE },
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_SETTINGS),
-}; /* button_context_eq */
-
-/** Bookmark Screen **/
-static const struct button_mapping button_context_bmark[] = {
- { ACTION_BMS_DELETE, BUTTON_BACK, BUTTON_NONE },
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST),
-}; /* button_context_bmark */
-
-static const struct button_mapping button_context_time[] = {
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS),
-}; /* button_context_time */
-
-static const struct button_mapping button_context_quickscreen[] = {
- { ACTION_QS_TOP, BUTTON_UP, BUTTON_NONE },
- { ACTION_QS_TOP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_QS_DOWN, BUTTON_DOWN, BUTTON_NONE },
- { ACTION_QS_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_QS_LEFT, BUTTON_LEFT, BUTTON_NONE },
- { ACTION_QS_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_QS_RIGHT, BUTTON_RIGHT, BUTTON_NONE },
- { ACTION_QS_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE },
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
-}; /* button_context_quickscreen */
-
-static const struct button_mapping button_context_pitchscreen[] = {
-
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
-}; /* button_context_pitchcreen */
-
-static const struct button_mapping button_context_keyboard[] = {
- { ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE },
- { ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_KBD_RIGHT, BUTTON_RIGHT, BUTTON_NONE },
- { ACTION_KBD_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_KBD_CURSOR_RIGHT, BUTTON_POWER, BUTTON_NONE },
- { ACTION_KBD_CURSOR_RIGHT, BUTTON_POWER|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_KBD_SELECT, BUTTON_SELECT, BUTTON_NONE },
- { ACTION_KBD_PAGE_FLIP, BUTTON_BACK|BUTTON_BACK, BUTTON_NONE },
- { ACTION_KBD_DONE, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
- { ACTION_KBD_ABORT, BUTTON_BACK|BUTTON_REL, BUTTON_BACK },
- { ACTION_KBD_BACKSPACE, BUTTON_BACK, BUTTON_NONE },
- { ACTION_KBD_BACKSPACE, BUTTON_BACK|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_KBD_UP, BUTTON_UP, BUTTON_NONE },
- { ACTION_KBD_UP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_KBD_DOWN, BUTTON_DOWN, BUTTON_NONE },
- { ACTION_KBD_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_KBD_MORSE_SELECT, BUTTON_SELECT|BUTTON_REL, BUTTON_NONE },
- LAST_ITEM_IN_LIST
-}; /* button_context_keyboard */
-
-/** FM Radio Screen **/
-#if CONFIG_TUNER
-static const struct button_mapping button_context_radio[] = {
- { ACTION_FM_MENU, BUTTON_SELECT | BUTTON_REPEAT, BUTTON_SELECT },
- { ACTION_FM_MODE, BUTTON_SELECT, BUTTON_SELECT },
-// { ACTION_FM_PRESET, BUTTON_STOP, BUTTON_NONE },
- { ACTION_FM_PLAY, BUTTON_POWER | BUTTON_REL, BUTTON_NONE },
- { ACTION_FM_STOP, BUTTON_POWER | BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_FM_EXIT, BUTTON_BACK, BUTTON_NONE },
-
- //{ ACTION_SETTINGS_INC, BUTTON_VOL_UP, BUTTON_NONE },
- //{ ACTION_SETTINGS_INCREPEAT,BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
- //{ ACTION_SETTINGS_DEC, BUTTON_VOL_DOWN, BUTTON_NONE },
- //{ ACTION_SETTINGS_DECREPEAT,BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
-
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
-}; /* button_context_radio */
-#endif
-
-#ifdef HAVE_RECORDING
-static const struct button_mapping button_context_recscreen[] = {
-
- { ACTION_REC_PAUSE, BUTTON_SELECT, BUTTON_NONE },
- { ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE },
- { ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE },
- { ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
-
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
-}; /* button_context_recscreen */
-#endif
-
-#ifdef USB_ENABLE_HID
-static const struct button_mapping button_context_usb_hid[] = {
- { ACTION_USB_HID_MODE_SWITCH_NEXT, BUTTON_BACK|BUTTON_REL, BUTTON_BACK },
- { ACTION_USB_HID_MODE_SWITCH_PREV, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK },
-
- LAST_ITEM_IN_LIST
-}; /* button_context_usb_hid */
-
-static const struct button_mapping button_context_usb_hid_mode_multimedia[] = {
-
- { ACTION_USB_HID_MULTIMEDIA_VOLUME_DOWN, BUTTON_VOL_DOWN, BUTTON_NONE },
- { ACTION_USB_HID_MULTIMEDIA_VOLUME_DOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_MULTIMEDIA_VOLUME_UP, BUTTON_VOL_UP, BUTTON_NONE },
- { ACTION_USB_HID_MULTIMEDIA_VOLUME_UP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_MULTIMEDIA_VOLUME_MUTE, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
- { ACTION_USB_HID_MULTIMEDIA_PLAYBACK_PLAY_PAUSE, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
- { ACTION_USB_HID_MULTIMEDIA_PLAYBACK_STOP, BUTTON_POWER|BUTTON_REPEAT, BUTTON_POWER },
- { ACTION_USB_HID_MULTIMEDIA_PLAYBACK_TRACK_PREV, BUTTON_REW|BUTTON_REL, BUTTON_REW },
- { ACTION_USB_HID_MULTIMEDIA_PLAYBACK_TRACK_NEXT, BUTTON_FF|BUTTON_REL, BUTTON_FF },
-
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID)
-}; /* button_context_usb_hid_mode_multimedia */
-
-
-static const struct button_mapping button_context_usb_hid_mode_presentation[] = {
- { ACTION_USB_HID_PRESENTATION_SLIDESHOW_START, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
- { ACTION_USB_HID_PRESENTATION_SLIDESHOW_LEAVE, BUTTON_POWER|BUTTON_REPEAT, BUTTON_POWER },
- { ACTION_USB_HID_PRESENTATION_SLIDE_PREV, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT },
- { ACTION_USB_HID_PRESENTATION_SLIDE_NEXT, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT },
- { ACTION_USB_HID_PRESENTATION_SLIDE_FIRST, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_PRESENTATION_SLIDE_LAST, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- //{ ACTION_USB_HID_PRESENTATION_SCREEN_BLACK, BUTTON_BOTTOMRIGHT|BUTTON_REPEAT, BUTTON_BOTTOMRIGHT },
- //{ ACTION_USB_HID_PRESENTATION_SCREEN_WHITE, BUTTON_BOTTOMLEFT|BUTTON_REPEAT, BUTTON_BOTTOMLEFT },
- { ACTION_USB_HID_PRESENTATION_LINK_PREV, BUTTON_UP, BUTTON_NONE },
- { ACTION_USB_HID_PRESENTATION_LINK_PREV, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_PRESENTATION_LINK_NEXT, BUTTON_DOWN, BUTTON_NONE },
- { ACTION_USB_HID_PRESENTATION_LINK_NEXT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_PRESENTATION_MOUSE_CLICK, BUTTON_SELECT, BUTTON_SELECT },
- { ACTION_USB_HID_PRESENTATION_MOUSE_OVER, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT },
-
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID)
-}; /* button_context_usb_hid_mode_presentation */
-
-static const struct button_mapping button_context_usb_hid_mode_browser[] = {
- { ACTION_USB_HID_BROWSER_SCROLL_UP, BUTTON_UP, BUTTON_NONE },
- { ACTION_USB_HID_BROWSER_SCROLL_UP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_BROWSER_SCROLL_DOWN, BUTTON_DOWN, BUTTON_NONE },
- { ACTION_USB_HID_BROWSER_SCROLL_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_BROWSER_ZOOM_IN, BUTTON_VOL_UP, BUTTON_NONE },
- { ACTION_USB_HID_BROWSER_ZOOM_IN, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_BROWSER_ZOOM_OUT, BUTTON_VOL_DOWN, BUTTON_NONE },
- { ACTION_USB_HID_BROWSER_ZOOM_OUT, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_BROWSER_ZOOM_RESET, BUTTON_POWER|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_BROWSER_TAB_PREV, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT },
- { ACTION_USB_HID_BROWSER_TAB_NEXT, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT },
- { ACTION_USB_HID_BROWSER_TAB_CLOSE, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK },
- { ACTION_USB_HID_BROWSER_HISTORY_BACK, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_LEFT },
- { ACTION_USB_HID_BROWSER_HISTORY_FORWARD, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_RIGHT },
- { ACTION_USB_HID_BROWSER_VIEW_FULL_SCREEN, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT },
-
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID)
-}; /* button_context_usb_hid_mode_browser */
-
-#ifdef HAVE_USB_HID_MOUSE
-static const struct button_mapping button_context_usb_hid_mode_mouse[] = {
- { ACTION_USB_HID_MOUSE_UP, BUTTON_UP, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_UP_REP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_DOWN, BUTTON_DOWN, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_DOWN_REP, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_LEFT, BUTTON_LEFT, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_LEFT_REP, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_RIGHT, BUTTON_RIGHT, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_RIGHT_REP, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_BUTTON_LEFT, BUTTON_SELECT, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_BUTTON_LEFT_REL, BUTTON_SELECT|BUTTON_REL, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_BUTTON_RIGHT, BUTTON_POWER, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_BUTTON_RIGHT_REL, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
-
- { ACTION_USB_HID_MOUSE_WHEEL_SCROLL_UP, BUTTON_FF, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_WHEEL_SCROLL_UP, BUTTON_FF|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_WHEEL_SCROLL_DOWN, BUTTON_REW, BUTTON_NONE },
- { ACTION_USB_HID_MOUSE_WHEEL_SCROLL_DOWN, BUTTON_REW|BUTTON_REPEAT, BUTTON_NONE },
-
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID)
-}; /* button_context_usb_hid_mode_mouse */
-#endif
-#endif
-
-const struct button_mapping* get_context_mapping(int context)
-{
- switch (context)
- {
- case CONTEXT_STD:
- return button_context_standard;
- case CONTEXT_WPS:
- return button_context_wps;
- case CONTEXT_LIST:
- return button_context_list;
- case CONTEXT_MAINMENU:
- case CONTEXT_TREE:
- return button_context_listtree_scroll_without_combo;
- case CONTEXT_CUSTOM|CONTEXT_TREE:
- return button_context_tree;
-#if CONFIG_TUNER
- case CONTEXT_FM:
- return button_context_radio;
-#endif
- case CONTEXT_SETTINGS:
- return button_context_settings;
- case CONTEXT_CUSTOM|CONTEXT_SETTINGS:
- return button_context_settings_right_is_inc;
- case CONTEXT_SETTINGS_COLOURCHOOSER:
- return button_context_colorchooser;
- case CONTEXT_SETTINGS_EQ:
- return button_context_eq;
- case CONTEXT_SETTINGS_TIME:
- return button_context_time;
- case CONTEXT_YESNOSCREEN:
- return button_context_yesno;
- case CONTEXT_BOOKMARKSCREEN:
- return button_context_bmark;
- case CONTEXT_QUICKSCREEN:
- return button_context_quickscreen;
- case CONTEXT_PITCHSCREEN:
- return button_context_pitchscreen;
- case CONTEXT_KEYBOARD:
- case CONTEXT_MORSE_INPUT:
- return button_context_keyboard;
-#ifdef HAVE_RECORDING
- case CONTEXT_SETTINGS_RECTRIGGER:
- return button_context_settings_right_is_inc;
- case CONTEXT_RECSCREEN:
- return button_context_recscreen;
-#endif
-#ifdef USB_ENABLE_HID
- case CONTEXT_USB_HID:
- return button_context_usb_hid;
- case CONTEXT_USB_HID_MODE_MULTIMEDIA:
- return button_context_usb_hid_mode_multimedia;
- case CONTEXT_USB_HID_MODE_PRESENTATION:
- return button_context_usb_hid_mode_presentation;
- case CONTEXT_USB_HID_MODE_BROWSER:
- return button_context_usb_hid_mode_browser;
-#ifdef HAVE_USB_HID_MOUSE
- case CONTEXT_USB_HID_MODE_MOUSE:
- return button_context_usb_hid_mode_mouse;
-#endif
-#endif
- }
- return button_context_standard;
-}
diff --git a/apps/lang/dansk.lang b/apps/lang/dansk.lang
index 536ecb28ec..aff651cc52 100644
--- a/apps/lang/dansk.lang
+++ b/apps/lang/dansk.lang
@@ -12652,3 +12652,17 @@
*: "Start auto-sluk ved opstart"
</voice>
</phrase>
+<phrase>
+ id: VOICE_NUMERIC_TENS_SWAP_SEPARATOR
+ desc: voice only, for speaking numbers in languages that swap the tens and ones fields. Leave blank for languages that do not need it, such as English ("231" => "two hundred thirty one") but other languages may speak it as "two hundred one [AND] thirty"
+ user: core
+ <source>
+ *: ""
+ </source>
+ <dest>
+ *: ""
+ </dest>
+ <voice>
+ *: "og"
+ </voice>
+</phrase>
diff --git a/apps/lang/english-us.lang b/apps/lang/english-us.lang
index 9439236b9c..618ee114fd 100644
--- a/apps/lang/english-us.lang
+++ b/apps/lang/english-us.lang
@@ -12019,14 +12019,17 @@
<source>
*: none
dac_power_mode: "DAC's power mode"
+ es9218: "DAC's output level"
</source>
<dest>
*: none
dac_power_mode: "DAC power mode"
+ es9218: "DAC's output level"
</dest>
<voice>
*: none
dac_power_mode: "DAC power mode"
+ es9218: "DAC's output level"
</voice>
</phrase>
<phrase>
@@ -12036,14 +12039,17 @@
<source>
*: none
dac_power_mode: "High performance"
+ es9218: "High Gain (2 Vrms)"
</source>
<dest>
*: none
dac_power_mode: "High performance"
+ es9218: "High Gain (2 Vrms)"
</dest>
<voice>
*: none
dac_power_mode: "High performance"
+ es9218: "High Gain (2 Vrms)"
</voice>
</phrase>
<phrase>
@@ -12053,14 +12059,17 @@
<source>
*: none
dac_power_mode: "Save battery"
+ es9218: "Low Gain (1 Vrms)"
</source>
<dest>
*: none
dac_power_mode: "Save battery"
+ es9218: "Low Gain (1 Vrms)"
</dest>
<voice>
*: none
dac_power_mode: "Save battery"
+ es9218: "Low Gain (1 Vrms)"
</voice>
</phrase>
<phrase>
@@ -15716,3 +15725,319 @@
*: "Reload After Saving"
</voice>
</phrase>
+<phrase>
+ id: LANG_FILTER_SUPER_SLOW
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ filter_roll_off: "Super Slow"
+ </source>
+ <dest>
+ *: none
+ filter_roll_off: "Super Slow"
+ </dest>
+ <voice>
+ *: none
+ filter_roll_off: "Super Slow"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_LINEAR_FAST
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Linear Fast"
+ </source>
+ <dest>
+ *: none
+ es9218: "Linear Fast"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Linear Fast"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_LINEAR_SLOW
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Linear Slow"
+ </source>
+ <dest>
+ *: none
+ es9218: "Linear Slow"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Linear Slow"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_MINIMUM_FAST
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Minimum Fast"
+ </source>
+ <dest>
+ *: none
+ es9218: "Minimum Fast"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Minimum Fast"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_MINIMUM_SLOW
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Minimum Slow"
+ </source>
+ <dest>
+ *: none
+ es9218: "Minimum Slow"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Minimum Slow"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_APODIZING_1
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Apodizing type 1"
+ </source>
+ <dest>
+ *: none
+ es9218: "Apodizing type 1"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Apodizing type 1"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_APODIZING_2
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Apodizing type 2"
+ </source>
+ <dest>
+ *: none
+ es9218: "Apodizing type 2"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Apodizing type 2"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_HYBRID_FAST
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Hybrid Fast"
+ </source>
+ <dest>
+ *: none
+ es9218: "Hybrid Fast"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Hybrid Fast"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_BRICK_WALL
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Brick Wall"
+ </source>
+ <dest>
+ *: none
+ es9218: "Brick Wall"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Brick Wall"
+ </voice>
+</phrase>
+### This phrase is missing entirely, copying from english!
+<phrase>
+ id: LANG_PROPERTIES_ALBUMARTIST
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Album Artist]"
+ </source>
+ <dest>
+ *: "[Album Artist]"
+ </dest>
+ <voice>
+ *: "Album Artist"
+ </voice>
+</phrase>
+### This phrase is missing entirely, copying from english!
+<phrase>
+ id: LANG_PROPERTIES_GENRE
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Genre]"
+ </source>
+ <dest>
+ *: "[Genre]"
+ </dest>
+ <voice>
+ *: "Genre"
+ </voice>
+</phrase>
+### This phrase is missing entirely, copying from english!
+<phrase>
+ id: LANG_PROPERTIES_COMMENT
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Comment]"
+ </source>
+ <dest>
+ *: "[Comment]"
+ </dest>
+ <voice>
+ *: "Comment"
+ </voice>
+</phrase>
+### This phrase is missing entirely, copying from english!
+<phrase>
+ id: LANG_PROPERTIES_COMPOSER
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Composer]"
+ </source>
+ <dest>
+ *: "[Composer]"
+ </dest>
+ <voice>
+ *: "Composer"
+ </voice>
+</phrase>
+### This phrase is missing entirely, copying from english!
+<phrase>
+ id: LANG_PROPERTIES_YEAR
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Year]"
+ </source>
+ <dest>
+ *: "[Year]"
+ </dest>
+ <voice>
+ *: "Year"
+ </voice>
+</phrase>
+### This phrase is missing entirely, copying from english!
+<phrase>
+ id: LANG_PROPERTIES_TRACKNUM
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Tracknum]"
+ </source>
+ <dest>
+ *: "[Tracknum]"
+ </dest>
+ <voice>
+ *: "Track number"
+ </voice>
+</phrase>
+### This phrase is missing entirely, copying from english!
+<phrase>
+ id: LANG_PROPERTIES_DISCNUM
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Discnum]"
+ </source>
+ <dest>
+ *: "[Discnum]"
+ </dest>
+ <voice>
+ *: "Disc number"
+ </voice>
+</phrase>
+### This phrase is missing entirely, copying from english!
+<phrase>
+ id: LANG_PROPERTIES_FREQUENCY
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Frequency]"
+ </source>
+ <dest>
+ *: "[Frequency]"
+ </dest>
+ <voice>
+ *: "Frequency"
+ </voice>
+</phrase>
+### This phrase is missing entirely, copying from english!
+<phrase>
+ id: LANG_PROPERTIES_BITRATE
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Bitrate]"
+ </source>
+ <dest>
+ *: "[Bitrate]"
+ </dest>
+ <voice>
+ *: "Bit rate"
+ </voice>
+</phrase>
+<phrase>
+ id: VOICE_NUMERIC_TENS_SWAP_SEPARATOR
+ desc: voice only, for speaking numbers in languages that swap the tens and ones fields. Leave blank for languages that do not need it, such as English ("231" => "two hundred thirty one") but other languages may speak it as "two hundred one [AND] thirty"
+ user: core
+ <source>
+ *: ""
+ </source>
+ <dest>
+ *: ""
+ </dest>
+ <voice>
+ *: ""
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_VOICED_DATE_FORMAT
+ desc: format string for how dates will be read back. Y == 4-digit year, A == month name, m == numeric month, d == numeric day. For example, "AdY" will read "January 21 2021"
+ user: core
+ <source>
+ *: "dAY"
+ </source>
+ <dest>
+ *: "AdY"
+ </dest>
+ <voice>
+ *: ""
+ </voice>
+</phrase>
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 667d1239ca..dab9ed8508 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -15954,3 +15954,157 @@
*: "Reload After Saving"
</voice>
</phrase>
+<phrase>
+ id: LANG_PROPERTIES_ALBUMARTIST
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Album Artist]"
+ </source>
+ <dest>
+ *: "[Album Artist]"
+ </dest>
+ <voice>
+ *: "Album Artist"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_GENRE
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Genre]"
+ </source>
+ <dest>
+ *: "[Genre]"
+ </dest>
+ <voice>
+ *: "Genre"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_COMMENT
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Comment]"
+ </source>
+ <dest>
+ *: "[Comment]"
+ </dest>
+ <voice>
+ *: "Comment"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_COMPOSER
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Composer]"
+ </source>
+ <dest>
+ *: "[Composer]"
+ </dest>
+ <voice>
+ *: "Composer"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_YEAR
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Year]"
+ </source>
+ <dest>
+ *: "[Year]"
+ </dest>
+ <voice>
+ *: "Year"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_TRACKNUM
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Tracknum]"
+ </source>
+ <dest>
+ *: "[Tracknum]"
+ </dest>
+ <voice>
+ *: "Track number"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_DISCNUM
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Discnum]"
+ </source>
+ <dest>
+ *: "[Discnum]"
+ </dest>
+ <voice>
+ *: "Disc number"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_FREQUENCY
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Frequency]"
+ </source>
+ <dest>
+ *: "[Frequency]"
+ </dest>
+ <voice>
+ *: "Frequency"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_BITRATE
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Bitrate]"
+ </source>
+ <dest>
+ *: "[Bitrate]"
+ </dest>
+ <voice>
+ *: "Bit rate"
+ </voice>
+</phrase>
+<phrase>
+ id: VOICE_NUMERIC_TENS_SWAP_SEPARATOR
+ desc: voice only, for speaking numbers in languages that swap the tens and ones fields. Leave blank for languages that do not need it, such as English ("231" => "two hundred thirty one") but other languages may speak it as "two hundred one [AND] thirty"
+ user: core
+ <source>
+ *: ""
+ </source>
+ <dest>
+ *: ""
+ </dest>
+ <voice>
+ *: ""
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_VOICED_DATE_FORMAT
+ desc: format string for how dates will be read back. Y == 4-digit year, A == month name, m == numeric month, d == numeric day. For example, "AdY" will read "January 21 2021"
+ user: core
+ <source>
+ *: "dAY"
+ </source>
+ <dest>
+ *: "dAY"
+ </dest>
+ <voice>
+ *: ""
+ </voice>
+</phrase>
diff --git a/apps/lang/magyar.lang b/apps/lang/magyar.lang
index 96e5833e8e..883b05cb93 100644
--- a/apps/lang/magyar.lang
+++ b/apps/lang/magyar.lang
@@ -140,7 +140,7 @@
*: "Betöltés ..."
</dest>
<voice>
- *: "Loading"
+ *: "Betöltés"
</voice>
</phrase>
<phrase>
@@ -154,7 +154,7 @@
*: "Betöltés... %d%% kész (%s)"
</dest>
<voice>
- *: ""
+ *: "Betöltés"
</voice>
</phrase>
<phrase>
@@ -210,7 +210,7 @@
*: "nem sikerült"
</dest>
<voice>
- *: ""
+ *: "nem sikerült"
</voice>
</phrase>
<phrase>
@@ -247,7 +247,6 @@
user: core
<source>
*: "PLAY = Yes"
- archosplayer: "(PLAY/STOP)"
cowond2*: "MENU = Yes"
gigabeat*,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh10_5gb,mrobe100,sansac200*,sansaclip*,sansaconnect,sansae200*,sansafuze*: "SELECT = Yes"
iriverh100,iriverh120,iriverh300: "NAVI = Yes"
@@ -255,7 +254,6 @@
</source>
<dest>
*: "PLAY = Igen"
- archosplayer: "(PLAY/STOP)"
cowond2*: "MENU = Igen"
gigabeat*,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh10_5gb,mrobe100,sansac200*,sansaclip*,sansaconnect,sansae200*,sansafuze*: "SELECT = Igen"
iriverh100,iriverh120,iriverh300: "NAVI = Igen"
@@ -271,15 +269,12 @@
user: core
<source>
*: "Any Other = No"
- archosplayer: none
</source>
<dest>
*: "Egyéb = Mégsem"
- archosplayer: none
</dest>
<voice>
*: ""
- archosplayer: none
</voice>
</phrase>
<phrase>
@@ -436,10 +431,10 @@
*: "Plugins"
</source>
<dest>
- *: "Pluginok"
+ *: "Kiegészítők"
</dest>
<voice>
- *: "Plugins"
+ *: "Kiegészítők"
</voice>
</phrase>
<phrase>
@@ -464,10 +459,10 @@
*: "Select Bookmark"
</source>
<dest>
- *: "Könyvjelző választása"
+ *: "Könyvjelző kiválasztása"
</dest>
<voice>
- *: "Select Bookmark"
+ *: "Könyvjelző kiválasztása"
</voice>
</phrase>
<phrase>
@@ -607,7 +602,7 @@
*: "Nincs könyvjelző"
</dest>
<voice>
- *: ""
+ *: "Nincs könyvjelző"
</voice>
</phrase>
<phrase>
@@ -646,10 +641,10 @@
*: "Bass"
</source>
<dest>
- *: "Mély"
+ *: "Mély kiemelés"
</dest>
<voice>
- *: "Bass"
+ *: "Mély kiemelés"
</voice>
</phrase>
<phrase>
@@ -660,10 +655,10 @@
*: "Treble"
</source>
<dest>
- *: "Magas"
+ *: "Magas kiemelés"
</dest>
<voice>
- *: "Treble"
+ *: "Magas kiemelés"
</voice>
</phrase>
<phrase>
@@ -674,10 +669,10 @@
*: "Balance"
</source>
<dest>
- *: "Balance"
+ *: "Balansz"
</dest>
<voice>
- *: "Balance"
+ *: "Balansz"
</voice>
</phrase>
<phrase>
@@ -800,10 +795,10 @@
*: "Crossfeed"
</source>
<dest>
- *: "Crossfeed"
+ *: "Térakusztika fejhallgatón (crossfeed)"
</dest>
<voice>
- *: "Crossfeed"
+ *: "Térakusztika fejhallgatón"
</voice>
</phrase>
<phrase>
@@ -996,10 +991,10 @@
*: "%d Hz Band Gain"
</source>
<dest>
- *: "%d Hz sáv módosítás"
+ *: "%d Hz sáv nyereség"
</dest>
<voice>
- *: ""
+ *: "Hz sáv nyereség"
</voice>
</phrase>
<phrase>
@@ -1010,10 +1005,10 @@
*: "Low Shelf Filter"
</source>
<dest>
- *: "Alsó perem szűrő"
+ *: "Alsó szűrő határa"
</dest>
<voice>
- *: ""
+ *: "Alsó szűrő határa"
</voice>
</phrase>
<phrase>
@@ -1027,7 +1022,7 @@
*: "Csúcsszűrő %d"
</dest>
<voice>
- *: ""
+ *: "Csúcsszűrő"
</voice>
</phrase>
<phrase>
@@ -1038,10 +1033,10 @@
*: "High Shelf Filter"
</source>
<dest>
- *: "Felső perem szűrő"
+ *: "Felső szűrő határa"
</dest>
<voice>
- *: ""
+ *: "Felső szűrő határa"
</voice>
</phrase>
<phrase>
@@ -1094,163 +1089,10 @@
*: "Dithering"
</source>
<dest>
- *: "Dithering"
- </dest>
- <voice>
- *: "Dithering"
- </voice>
-</phrase>
-<phrase>
- id: LANG_LOUDNESS
- desc: in sound_settings
- user: core
- <source>
- *: none
- masf: "Loudness"
- </source>
- <dest>
- *: none
- masf: "Loudness"
- </dest>
- <voice>
- *: none
- masf: "Loudness"
- </voice>
-</phrase>
-<phrase>
- id: LANG_AUTOVOL
- desc: in sound_settings
- user: core
- <source>
- *: none
- masf: "Auto Volume"
- </source>
- <dest>
- *: none
- masf: "Automatikus hangerő"
- </dest>
- <voice>
- *: none
- masf: "Auto Volume"
- </voice>
-</phrase>
-<phrase>
- id: LANG_DECAY
- desc: in sound_settings
- user: core
- <source>
- *: none
- masf: "AV Decay Time"
- </source>
- <dest>
- *: none
- masf: "Csökkentés átlagos ideje"
- </dest>
- <voice>
- *: none
- masf: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_SUPERBASS
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "Super Bass"
- </source>
- <dest>
- *: none
- masf: "Super Bass"
- </dest>
- <voice>
- *: none
- masf: "Super bass"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_ENABLE
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Enable"
- </source>
- <dest>
- *: none
- masf: "MDB bekapcsolása"
+ *: "Zajmoduláció (dithering)"
</dest>
<voice>
- *: none
- masf: "MDB Enable"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_STRENGTH
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Strength"
- </source>
- <dest>
- *: none
- masf: "MDB erőssége"
- </dest>
- <voice>
- *: none
- masf: "MDB Strength"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_HARMONICS
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Harmonics"
- </source>
- <dest>
- *: none
- masf: "MDB felhangok"
- </dest>
- <voice>
- *: none
- masf: "MDB Harmonics"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_CENTER
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Centre Frequency"
- </source>
- <dest>
- *: none
- masf: "MDB középfrekvencia"
- </dest>
- <voice>
- *: none
- masf: "MDB Center frequency"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_SHAPE
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Shape"
- </source>
- <dest>
- *: none
- masf: "MDB forma"
- </dest>
- <voice>
- *: none
- masf: "MDB Shape"
+ *: "Zajmoduláció"
</voice>
</phrase>
<phrase>
@@ -2405,7 +2247,8 @@
hold_button: "Világítás (Hold gomb lenyomásakor)"
</dest>
<voice>
- *: "Backlight on hold"
+ *: none
+ hold_button: "Világítás (Hold gomb lenyomásakor)"
</voice>
</phrase>
<phrase>
@@ -2488,23 +2331,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_NEVER
- desc: in lcd settings
- user: core
- <source>
- *: none
- lcd_sleep: "Never"
- </source>
- <dest>
- *: none
- lcd_sleep: "Soha"
- </dest>
- <voice>
- *: none
- lcd_sleep: "Never"
- </voice>
-</phrase>
-<phrase>
id: LANG_BRIGHTNESS
desc: in settings_menu
user: core
@@ -2656,7 +2482,7 @@
</dest>
<voice>
*: none
- ldc_non-mono: "Background Colour"
+ lcd_color: "Background Colour"
</voice>
</phrase>
<phrase>
@@ -3026,23 +2852,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_BUTTON_BAR
- desc: in settings menu
- user: core
- <source>
- *: none
- recorder_pad: "Button Bar"
- </source>
- <dest>
- *: none
- recorder_pad: "Kapcsoló sor"
- </dest>
- <voice>
- *: none
- recorder_pad: "Button bar"
- </voice>
-</phrase>
-<phrase>
id: LANG_VOLUME_DISPLAY
desc: Volume type title
user: core
@@ -3095,7 +2904,7 @@
*: "Számmal"
</dest>
<voice>
- *: "Numeric"
+ *: "Számmal"
</voice>
</phrase>
<phrase>
@@ -3104,15 +2913,12 @@
user: core
<source>
*: "Peak Meter"
- masd: none
</source>
<dest>
*: "Kivezérlés mutató"
- masd: none
</dest>
<voice>
- *: "Peak Meter"
- masd: none
+ *: "Kivezérlés mutató"
</voice>
</phrase>
<phrase>
@@ -3121,15 +2927,12 @@
user: core
<source>
*: "Clip Hold Time"
- masd: none
</source>
<dest>
*: "Clip Hold Time"
- masd: none
</dest>
<voice>
*: "Clip Hold Time"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3138,15 +2941,12 @@
user: core
<source>
*: "Peak Hold Time"
- masd: none
</source>
<dest>
*: "Peak Hold Time"
- masd: none
</dest>
<voice>
*: "Peak Hold Time"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3155,15 +2955,12 @@
user: core
<source>
*: "Eternal"
- masd: none
</source>
<dest>
*: "Végtelen"
- masd: none
</dest>
<voice>
- *: "Eternal"
- masd: none
+ *: "Végtelen"
</voice>
</phrase>
<phrase>
@@ -3172,15 +2969,12 @@
user: core
<source>
*: "Peak Release"
- masd: none
</source>
<dest>
*: "Peak Release"
- masd: none
</dest>
<voice>
*: "Peak Release"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3189,15 +2983,12 @@
user: core
<source>
*: "Scale"
- masd: none
</source>
<dest>
*: "Skála"
- masd: none
</dest>
<voice>
- *: "Scale"
- masd: none
+ *: "Skála"
</voice>
</phrase>
<phrase>
@@ -3206,15 +2997,12 @@
user: core
<source>
*: "Logarithmic (dB)"
- masd: none
</source>
<dest>
*: "Logaritmikus (dB)"
- masd: none
</dest>
<voice>
- *: "Logarithmic decibel"
- masd: none
+ *: "Logaritmikus decibel"
</voice>
</phrase>
<phrase>
@@ -3223,15 +3011,12 @@
user: core
<source>
*: "Linear (%)"
- masd: none
</source>
<dest>
*: "Lineáris (%)"
- masd: none
</dest>
<voice>
*: "Linear percent"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3240,15 +3025,12 @@
user: core
<source>
*: "Minimum Of Range"
- masd: none
</source>
<dest>
*: "Legkisebb érték"
- masd: none
</dest>
<voice>
- *: "Minimum Of Range"
- masd: none
+ *: "Legkisebb érték"
</voice>
</phrase>
<phrase>
@@ -3257,15 +3039,12 @@
user: core
<source>
*: "Maximum Of Range"
- masd: none
</source>
<dest>
*: "Legnagyobb érték"
- masd: none
</dest>
<voice>
- *: "Maximum Of Range"
- masd: none
+ *: "Legnagyobb érték"
</voice>
</phrase>
<phrase>
@@ -3480,8 +3259,8 @@
</dest>
<voice>
*: none
- button_light: "Button Light Timeout"
- sansae200*,sansafuze*: "Wheel Light Timeout"
+ button_light: "Gomb világításának hossza"
+ sansae200*,sansafuze*: "Kerék világításának hossza"
</voice>
</phrase>
<phrase>
@@ -3498,7 +3277,7 @@
</dest>
<voice>
*: none
- gigabeatfx: "Button Light Brightness"
+ buttonlight_brightness: "Gomb-világítás erőssége"
</voice>
</phrase>
<phrase>
@@ -3595,14 +3374,17 @@
<source>
*: none
battery_types: "Alkaline"
+ xduoox3: "Newer (2000 mAh)"
</source>
<dest>
*: none
battery_types: "Alkáli"
+ xduoox3: "Újabb (2000 mAh)"
</dest>
<voice>
*: none
battery_types: "Alkaline"
+ xduoox3: "Újabb 2000 m A h"
</voice>
</phrase>
<phrase>
@@ -3612,14 +3394,17 @@
<source>
*: none
battery_types: "NiMH"
+ xduoox3: "Older (1500 mAh)"
</source>
<dest>
*: none
battery_types: "NiMH"
+ xduoox3: "Régebbi (1500 mAh)"
</dest>
<voice>
*: none
battery_types: "Nickel metal hydride"
+ xduoox3: "Régebbi 1500 m A h"
</voice>
</phrase>
<phrase>
@@ -4418,20 +4203,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_BOOKMARK_SETTINGS_UNIQUE_ONLY
- desc: Save only on bookmark for each playlist in recent bookmarks
- user: core
- <source>
- *: "Unique only"
- </source>
- <dest>
- *: "Unique only"
- </dest>
- <voice>
- *: "Unique only"
- </voice>
-</phrase>
-<phrase>
id: LANG_LANGUAGE
desc: in settings_menu
user: core
@@ -4453,10 +4224,10 @@
*: "New Language"
</source>
<dest>
- *: "Új nyelv"
+ *: "Nyelv beállítva"
</dest>
<voice>
- *: "New Language"
+ *: "Nyelv beállítva"
</voice>
</phrase>
<phrase>
@@ -4467,10 +4238,10 @@
*: "Voice"
</source>
<dest>
- *: "Hangok"
+ *: "Beszéd"
</dest>
<voice>
- *: "Voice"
+ *: "Beszéd"
</voice>
</phrase>
<phrase>
@@ -4551,10 +4322,10 @@
*: "Numbers"
</source>
<dest>
- *: "számok"
+ *: "Számok"
</dest>
<voice>
- *: "Numbers"
+ *: "Számok"
</voice>
</phrase>
<phrase>
@@ -4565,10 +4336,10 @@
*: "Spell"
</source>
<dest>
- *: "betűz"
+ *: "Betűz"
</dest>
<voice>
- *: "Spell"
+ *: "Betűz"
</voice>
</phrase>
<phrase>
@@ -4847,57 +4618,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_BUTTONBAR_MENU
- desc: in button bar
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Menu"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "Menü"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_FM_BUTTONBAR_EXIT
- desc: in radio screen
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Exit"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "Kilépés"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_FM_BUTTONBAR_ACTION
- desc: in radio screen
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Action"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "Művelet"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
- </voice>
-</phrase>
-<phrase>
id: LANG_PRESET
desc: in button bar and radio screen / menu
user: core
@@ -4911,41 +4631,7 @@
</dest>
<voice>
*: none
- radio: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_FM_BUTTONBAR_ADD
- desc: in radio screen
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Add"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "Hozzáad"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_FM_BUTTONBAR_RECORD
- desc: in radio screen
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Record"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "Felvétel"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
+ radio: "Beállított állomás"
</voice>
</phrase>
<phrase>
@@ -5060,11 +4746,11 @@
</source>
<dest>
*: none
- radio: "Keresés"
+ radio: "Hangolás"
</dest>
<voice>
*: none
- radio: ""
+ radio: "Hangolás"
</voice>
</phrase>
<phrase>
@@ -5195,11 +4881,12 @@
radio: "US / Canada"
</source>
<dest>
- *: "Észak-Amerika"
+ *: none
+ radio: "Észak-Amerika"
</dest>
<voice>
*: none
- radio: "US and Canada"
+ radio: "USA / Kama"
</voice>
</phrase>
<phrase>
@@ -5280,7 +4967,7 @@
</source>
<dest>
*: none
- recording: "wav"
+ recording: "WAV"
</dest>
<voice>
*: none
@@ -5373,23 +5060,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_RECORDING_QUALITY
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording_hwcodec: "Quality"
- </source>
- <dest>
- *: none
- recording_hwcodec: "Minőség"
- </dest>
- <voice>
- *: none
- recording_hwcodec: "Quality"
- </voice>
-</phrase>
-<phrase>
id: LANG_FREQUENCY
desc: in recording and playback settings
user: core
@@ -5403,7 +5073,7 @@
</dest>
<voice>
*: none
- play_frequency,recording: "Frequency"
+ play_frequency,recording: "Mintavétel"
</voice>
</phrase>
<phrase>
@@ -5456,8 +5126,8 @@
</dest>
<voice>
*: none
- iriverh100,iriverh120,iriverh300: "Internal Microphone"
- recording: "Microphone"
+ iriverh100,iriverh120,iriverh300: "Belső mikrofon"
+ recording: "Mikrofon"
</voice>
</phrase>
<phrase>
@@ -5487,28 +5157,11 @@
</source>
<dest>
*: none
- recording: "Line In"
+ recording: "Vonalbemenet"
</dest>
<voice>
*: none
- recording: "Line In"
- </voice>
-</phrase>
-<phrase>
- id: LANG_RECORDING_EDITABLE
- desc: Editable recordings setting
- user: core
- <source>
- *: none
- recording_hwcodec: "Independent Frames"
- </source>
- <dest>
- *: none
- recording_hwcodec: "Független mp3-keretek"
- </dest>
- <voice>
- *: none
- recording_hwcodec: "Independent frames"
+ recording: "Vonalbemenet"
</voice>
</phrase>
<phrase>
@@ -5848,7 +5501,7 @@
</dest>
<voice>
*: none
- recordng: "New file"
+ recording: "Új fájl"
</voice>
</phrase>
<phrase>
@@ -6283,23 +5936,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_SHUTDOWN
- desc: in main menu
- user: core
- <source>
- *: none
- soft_shutdown: "Shut down"
- </source>
- <dest>
- *: none
- soft_shutdown: "Kikapcsol"
- </dest>
- <voice>
- *: none
- soft_shutdown: "Shut down"
- </voice>
-</phrase>
-<phrase>
id: LANG_ROCKBOX_INFO
desc: displayed topmost on the info screen and in the info menu
user: core
@@ -6310,7 +5946,7 @@
*: "Rockbox névjegy"
</dest>
<voice>
- *: "Rockbox Info"
+ *: "Rockbox névjegy"
</voice>
</phrase>
<phrase>
@@ -6319,14 +5955,12 @@
user: core
<source>
*: "Buffer:"
- archosplayer: "Buf:"
</source>
<dest>
*: "Puffer:"
- archosplayer: "Puf:"
</dest>
<voice>
- *: ""
+ *: "Puffer:"
</voice>
</phrase>
<phrase>
@@ -6398,21 +6032,19 @@
user: core
<source>
*: none
- archosondio*: "MMC:"
multivolume: "HD1"
sansac200*,sansaclipplus,sansae200*,sansafuze*: "mSD:"
xduoox3: "mSD2:"
</source>
<dest>
*: none
- archosondio*: "MMC:"
multivolume: "HD1"
sansac200*,sansaclipplus,sansae200*,sansafuze*: "mSD"
xduoox3: "mSD2:"
</dest>
<voice>
*: none
- archosondio*: "Multimedia card"
+ multivolume: "H D 1"
sansac200*,sansaclipplus,sansae200*,sansafuze*: "micro Secure Digital card:"
xduoox3: "micro Secure Digital card 2:"
</voice>
@@ -7477,15 +7109,12 @@
user: core
<source>
*: "End of Song List"
- archosplayer: "End of List"
</source>
<dest>
*: "Vége a számok listájának"
- archosplayer: "Lista vége"
</dest>
<voice>
*: "End of Song List"
- archosplayer: "End of List"
</voice>
</phrase>
<phrase>
@@ -7729,41 +7358,7 @@
</dest>
<voice>
*: none
- recording: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_CONFIRM_SHUTDOWN
- desc: in shutdown screen
- user: core
- <source>
- *: none
- soft_shutdown: "Press OFF to shut down"
- </source>
- <dest>
- *: none
- soft_shutdown: "OFF - Kikapcsolás"
- </dest>
- <voice>
- *: none
- soft_shutdown: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_REMOVE_MMC
- desc: before acknowledging usb in case an MMC is inserted (Ondio)
- user: core
- <source>
- *: none
- archosondio*: "Please remove inserted MMC"
- </source>
- <dest>
- *: none
- archosondio*: "Vedd ki a multimédia kártyát"
- </dest>
- <voice>
- *: none
- archosondio*: "Please remove multimedia card"
+ recording: "-végtelen"
</voice>
</phrase>
<phrase>
@@ -7796,7 +7391,7 @@
</phrase>
<phrase>
id: LANG_OFF_ABORT
- desc: Used on archosrecorder models
+ desc: Used on many models
user: core
<source>
*: "OFF to abort"
@@ -7888,7 +7483,7 @@
*: "Inkompatibilis modell"
</dest>
<voice>
- *: ""
+ *: "Inkompatibilis modell"
</voice>
</phrase>
<phrase>
@@ -7902,7 +7497,7 @@
*: "Inkompatibilis verzió"
</dest>
<voice>
- *: ""
+ *: "Inkompatibilis verzió"
</voice>
</phrase>
<phrase>
@@ -7916,7 +7511,7 @@
*: "Plugin hibát jelzett"
</dest>
<voice>
- *: ""
+ *: "Plugin hibát jelzett"
</voice>
</phrase>
<phrase>
@@ -7993,23 +7588,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_BATTERY_TOPOFF_CHARGE
- desc: in info display, shows that top off charge is running Only for V1 archosrecorder
- user: core
- <source>
- *: none
- archosrecorder: "Battery: Top-Off Chg"
- </source>
- <dest>
- *: none
- archosrecorder: "Battery: Top-Off Chg"
- </dest>
- <voice>
- *: none
- archosrecorder: "Top off charge"
- </voice>
-</phrase>
-<phrase>
id: LANG_BATTERY_TRICKLE_CHARGE
desc: in info display, shows that trickle charge is running
user: core
@@ -8069,48 +7647,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_KILOBYTE
- desc: a unit postfix, also voiced
- user: core
- <source>
- *: "KB"
- </source>
- <dest>
- *: "kB"
- </dest>
- <voice>
- *: "kilobyte"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MEGABYTE
- desc: a unit postfix, also voiced
- user: core
- <source>
- *: "MB"
- </source>
- <dest>
- *: "MB"
- </dest>
- <voice>
- *: "megabyte"
- </voice>
-</phrase>
-<phrase>
- id: LANG_GIGABYTE
- desc: a unit postfix, also voiced
- user: core
- <source>
- *: "GB"
- </source>
- <dest>
- *: "GB"
- </dest>
- <voice>
- *: "gigabyte"
- </voice>
-</phrase>
-<phrase>
id: LANG_POINT
desc: decimal separator for composing numbers
user: core
@@ -9341,7 +8877,8 @@
remote: ""
</dest>
<voice>
- *: "remote while-playing-screen"
+ *: none
+ remote: "remote while-playing-screen"
</voice>
</phrase>
<phrase>
@@ -9446,241 +8983,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_SYSFONT_MODE
- desc: in wps F2 pressed
- user: core
- <source>
- *: "Mode:"
- </source>
- <dest>
- *: "Mód:"
- </dest>
- <voice>
- *: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_DIRBROWSE_F1
- desc: in dir browser, F1 button bar text
- user: core
- <source>
- *: none
- recorder_pad: "Menu"
- </source>
- <dest>
- *: none
- recorder_pad: "Menü"
- </dest>
- <voice>
- *: none
- recorder_pad: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_DIRBROWSE_F2
- desc: in dir browser, F2 button bar text
- user: core
- <source>
- *: none
- recorder_pad: "Option"
- </source>
- <dest>
- *: none
- recorder_pad: "Beállítások"
- </dest>
- <voice>
- *: none
- recorder_pad: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_DIRBROWSE_F3
- desc: in dir browser, F3 button bar text
- user: core
- <source>
- *: none
- recorder_pad: "LCD"
- </source>
- <dest>
- *: none
- recorder_pad: "LCD"
- </dest>
- <voice>
- *: none
- recorder_pad: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_CHANNEL_STEREO
- desc: in sound_settings
- user: core
- <source>
- *: none
- recording: "Stereo"
- </source>
- <dest>
- *: none
- recording: "Sztereó"
- </dest>
- <voice>
- *: none
- recording: "Stereo"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_CHANNEL_MONO
- desc: in sound_settings
- user: core
- <source>
- *: none
- recording: "Mono"
- </source>
- <dest>
- *: none
- recording: "Monó"
- </dest>
- <voice>
- *: none
- recording: "Mono"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORDING_QUALITY
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording_hwcodec: "Quality"
- </source>
- <dest>
- *: none
- recording_hwcodec: "Minőség"
- </dest>
- <voice>
- *: none
- recording_hwcodec: "Quality"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORDING_FREQUENCY
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Frequency"
- </source>
- <dest>
- *: none
- recording: "Frekvencia"
- </dest>
- <voice>
- *: none
- recording: "Frequency"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORDING_SOURCE
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Source"
- </source>
- <dest>
- *: none
- recording: "Forrás"
- </dest>
- <voice>
- *: none
- recording: "Source"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORDING_SRC_MIC
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Int. Mic"
- </source>
- <dest>
- *: none
- recording: "Belső mikr."
- </dest>
- <voice>
- *: none
- recording: "Internal Microphone"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_LINE_IN
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Line In"
- </source>
- <dest>
- *: none
- recording: "Line In"
- </dest>
- <voice>
- *: none
- recording: "Line In"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORDING_SRC_DIGITAL
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Digital"
- </source>
- <dest>
- *: none
- recording: "Digitális"
- </dest>
- <voice>
- *: none
- recording: "Digital"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_CHANNELS
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Channels"
- </source>
- <dest>
- *: none
- recording: "Csatornák"
- </dest>
- <voice>
- *: none
- recording: "Channels"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORD_TRIGGER
- desc: in recording settings_menu
- user: core
- <source>
- *: none
- recording: "Trigger"
- </source>
- <dest>
- *: none
- recording: "Trigger"
- </dest>
- <voice>
- *: none
- recording: "Trigger"
- </voice>
-</phrase>
-<phrase>
id: VOICE_OF
desc: spoken only, as in 3/8 => 3 of 8
user: core
@@ -9975,7 +9277,7 @@
</dest>
<voice>
*: none
- gigabeatfx,ipod6g,ipodvideo,mpiohd200,mpiohd300,mrobe100: "Bass Cutoff"
+ gigabeatfx,ipod6g,ipodvideo,mpiohd200,mpiohd300,mrobe100: "Alsó határfrekvencia"
</voice>
</phrase>
<phrase>
@@ -10049,15 +9351,15 @@
user: core
<source>
*: none
- gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
+ gigabeatfx,sansafuzeplus,fiiom3k: "Touchpad Sensitivity"
</source>
<dest>
*: none
- gigabeatfx: "Érintőpad érzékenysége"
+ gigabeatfx,sansafuzeplus,fiiom3k: "Érintőpad érzékenysége"
</dest>
<voice>
*: none
- gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
+ gigabeatfx,sansafuzeplus,fiiom3k: "Érintőpad érzékenysége"
</voice>
</phrase>
<phrase>
@@ -10652,7 +9954,7 @@
</dest>
<voice>
*: none
- gigabeatfx,ipod6g,ipodvideo,mpiohd200,mpiohd300,mrobe100: "Treble Cutoff"
+ gigabeatfx,ipod6g,ipodvideo,mpiohd200,mpiohd300,mrobe100: "Magas határfrekvencia"
</voice>
</phrase>
<phrase>
@@ -12806,7 +12108,7 @@
*: "Szerző"
</dest>
<voice>
- *: ""
+ *: "Szerző"
</voice>
</phrase>
<phrase>
diff --git a/apps/lang/nederlands.lang b/apps/lang/nederlands.lang
index 3e7abc613d..6d6f286486 100644
--- a/apps/lang/nederlands.lang
+++ b/apps/lang/nederlands.lang
@@ -3798,12 +3798,10 @@
<source>
*: "Battery: %d%% %dh %dm"
ipodmini1g,ipodmini2g,iriverh10: "Batt: %d%% %dh %dm"
- iriverifp7xx: "%d%% %dh %dm"
</source>
<dest>
*: "Batterij: %d%% %du %dm"
ipodmini1g,ipodmini2g,iriverh10: "Batt: %d%% %dh %dm"
- iriverifp7xx: "%d%% %dh %dm"
</dest>
<voice>
*: "Batterijniveau"
@@ -3843,14 +3841,17 @@
user: core
<source>
*: "Int:"
+ hibylinux: "mSD:"
xduoox3: "mSD1:"
</source>
<dest>
*: "Intern:"
+ hibylinux: "mSD:"
xduoox3: "mSD1:"
</dest>
<voice>
*: "Intern"
+ hibylinux: "micro S D"
xduoox3: "micro S D 1"
</voice>
</phrase>
@@ -4032,7 +4033,7 @@
</dest>
<voice>
*: none
- gogearsa9200,iaudiom5,iaudiox5,ipod*,sansac200*,iriverh10,iriverh10_5gb,sansae200*,iriverh100,iriverh120,iriverh300,mrobe100,rtc,samsungyh*: ""
+ gigabeat*,gogearsa9200,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh100,iriverh10_5gb,iriverh120,iriverh300,mrobe100,rtc,samsungyh*,sansac200*,sansae200*: ""
</voice>
</phrase>
<phrase>
@@ -7926,16 +7927,16 @@
</phrase>
<phrase>
id: LANG_REPLACE
- desc: in onplay menu. Replace the current playlist with a new one.
+ desc: deprecated
user: core
<source>
- *: "Play Next"
+ *: ""
</source>
<dest>
- *: "Volgende afspelen"
+ *: ""
</dest>
<voice>
- *: "Volgende afspelen"
+ *: ""
</voice>
</phrase>
<phrase>
@@ -8698,7 +8699,7 @@
</dest>
<voice>
*: none
- gigabeat*,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh10_5gb,mrobe100,sansac200*,sansae200*,gogearsa9200,samsungyh*,iriverh100,iriverh120,iriverh300,rtc: ""
+ gigabeat*,gogearsa9200,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh100,iriverh10_5gb,iriverh120,iriverh300,mrobe100,rtc,samsungyh*,sansac200*,sansae200*: ""
</voice>
</phrase>
<phrase>
@@ -9601,15 +9602,15 @@
user: core
<source>
*: none
- gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
</source>
<dest>
*: none
- gigabeatfx,sansafuzeplus: "Touchpadgevoeligheid"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Touchpadgevoeligheid"
</dest>
<voice>
*: none
- gigabeatfx,sansafuzeplus: "Touchpadgevoeligheid"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Touchpadgevoeligheid"
</voice>
</phrase>
<phrase>
@@ -12130,7 +12131,7 @@
desc: Selective Actions
user: core
<source>
- *: "Play"
+ *: "Exempt Play"
</source>
<dest>
*: "Afspelen"
@@ -12158,7 +12159,7 @@
desc: Softlock behaviour setting
user: core
<source>
- *: "Disable Notify"
+ *: "Disable Locked Reminders"
</source>
<dest>
*: "Melden uitschakelen"
@@ -12284,7 +12285,7 @@
desc: Selective Actions
user: core
<source>
- *: "Skip"
+ *: "Exempt Skip"
</source>
<dest>
*: "Overslaan"
@@ -12413,7 +12414,7 @@
desc: Selective Actions
user: core
<source>
- *: "Seek"
+ *: "Exempt Seek"
</source>
<dest>
*: "Zoeken"
@@ -15021,10 +15022,10 @@
*: "Update cache"
</source>
<dest>
- *: "Update cache"
+ *: "Cache bijwerken"
</dest>
<voice>
- *: "Update cache"
+ *: "Cache bijwerken"
</voice>
</phrase>
<phrase>
@@ -15119,8 +15120,8 @@
<dest>
*: "Druk op LINKS om te annuleren."
android: "Druk op RECHTS om te annuleren."
- hifietma*,zenvision: "Druk op BACK om te annuleren."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Druk op POWER om te annuleren."
+ hifietma*,zenvision: "Druk op BACK om te annuleren."
ihifi760,ihifi960: "Dubbeltik op RETURN om te annuleren."
ihifi770,ihifi770c,ihifi800: "Druk op HOME om te annuleren."
iriverh10,samsungyh*: "Dubbeltik op LINKS om te annuleren."
@@ -15135,8 +15136,8 @@
<voice>
*: "Druk op LINKS om te annuleren."
android: "Druk op RECHTS om te annuleren."
- hifietma*,zenvision: "Druk op BACK om te annuleren."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Druk op POWER om te annuleren."
+ hifietma*,zenvision: "Druk op BACK om te annuleren."
ihifi760,ihifi960: "Dubbeltik op RETURN om te annuleren."
ihifi770,ihifi770c,ihifi800: "Druk op HOME om te annuleren."
iriverh10,samsungyh*: "Dubbeltik op LINKS om te annuleren."
@@ -15522,3 +15523,370 @@
*: "USB massa opslag modus openen?"
</voice>
</phrase>
+<phrase>
+ id: LANG_TALK_MIXER_LEVEL
+ desc: Relative volume of voice prompts
+ user: core
+ <source>
+ *: "Voice prompt volume"
+ </source>
+ <dest>
+ *: "Volume van gesproken prompt"
+ </dest>
+ <voice>
+ *: "Volume van gesproken prompt"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_SUPER_SLOW
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ filter_roll_off: "Super Slow"
+ </source>
+ <dest>
+ *: none
+ filter_roll_off: "Super Traag"
+ </dest>
+ <voice>
+ *: none
+ filter_roll_off: "Super Traag"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_LINEAR_FAST
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Linear Fast"
+ </source>
+ <dest>
+ *: none
+ es9218: "Lineair Snel"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Lineair Snel"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_LINEAR_SLOW
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Linear Slow"
+ </source>
+ <dest>
+ *: none
+ es9218: "Lineair Traag"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Lineair Traag"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_MINIMUM_FAST
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Minimum Fast"
+ </source>
+ <dest>
+ *: none
+ es9218: "Minimaal Snel"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Minimaal Snel"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_MINIMUM_SLOW
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Minimum Slow"
+ </source>
+ <dest>
+ *: none
+ es9218: "Minimaal Traag"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Minimaal Traag"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_APODIZING_1
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Apodizing type 1"
+ </source>
+ <dest>
+ *: none
+ es9218: "Apodiserend type 1"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Apodiserend type 1"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_APODIZING_2
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Apodizing type 2"
+ </source>
+ <dest>
+ *: none
+ es9218: "Apodiserend type 2"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Apodiserend type 2"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_HYBRID_FAST
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Hybrid Fast"
+ </source>
+ <dest>
+ *: none
+ es9218: "Hybride Snel"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Hybride Snel"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_FILTER_BRICK_WALL
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ es9218: "Brick Wall"
+ </source>
+ <dest>
+ *: none
+ es9218: "Stenen Muur"
+ </dest>
+ <voice>
+ *: none
+ es9218: "Stenen Muur"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_DAC_POWER_MODE
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ dac_power_mode: "DAC's power mode"
+ es9218: "DAC's output level"
+ </source>
+ <dest>
+ *: none
+ dac_power_mode: "DAC energiemodus"
+ es9218: "DAC uitgangsniveau"
+ </dest>
+ <voice>
+ *: none
+ dac_power_mode: "DAC energiemodus"
+ es9218: "DAC uitgangsniveau"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_DAC_POWER_HIGH
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ dac_power_mode: "High performance"
+ es9218: "High Gain (2 Vrms)"
+ </source>
+ <dest>
+ *: none
+ dac_power_mode: "Hoge uitvoering"
+ es9218: "Hoge Versterking (2 Vrms)"
+ </dest>
+ <voice>
+ *: none
+ dac_power_mode: "Hoge uitvoering"
+ es9218: "Hoge Versterking (2 Vrms)"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_DAC_POWER_LOW
+ desc: in sound settings
+ user: core
+ <source>
+ *: none
+ dac_power_mode: "Save battery"
+ es9218: "Low Gain (1 Vrms)"
+ </source>
+ <dest>
+ *: none
+ dac_power_mode: "Energie besparen"
+ es9218: "Lage versterking (1 Vrms)"
+ </dest>
+ <voice>
+ *: none
+ dac_power_mode: "Energie besparen"
+ es9218: "Lage versterking (1 Vrms)"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_CLEAR_LIST_AND_PLAY_NEXT
+ desc: in onplay menu. Replace current playlist with selected tracks
+ user: core
+ <source>
+ *: "Clear List & Play Next"
+ </source>
+ <dest>
+ *: "Lijst Wissen en Volgende Afspelen"
+ </dest>
+ <voice>
+ *: "Lijst Wissen en Volgende Afspelen"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_QUEUE_MENU
+ desc: in onplay menu
+ user: core
+ <source>
+ *: "Queue..."
+ </source>
+ <dest>
+ *: "Rij..."
+ </dest>
+ <voice>
+ *: "Rij..."
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_SHOW_QUEUE_OPTIONS
+ desc: in Current Playlist settings
+ user: core
+ <source>
+ *: "Show Queue Options"
+ </source>
+ <dest>
+ *: "Wachtrij-Opties Weergeven"
+ </dest>
+ <voice>
+ *: "Wachtrij Opties Weergeven"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_SHOW_SHUFFLED_ADDING_OPTIONS
+ desc: in Current Playlist settings
+ user: core
+ <source>
+ *: "Show Shuffled Adding Options"
+ </source>
+ <dest>
+ *: "Opties voor Geschud Toevoeging Weergeven"
+ </dest>
+ <voice>
+ *: "Opties voor Geschud Toevoeging Weergeven"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_IN_SUBMENU
+ desc: in Settings
+ user: core
+ <source>
+ *: "In Submenu"
+ </source>
+ <dest>
+ *: "In Submenu"
+ </dest>
+ <voice>
+ *: "In Submenu"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_CLEAR_LIST_AND_PLAY_SHUFFLED
+ desc: in onplay menu. Replace current playlist with selected tracks in random order.
+ user: core
+ <source>
+ *: "Clear List & Play Shuffled"
+ </source>
+ <dest>
+ *: "Lijst Wissen en in Geschude Volgorde Afspelen"
+ </dest>
+ <voice>
+ *: "Lijst Wissen en in Geschude Volgorde Afspelen"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_SOFTLOCK_DISABLE_ALL_NOTIFY
+ desc: disable all softlock notifications
+ user: core
+ <source>
+ *: "Disable All Lock Notifications"
+ </source>
+ <dest>
+ *: "Alle Vergrendelingsmeldingen Uitschakelen"
+ </dest>
+ <voice>
+ *: "Alle Vergrendelingsmeldingen Uitschakelen"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_ACTION_VOLUME
+ desc: exempt volume from softlock
+ user: core
+ <source>
+ *: "Exempt Volume"
+ </source>
+ <dest>
+ *: "Volume Vrijstellen"
+ </dest>
+ <voice>
+ *: "Volume Vrijstellen"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_ACTION_ALWAYSAUTOLOCK
+ desc: always prime autolock
+ user: core
+ <source>
+ *: "Always Autolock"
+ </source>
+ <dest>
+ *: "Altijd Auto-vergrendelen"
+ </dest>
+ <voice>
+ *: "Altijd Auto-vergrendelen"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PLAYLIST_RELOAD_AFTER_SAVE
+ desc: reload playlist after saving
+ user: core
+ <source>
+ *: "Reload After Saving"
+ </source>
+ <dest>
+ *: "Herladen na Opslaan"
+ </dest>
+ <voice>
+ *: "Herladen na Opslaan"
+ </voice>
+</phrase>
diff --git a/apps/lang/polski.lang b/apps/lang/polski.lang
index ec455bc7c7..aab35b556f 100644
--- a/apps/lang/polski.lang
+++ b/apps/lang/polski.lang
@@ -15887,3 +15887,129 @@
es9218: "Ściana"
</voice>
</phrase>
+<phrase>
+ id: LANG_PROPERTIES_ALBUMARTIST
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Album Artist]"
+ </source>
+ <dest>
+ *: "[Wykonawca albumu]"
+ </dest>
+ <voice>
+ *: "Wykonawca albumu"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_GENRE
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Genre]"
+ </source>
+ <dest>
+ *: "[Gatunek]"
+ </dest>
+ <voice>
+ *: "Gatunek"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_COMMENT
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Comment]"
+ </source>
+ <dest>
+ *: "[Komentarz]"
+ </dest>
+ <voice>
+ *: "Komentarz"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_COMPOSER
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Composer]"
+ </source>
+ <dest>
+ *: "[Kompozytor]"
+ </dest>
+ <voice>
+ *: "Kompozytor"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_YEAR
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Year]"
+ </source>
+ <dest>
+ *: "[Rok]"
+ </dest>
+ <voice>
+ *: "Rok"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_TRACKNUM
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Tracknum]"
+ </source>
+ <dest>
+ *: "[Nr utworu]"
+ </dest>
+ <voice>
+ *: "Numer utworu"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_DISCNUM
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Discnum]"
+ </source>
+ <dest>
+ *: "[Nr płyty]"
+ </dest>
+ <voice>
+ *: "Numer płyty"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_FREQUENCY
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Frequency]"
+ </source>
+ <dest>
+ *: "[Częstotliwość]"
+ </dest>
+ <voice>
+ *: "Częstotliwość"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PROPERTIES_BITRATE
+ desc: in properties plugin
+ user: core
+ <source>
+ *: "[Bitrate]"
+ </source>
+ <dest>
+ *: "[Prędkość transmisji]"
+ </dest>
+ <voice>
+ *: "Prędkość transmisji"
+ </voice>
+</phrase>
diff --git a/apps/language.c b/apps/language.c
index 7fe1258dea..1ad1d5c829 100644
--- a/apps/language.c
+++ b/apps/language.c
@@ -86,7 +86,7 @@ int lang_load(const char *filename, const unsigned char *builtin,
lang_init(builtin, dest, max_id);
lseek(fd, foffset, SEEK_SET);
read(fd, buffer, lang_size);
-
+ buffer[max_lang_size - 1] = '\0'; /* ensure buffer is null terminated */
while(lang_size>3) {
id = ((buffer[0]<<8) | buffer[1]); /* get two-byte id */
buffer += 2; /* pass the id */
@@ -100,7 +100,7 @@ int lang_load(const char *filename, const unsigned char *builtin,
while(*buffer) { /* pass the string */
lang_size--;
buffer++;
- }
+ }
lang_size-=3; /* the id and the terminating zero */
buffer++; /* pass the terminating zero-byte */
}
diff --git a/apps/main.c b/apps/main.c
index 483d280204..3b7ec6d4c1 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -444,11 +444,6 @@ static void init(void)
#if CONFIG_RTC
rtc_init();
#endif
-#ifdef HAVE_RTC_RAM
- CHART(">settings_load(RTC)");
- settings_load(SETTINGS_RTC); /* early load parts of global_settings */
- CHART("<settings_load(RTC)");
-#endif
adc_init();
diff --git a/apps/menu.c b/apps/menu.c
index 6279ec10a6..4991b05383 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -68,7 +68,7 @@ static int current_subitems_count = 0;
static int talk_menu_item(int selected_item, void *data);
static void get_menu_callback(const struct menu_item_ex *m,
- menu_callback_type *menu_callback)
+ menu_callback_type *menu_callback)
{
if (m->flags&(MENU_HAS_DESC|MENU_DYNAMIC_DESC))
*menu_callback= m->callback_and_desc->menu_callback;
@@ -180,6 +180,12 @@ static void init_menu_lists(const struct menu_item_ex *menu,
struct gui_synclist *lists, int selected, bool callback,
struct viewport parent[NB_SCREENS])
{
+ if (!menu || !lists)
+ {
+ panicf("init_menu_lists, NULL pointer");
+ return;
+ }
+
int i;
int count = MIN(MENU_GET_COUNT(menu->flags), MAX_MENU_SUBITEMS);
int type = (menu->flags&MENU_TYPE_MASK);
@@ -334,19 +340,26 @@ void do_setting_screen(const struct settings_list *setting, const char * title,
option_screen((struct settings_list *)setting, parent,
setting->flags&F_TEMPVAR, (char*)title);
}
-
+
void do_setting_from_menu(const struct menu_item_ex *temp,
struct viewport parent[NB_SCREENS])
{
char *title;
int setting_id;
+ if (!temp)
+ {
+ panicf("do_setting_from_menu, NULL pointer");
+ return;
+ }
const struct settings_list *setting =
find_setting(temp->variable, &setting_id);
- if (temp && ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT))
+
+ if ((temp->flags&MENU_TYPE_MASK) == MT_SETTING_W_TEXT)
title = temp->callback_and_desc->desc;
else
title = ID2P(setting->lang_id);
+
do_setting_screen(setting, title, parent);
}
@@ -366,6 +379,7 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
#ifdef HAVE_TOUCHSCREEN
/* plugins possibly have grid mode active. force global settings in lists */
enum touchscreen_mode tsm = touchscreen_get_mode();
+ enum touchscreen_mode old_global_mode = global_settings.touch_mode;
touchscreen_set_mode(global_settings.touch_mode);
#endif
@@ -487,12 +501,12 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
ID2P(LANG_RIGHT_QS_ITEM),
ID2P(LANG_ADD_TO_FAVES));
#endif
- MENUITEM_STRINGLIST(notquickscreen_able_option,
+ MENUITEM_STRINGLIST(notquickscreen_able_option,
ID2P(LANG_ONPLAY_MENU_TITLE), NULL,
ID2P(LANG_RESET_SETTING));
const struct menu_item_ex *menu;
int menu_selection = 0;
- const struct settings_list *setting =
+ const struct settings_list *setting =
find_setting(temp->variable, NULL);
#ifdef HAVE_QUICKSCREEN
if (is_setting_quickscreenable(setting))
@@ -560,7 +574,7 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
if (!exiting_menu && (menu->flags&MENU_EXITAFTERTHISMENU))
done = true;
else
- init_menu_lists(menu, &lists,
+ init_menu_lists(menu, &lists,
menu_stack_selected_item[stack_top], false, vps);
redraw_lists = true;
/* new menu, so reload the callback */
@@ -674,7 +688,7 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
init_menu_lists(menu,&lists,selected,true,vps);
/* callback was changed, so reload the menu's callback */
get_menu_callback(menu, &menu_callback);
- if ((menu->flags&MENU_EXITAFTERTHISMENU) &&
+ if ((menu->flags&MENU_EXITAFTERTHISMENU) &&
!(temp->flags&MENU_EXITAFTERTHISMENU))
{
done = true;
@@ -727,7 +741,12 @@ int do_menu(const struct menu_item_ex *start_menu, int *start_selected,
FOR_NB_SCREENS(i)
viewportmanager_theme_undo(i, false);
#ifdef HAVE_TOUCHSCREEN
- touchscreen_set_mode(tsm);
+ /* This is needed because this function runs the settings menu and we do
+ * not want to switch back to the old mode if the user intentionally went
+ * to a different one. This is a very hacky way to do this... */
+ if(!(global_settings.touch_mode != (int)old_global_mode &&
+ tsm == old_global_mode))
+ touchscreen_set_mode(tsm);
#endif
return ret;
diff --git a/apps/menus/eq_menu.c b/apps/menus/eq_menu.c
index 49d35c133b..109c3c9ab7 100644
--- a/apps/menus/eq_menu.c
+++ b/apps/menus/eq_menu.c
@@ -49,6 +49,9 @@
#include "exported_menus.h"
#include "pcmbuf.h"
#include "option_select.h"
+#include "string-extra.h"
+
+static void eq_apply(void);
/*
* Utility functions
@@ -68,6 +71,12 @@ const char* eq_precut_format(char* buffer, size_t buffer_size, int value, const
return buffer;
}
+void eq_enabled_option_callback(bool enabled)
+{
+ (void)enabled;
+ eq_apply();
+}
+
/*
* Settings functions
*/
@@ -239,14 +248,12 @@ static void selection_to_banditem(int selection, int expanded_band, int *band, i
static char *advancedmenu_item_get_name(int selected_item, void *data, char *buffer, size_t len)
{
- (void)len;
int band;
int item;
- char *lang = NULL;
+ int lang = -1;
selection_to_banditem(selected_item, *(intptr_t*)data, &band, &item);
- strcpy(buffer, "\t");
switch (item)
{
case 0: /* Band title */
@@ -256,27 +263,34 @@ static char *advancedmenu_item_get_name(int selected_item, void *data, char *buf
return str(LANG_EQUALIZER_BAND_HIGH_SHELF);
else
{
- snprintf(buffer, MAX_PATH, str(LANG_EQUALIZER_BAND_PEAK), band);
+ snprintf(buffer, len, str(LANG_EQUALIZER_BAND_PEAK), band);
return buffer;
}
break;
case 1: /* cutoff */
if (band == 0)
- lang = str(LANG_EQUALIZER_BAND_CUTOFF);
+ lang = LANG_EQUALIZER_BAND_CUTOFF;
else if (band == EQ_NUM_BANDS - 1)
- lang = str(LANG_EQUALIZER_BAND_CUTOFF);
+ lang = LANG_EQUALIZER_BAND_CUTOFF;
else
- lang = str(LANG_EQUALIZER_BAND_CENTER);
+ lang = LANG_EQUALIZER_BAND_CENTER;
break;
case 2: /* Q */
- lang = str(LANG_EQUALIZER_BAND_Q);
+ lang = LANG_EQUALIZER_BAND_Q;
break;
case 3: /* Gain */
- lang = str(LANG_GAIN);
+ lang = LANG_GAIN;
break;
}
- return strcat(buffer, lang);;
+ if(lang < 0)
+ buffer[0] = 0;
+ else {
+ buffer[0] = '\t';
+ strlcpy(&buffer[1], str(lang), len - 1);
+ }
+
+ return buffer;
}
static int advancedmenu_speak_item(int selected_item, void *data)
@@ -660,7 +674,7 @@ int eq_menu_graphical(void)
{
if (current_band == 0) {
start_item = 0;
- } else if (current_band == 9) {
+ } else if (current_band == EQ_NUM_BANDS - 1) {
start_item = EQ_NUM_BANDS - nb_eq_sliders[i];
} else {
start_item = current_band - 1;
diff --git a/apps/menus/eq_menu.h b/apps/menus/eq_menu.h
index 04e8be2ead..f99f83d94f 100644
--- a/apps/menus/eq_menu.h
+++ b/apps/menus/eq_menu.h
@@ -48,4 +48,7 @@ const char* eq_q_format(char* buffer, size_t buffer_size, int value,
const char* eq_precut_format(char* buffer, size_t buffer_size, int value,
const char* unit);
+/* callbacks for settings_list.c */
+void eq_enabled_option_callback(bool enabled);
+
#endif
diff --git a/apps/misc.c b/apps/misc.c
index 96ad534c68..7da86930ba 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -864,27 +864,17 @@ char* strrsplt(char* str, int c)
*/
char *strip_extension(char* buffer, int buffer_size, const char *filename)
{
- char *dot = strrchr(filename, '.');
- int len;
-
- if (buffer_size <= 0)
+ if (!buffer || !filename || buffer_size <= 0)
{
return NULL;
}
- buffer_size--; /* Make room for end nil */
+ off_t dotpos = (strrchr(filename, '.') - filename) + 1;
- if (dot != 0 && filename[0] != '.')
- {
- len = dot - filename;
- len = MIN(len, buffer_size);
- }
- else
- {
- len = buffer_size;
- }
-
- strlcpy(buffer, filename, len + 1);
+ /* no match on filename beginning with '.' or beyond buffer_size */
+ if(dotpos > 1 && dotpos < buffer_size)
+ buffer_size = dotpos;
+ strlcpy(buffer, filename, buffer_size);
return buffer;
}
@@ -1049,6 +1039,11 @@ int format_sound_value(char *buf, size_t size, int snd, int val)
int physval = sound_val2phys(snd, val);
unsigned int factor = ipow(10, numdec);
+ if (factor == 0)
+ {
+ DEBUGF("DIVISION BY ZERO: format_sound_value s:%d v:%d", snd, val);
+ factor = 1;
+ }
unsigned int av = abs(physval);
unsigned int i = av / factor;
unsigned int d = av - i*factor;
diff --git a/apps/onplay.c b/apps/onplay.c
index 0942d69d3f..a5a92e7c1c 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -1441,10 +1441,13 @@ static int clipboard_paste(void)
{
case OPRC_CANCELLED:
splash_cancelled();
+ /* Fallthrough */
case OPRC_SUCCESS:
onplay_result = ONPLAY_RELOAD_DIR;
+ /* Fallthrough */
case OPRC_NOOP:
clipboard_clear_selection(&clipboard);
+ /* Fallthrough */
case OPRC_NOOVERWRT:
break;
default:
diff --git a/apps/open_plugin.c b/apps/open_plugin.c
index c64661f2e6..d16502ecbe 100644
--- a/apps/open_plugin.c
+++ b/apps/open_plugin.c
@@ -27,6 +27,10 @@
#include "splash.h"
#include "lang.h"
+/* Define LOGF_ENABLE to enable logf output in this file */
+//#define LOGF_ENABLE
+#include "logf.h"
+
#define ROCK_EXT "rock"
#define ROCK_LEN 5
#define OP_EXT "opx"
@@ -34,83 +38,228 @@
struct open_plugin_entry_t open_plugin_entry = {0};
+static const uint32_t open_plugin_csum = OPEN_PLUGIN_CHECKSUM;
+
static const int op_entry_sz = sizeof(struct open_plugin_entry_t);
-static int open_plugin_hash_get_entry(uint32_t hash,
- struct open_plugin_entry_t *entry,
- const char* dat_file);
+static const char* strip_rockbox_root(const char *path)
+{
+ int dlen = strlen(ROCKBOX_DIR);
+ if (strncmp(path, ROCKBOX_DIR, dlen) == 0)
+ path+= dlen;
+ return path;
+}
static inline void op_clear_entry(struct open_plugin_entry_t *entry)
{
- if (entry)
+ if (entry == NULL)
+ return;
+ memset(entry, 0, op_entry_sz);
+ entry->lang_id = -1;
+}
+
+static int op_entry_checksum(struct open_plugin_entry_t *entry)
+{
+ if (entry == NULL || entry->checksum != open_plugin_csum)
+ return 0;
+ return 1;
+}
+
+static int op_find_entry(int fd, struct open_plugin_entry_t *entry,
+ uint32_t hash, int32_t lang_id)
+{
+ int ret = OPEN_PLUGIN_NOT_FOUND;
+ int record = 0;
+ if (hash == 0)
+ hash = OPEN_PLUGIN_SEED;
+ if (fd >= 0)
{
- memset(entry, 0, op_entry_sz);
- entry->lang_id = -1;
+ logf("OP find_entry *Searching* hash: %x lang_id: %d", hash, lang_id);
+
+ while (read(fd, entry, op_entry_sz) == op_entry_sz)
+ {
+ if (entry->lang_id == lang_id || entry->hash == hash ||
+ (lang_id == OPEN_PLUGIN_LANG_IGNOREALL))/* return first entry found */
+ {
+ ret = record;
+ /* NULL terminate fields NOTE -- all are actually +1 larger */
+ entry->name[OPEN_PLUGIN_NAMESZ] = '\0';
+ /*entry->key[OPEN_PLUGIN_BUFSZ] = '\0';*/
+ entry->path[OPEN_PLUGIN_BUFSZ] = '\0';
+ entry->param[OPEN_PLUGIN_BUFSZ] = '\0';
+ logf("OP find_entry *Found* hash: %x lang_id: %d",
+ entry->hash, entry->lang_id);
+ logf("OP find_entry rec: %d name: %s %s %s", record,
+ entry->name, entry->path, entry->param);
+ break;
+ }
+ record++;
+ }
}
+
+ /* sanity check */
+ if (ret > OPEN_PLUGIN_NOT_FOUND && op_entry_checksum(entry) <= 0)
+ {
+ splash(HZ * 2, "OpenPlugin Invalid entry");
+ ret = OPEN_PLUGIN_NOT_FOUND;
+ }
+ if (ret == OPEN_PLUGIN_NOT_FOUND)
+ op_clear_entry(entry);
+
+ return ret;
}
-static int op_update_dat(struct open_plugin_entry_t *entry)
+static int op_update_dat(struct open_plugin_entry_t *entry, bool clear)
{
- int fd, fd1;
+ int fd;
uint32_t hash;
-
- if (!entry || entry->hash == 0)
- return -1;
+ int32_t lang_id;
+ if (entry == NULL|| entry->hash == 0)
+ {
+ logf("OP update *No entry*");
+ return OPEN_PLUGIN_NOT_FOUND;
+ }
hash = entry->hash;
+ lang_id = entry->lang_id;
+ if (lang_id <= OPEN_PLUGIN_LANG_INVALID)
+ lang_id = OPEN_PLUGIN_LANG_IGNORE;
+
+ logf("OP update hash: %x lang_id: %d", hash, lang_id);
+ logf("OP update name: %s clear: %d", entry->name, (int) clear);
+ logf("OP update %s %s %s", entry->name, entry->path, entry->param);
+
+#if (CONFIG_STORAGE & STORAGE_ATA) /* Harddrive -- update existing */
+ logf("OP update *Updating entries* %s", OPEN_PLUGIN_DAT);
+ fd = open(OPEN_PLUGIN_DAT, O_RDWR | O_CREAT, 0666);
+
+ if (fd < 0)
+ return OPEN_PLUGIN_NOT_FOUND;
+ /* Only read the hash lang id and checksum */
+ uint32_t hash_langid_csum[3] = {0};
+ const off_t hlc_sz = sizeof(hash_langid_csum);
+ while (read(fd, &hash_langid_csum, hlc_sz) == hlc_sz)
+ {
+ if ((hash_langid_csum[0] == hash || (int32_t)hash_langid_csum[1] == lang_id) &&
+ hash_langid_csum[2] == open_plugin_csum)
+ {
+ logf("OP update *Entry Exists* hash: %x langid: %d",
+ hash_langid_csum[0], (int32_t)hash_langid[1]);
+ lseek(fd, 0-hlc_sz, SEEK_CUR);/* back to the start of record */
+ break;
+ }
+ lseek(fd, op_entry_sz - hlc_sz, SEEK_CUR); /* finish record */
+ }
+ write(fd, entry, op_entry_sz);
+ close(fd);
+#else /* Everyone else make a temp file */
+ logf("OP update *Copying entries* %s", OPEN_PLUGIN_DAT ".tmp");
+ fd = open(OPEN_PLUGIN_DAT ".tmp", O_RDWR | O_CREAT | O_TRUNC, 0666);
- fd = open(OPEN_PLUGIN_DAT ".tmp", O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (!fd)
- return -1;
+ if (fd < 0)
+ return OPEN_PLUGIN_NOT_FOUND;
write(fd, entry, op_entry_sz);
- fd1 = open(OPEN_PLUGIN_DAT, O_RDONLY);
- if (fd1)
+ int fd1 = open(OPEN_PLUGIN_DAT, O_RDONLY);
+ if (fd1 >= 0)
{
- while (read(fd1, &open_plugin_entry, op_entry_sz) == op_entry_sz)
+ /* copy non-duplicate entries back from original */
+ while (read(fd1, entry, op_entry_sz) == op_entry_sz)
{
- if (open_plugin_entry.hash != hash)
- write(fd, &open_plugin_entry, op_entry_sz);
+ if (entry->hash != hash && entry->lang_id != lang_id &&
+ op_entry_checksum(entry) > 0)
+ {
+ write(fd, entry, op_entry_sz);
+ }
}
close(fd1);
remove(OPEN_PLUGIN_DAT);
}
+ if (!clear) /* retrieve original entry */
+ {
+ logf("OP update *Loading original entry*");
+ lseek(fd, 0, SEEK_SET);
+ op_find_entry(fd, entry, hash, lang_id);
+ }
close(fd);
-
rename(OPEN_PLUGIN_DAT ".tmp", OPEN_PLUGIN_DAT);
+#endif
+
+ if (clear)
+ {
+ logf("OP update *Clearing entry*");
+ op_clear_entry(entry);
+ }
- op_clear_entry(&open_plugin_entry);
return 0;
}
+static int op_get_entry(uint32_t hash, int32_t lang_id,
+ struct open_plugin_entry_t *entry, const char *dat_file)
+{
+ int opret = OPEN_PLUGIN_NOT_FOUND;
+
+ if (entry != NULL)
+ {
+ /* Is the entry we want already loaded? */
+ if(hash != 0 && entry->hash == hash)
+ return OPEN_PLUGIN_NEEDS_FLUSHED;
+
+ if(lang_id <= OPEN_PLUGIN_LANG_INVALID)
+ {
+ lang_id = OPEN_PLUGIN_LANG_IGNORE;
+ if (hash == 0)/* no hash or langid -- returns first entry found */
+ lang_id = OPEN_PLUGIN_LANG_IGNOREALL;
+ }
+ else if(entry->lang_id == lang_id)
+ {
+ return OPEN_PLUGIN_NEEDS_FLUSHED;
+ }
+
+ /* if another entry is loaded; flush it to disk before we destroy it */
+ op_update_dat(&open_plugin_entry, true);
+
+ logf("OP get_entry hash: %x lang id: %d db: %s", hash, lang_id, dat_file);
+
+ int fd = open(dat_file, O_RDONLY);
+ opret = op_find_entry(fd, entry, hash, lang_id);
+ close(fd);
+ }
+
+ return opret;
+}
+
uint32_t open_plugin_add_path(const char *key, const char *plugin, const char *parameter)
{
int len;
- bool is_valid = false;
uint32_t hash;
int32_t lang_id;
char *pos = "\0";
- if(!key)
+ if(key == NULL)
{
+ logf("OP add_path No Key, *Clearing entry*");
op_clear_entry(&open_plugin_entry);
return 0;
}
lang_id = P2ID((unsigned char*)key);
- key = P2STR((unsigned char *)key);
-
- open_plugin_get_hash(key, &hash);
-
+ const char *skey = P2STR((unsigned char *)key);
+ logf("OP add_path key: %s lang id: %d", skey, lang_id);
+ open_plugin_get_hash(strip_rockbox_root(skey), &hash);
if(open_plugin_entry.hash != hash)
{
+ logf("OP add_path *Flush entry*");
/* the entry in ram needs saved */
- op_update_dat(&open_plugin_entry);
+ op_update_dat(&open_plugin_entry, true);
}
if (plugin)
{
+ open_plugin_entry.hash = hash;
+ open_plugin_entry.lang_id = lang_id;
+ open_plugin_entry.checksum = open_plugin_csum;
/* name */
if (path_basename(plugin, (const char **)&pos) == 0)
pos = "\0";
@@ -118,45 +267,46 @@ uint32_t open_plugin_add_path(const char *key, const char *plugin, const char *p
len = strlcpy(open_plugin_entry.name, pos, OPEN_PLUGIN_NAMESZ);
if (len > ROCK_LEN && strcasecmp(&(pos[len-ROCK_LEN]), "." ROCK_EXT) == 0)
{
- is_valid = true;
-
/* path */
strlcpy(open_plugin_entry.path, plugin, OPEN_PLUGIN_BUFSZ);
- if(parameter)
- strlcpy(open_plugin_entry.param, parameter, OPEN_PLUGIN_BUFSZ);
- else
- open_plugin_entry.param[0] = '\0';
+ if(!parameter)
+ parameter = "";
+ strlcpy(open_plugin_entry.param, parameter, OPEN_PLUGIN_BUFSZ);
+ goto retnhash;
}
else if (len > OP_LEN && strcasecmp(&(pos[len-OP_LEN]), "." OP_EXT) == 0)
{
- is_valid = true;
- open_plugin_hash_get_entry(0, &open_plugin_entry, plugin);
+ op_get_entry(0, OPEN_PLUGIN_LANG_IGNORE, &open_plugin_entry, plugin);
+ goto retnhash;
}
}
- if (!is_valid)
- {
- if (lang_id != LANG_SHORTCUTS) /* from shortcuts menu */
- splashf(HZ / 2, str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), pos);
- op_clear_entry(&open_plugin_entry);
- hash = 0;
- }
- else
- {
- open_plugin_entry.hash = hash;
- open_plugin_entry.lang_id = lang_id;
- }
+ logf("OP add_path Invalid, *Clearing entry*");
+ if (lang_id != LANG_SHORTCUTS) /* from shortcuts menu */
+ splashf(HZ * 2, str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), pos);
+ op_clear_entry(&open_plugin_entry);
+ hash = 0;
+retnhash:
+ logf("OP add_path name: %s %s %s",
+ open_plugin_entry.name,
+ open_plugin_entry.path,
+ open_plugin_entry.param);
return hash;
}
void open_plugin_browse(const char *key)
{
+ logf("OP browse");
struct browse_context browse;
char tmp_buf[OPEN_PLUGIN_BUFSZ+1];
open_plugin_get_entry(key, &open_plugin_entry);
+ logf("OP browse key: %s name: %s",
+ (key ? P2STR((unsigned char *)key):"No Key") ,open_plugin_entry.name);
+ logf("OP browse %s %s", open_plugin_entry.path, open_plugin_entry.param);
+
if (open_plugin_entry.path[0] == '\0')
strcpy(open_plugin_entry.path, PLUGIN_DIR"/");
@@ -170,72 +320,50 @@ void open_plugin_browse(const char *key)
open_plugin_add_path(key, tmp_buf, NULL);
}
-static int open_plugin_hash_get_entry(uint32_t hash,
- struct open_plugin_entry_t *entry,
- const char* dat_file)
-{
- int ret = -1, record = -1;
-
- if (entry)
- {
-
- if (hash != 0)
- {
- if(entry->hash == hash) /* hasn't been flushed yet? */
- return 0;
- else
- op_update_dat(&open_plugin_entry);
- }
-
- int fd = open(dat_file, O_RDONLY);
-
- if (fd)
- {
- while (read(fd, entry, op_entry_sz) == op_entry_sz)
- {
- record++;
- if (hash == 0 || entry->hash == hash)
- {
- ret = record;
- break;
- }
- }
- close(fd);
- }
- if (ret < 0)
- {
- memset(entry, 0, op_entry_sz);
- entry->lang_id = -1;
- }
- }
-
- return ret;
-}
-
int open_plugin_get_entry(const char *key, struct open_plugin_entry_t *entry)
{
- uint32_t hash;
- key = P2STR((unsigned char *)key);
+ if (key == NULL || entry == NULL)
+ return OPEN_PLUGIN_NOT_FOUND;
+ int opret;
+ uint32_t hash = 0;
+ int32_t lang_id = P2ID((unsigned char *)key);
+ const char* skey = P2STR((unsigned char *)key); /* string|LANGPTR => string */
+
+ if (lang_id <= OPEN_PLUGIN_LANG_INVALID)
+ open_plugin_get_hash(strip_rockbox_root(skey), &hash); /* in open_plugin.h */
+
+ opret = op_get_entry(hash, lang_id, entry, OPEN_PLUGIN_DAT);
+ logf("OP entry hash: %x lang id: %d ret: %d key: %s", hash, lang_id, opret, skey);
+
+ if (opret == OPEN_PLUGIN_NOT_FOUND && lang_id > OPEN_PLUGIN_LANG_INVALID)
+ { /* try rb defaults */
+ opret = op_get_entry(hash, lang_id, entry, OPEN_RBPLUGIN_DAT);
+ logf("OP rb_entry hash: %x lang id: %d ret: %d key: %s", hash, lang_id, opret, skey);
+ /* add to the user plugin.dat file if found */
+ op_update_dat(entry, false);
- open_plugin_get_hash(key, &hash); /* in open_plugin.h */
- return open_plugin_hash_get_entry(hash, entry, OPEN_PLUGIN_DAT);
+ }
+ logf("OP entry ret: %s", (opret == OPEN_PLUGIN_NOT_FOUND ? "Not Found":"Found"));
+ return opret;
}
int open_plugin_run(const char *key)
{
int ret = 0;
- const char *path;
- const char *param;
+ int opret = open_plugin_get_entry(key, &open_plugin_entry);
+ if (opret == OPEN_PLUGIN_NEEDS_FLUSHED)
+ op_update_dat(&open_plugin_entry, false);
+ const char *path = open_plugin_entry.path;
+ const char *param = open_plugin_entry.param;
- open_plugin_get_entry(key, &open_plugin_entry);
+ logf("OP run key: %s ret: %d name: %s",
+ (key ? P2STR((unsigned char *)key):"No Key"), opret, open_plugin_entry.name);
+ logf("OP run: %s %s %s", open_plugin_entry.name, path, param);
- path = open_plugin_entry.path;
- param = open_plugin_entry.param;
if (param[0] == '\0')
param = NULL;
- if (path)
- ret = plugin_load(path, param);
+ ret = plugin_load(path, param);
if (ret != GO_TO_PLUGIN)
op_clear_entry(&open_plugin_entry);
@@ -245,7 +373,8 @@ int open_plugin_run(const char *key)
void open_plugin_cache_flush(void)
{
- op_update_dat(&open_plugin_entry);
+ logf("OP *cache flush*");
+ op_update_dat(&open_plugin_entry, true);
}
#endif /* ndef __PCTOOL__ */
diff --git a/apps/open_plugin.h b/apps/open_plugin.h
index 8c09c4ac58..d16be2052c 100644
--- a/apps/open_plugin.h
+++ b/apps/open_plugin.h
@@ -32,23 +32,47 @@
#ifndef __PCTOOL__
/* open_plugin path lookup */
#define OPEN_PLUGIN_DAT PLUGIN_DIR "/plugin.dat"
+#define OPEN_RBPLUGIN_DAT PLUGIN_DIR "/rb_plugins.dat"
#define OPEN_PLUGIN_BUFSZ MAX_PATH
#define OPEN_PLUGIN_NAMESZ 32
+
+enum {
+ OPEN_PLUGIN_LANG_INVALID = (-1),
+ OPEN_PLUGIN_LANG_IGNORE = (-2),
+ OPEN_PLUGIN_LANG_IGNOREALL = (-3),
+ OPEN_PLUGIN_NOT_FOUND = (-1),
+ OPEN_PLUGIN_NEEDS_FLUSHED = (-2),
+};
+
struct open_plugin_entry_t
{
+/* hash lang_id checksum need to be the first items */
uint32_t hash;
int32_t lang_id;
+ uint32_t checksum;
char name[OPEN_PLUGIN_NAMESZ+1];
/*char key[OPEN_PLUGIN_BUFSZ+1];*/
char path[OPEN_PLUGIN_BUFSZ+1];
char param[OPEN_PLUGIN_BUFSZ+1];
};
+#define OPEN_PLUGIN_CHECKSUM (uint32_t) \
+( \
+ (sizeof(struct open_plugin_entry_t) << 16) + \
+ offsetof(struct open_plugin_entry_t, hash) + \
+ offsetof(struct open_plugin_entry_t, lang_id) + \
+ offsetof(struct open_plugin_entry_t, checksum) + \
+ offsetof(struct open_plugin_entry_t, name) + \
+ /*offsetof(struct open_plugin_entry_t, key)+*/ \
+ offsetof(struct open_plugin_entry_t, path) + \
+ offsetof(struct open_plugin_entry_t, param))
+
+#define OPEN_PLUGIN_SEED 0x811C9DC5; //seed, 2166136261;
inline static void open_plugin_get_hash(const char *key, uint32_t *hash)
{
/* Calculate modified FNV1a hash of string */
const uint32_t p = 16777619;
- *hash = 0x811C9DC5; //seed, 2166136261;
+ *hash = OPEN_PLUGIN_SEED;
while(*key)
*hash = (*key++ ^ *hash) * p;
}
diff --git a/apps/playback.c b/apps/playback.c
index ef4b38da51..5a6f18735b 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -1915,7 +1915,8 @@ static int audio_load_track(void)
if (fd >= 0)
{
id3_mutex_lock();
- get_metadata(ub_id3, fd, path);
+ if(!get_metadata(ub_id3, fd, path))
+ wipe_mp3entry(ub_id3);
id3_mutex_unlock();
close(fd);
}
diff --git a/apps/playlist.c b/apps/playlist.c
index 7cd264e821..0d02be3d48 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -542,7 +542,7 @@ static void update_playlist_filename(struct playlist_info* playlist,
static int add_indices_to_playlist(struct playlist_info* playlist,
char* buffer, size_t buflen)
{
- unsigned int nread;
+ ssize_t nread;
unsigned int i = 0;
unsigned int count = 0;
bool store_index;
@@ -572,7 +572,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
p = (unsigned char *)buffer;
- for(count=0; count < nread; count++,p++) {
+ for(count=0; count < (unsigned int)nread; count++,p++) {
/* Are we on a new line? */
if((*p == '\n') || (*p == '\r'))
@@ -1493,8 +1493,8 @@ static int get_next_dir(char *dir, bool is_forward)
if (fd >= 0)
{
int folder_count = 0;
- read(fd,&folder_count,sizeof(int));
- if (folder_count)
+ ssize_t nread = read(fd,&folder_count,sizeof(int));
+ if ((nread == sizeof(int)) && folder_count)
{
char buffer[MAX_PATH];
/* give up looking for a directory after we've had four
@@ -1762,9 +1762,8 @@ static ssize_t format_track_path(char *dest, char *src, int buf_length,
* to "/<0>/bar" (aka "/bar" at this time). *fingers crossed*
*
* If any stripped drive spec was absolute, prepend the playlist
- * directory's volume spec, or root if none. Relative paths remain
- * relative and the playlist's directory fully qualifies them. Absolute
- * UNIX-style paths remain unaltered.
+ * directory's volume spec, or root if none. Absolute UNIX-style paths
+ * remain unaltered.
*/
if (path_strip_drive(src, (const char **)&src, true) >= 0 &&
src[-1] == PATH_SEPCH)
@@ -1782,7 +1781,9 @@ static ssize_t format_track_path(char *dest, char *src, int buf_length,
if (len >= (size_t)buf_length)
return -1; /* buffer too small */
- return len;
+ path_remove_dot_segments (dest, dest);
+
+ return strlen (dest);
}
/*
@@ -2703,7 +2704,7 @@ int playlist_next(int steps)
{
index = get_next_index(playlist, i, -1);
- if (playlist->indices[index] & PLAYLIST_QUEUE_MASK)
+ if (index >= 0 && playlist->indices[index] & PLAYLIST_QUEUE_MASK)
{
remove_track_from_playlist(playlist, index, true);
steps--; /* one less track */
@@ -3151,7 +3152,11 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
{
if (playlist_remove_all_tracks(playlist) == 0)
position = PLAYLIST_INSERT_LAST;
- else return -1;
+ else
+ {
+ close(fd);
+ return -1;
+ }
}
cpu_boost(true);
@@ -3703,7 +3708,7 @@ int playlist_save(struct playlist_info* playlist, char *filename,
if (!rename(path, tmp_buf))
{
fd = open_utf8(tmp_buf, O_RDONLY);
- if (fsamefile(fd, playlist->fd) > 0)
+ if (fd >= 0 && fsamefile(fd, playlist->fd) > 0)
{
/* Replace the current playlist with the new one and update
indices */
diff --git a/apps/playlist_catalog.c b/apps/playlist_catalog.c
index d100023b1b..ba12ff6d98 100644
--- a/apps/playlist_catalog.c
+++ b/apps/playlist_catalog.c
@@ -87,11 +87,14 @@ static int initialize_catalog(void)
mkdir(playlist_dir);
}
+ playlist_dir_length = strlen(playlist_dir);
+
/* remove duplicate leading '/' */
if (playlist_dir[0] == '/' && playlist_dir[1] == '/')
- strcpy(playlist_dir, &playlist_dir[1]);
-
- playlist_dir_length = strlen(playlist_dir);
+ {
+ memmove(&playlist_dir[0], &playlist_dir[1], playlist_dir_length); /* gets the \0 too */
+ playlist_dir_length--;
+ }
if (dir_exists(playlist_dir))
{
@@ -125,7 +128,8 @@ void catalog_set_directory(const char* directory)
}
else
{
- strcpy(global_settings.playlist_catalog_dir, directory);
+ strlcpy(global_settings.playlist_catalog_dir,
+ directory, sizeof(global_settings.playlist_catalog_dir));
}
initialized = false;
initialize_catalog();
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c
index e0e2e787cd..21b61d4a67 100644
--- a/apps/playlist_viewer.c
+++ b/apps/playlist_viewer.c
@@ -98,7 +98,7 @@ struct playlist_viewer {
int selected_track; /* The selected track, relative (first is 0) */
int moving_track; /* The track to move, relative (first is 0)
or -1 if nothing is currently being moved */
- int moving_playlist_index; /* Playlist-relative index (as opposed to
+ int moving_playlist_index; /* Playlist-relative index (as opposed to
viewer-relative index) of moving track */
struct playlist_buffer buffer;
};
@@ -295,7 +295,7 @@ static struct playlist_entry * playlist_buffer_get_track(struct playlist_buffer
the name_buffer is probably too small to store enough
titles to fill the screen, and preload data in the short
direction.
-
+
If this happens then scrolling performance will probably
be quite low, but it's better then having Data Abort errors */
playlist_buffer_load_entries(pb, index, FORWARD);
@@ -319,7 +319,7 @@ static bool playlist_viewer_init(struct playlist_viewer * viewer,
}
if (!have_list && (playlist_amount() > 0))
{
- /*If dynamic playlist still exists, view it anyway even
+ /*If dynamic playlist still exists, view it anyway even
if playback has reached the end of the playlist */
have_list = true;
}
diff --git a/apps/plugin.c b/apps/plugin.c
index a3970a88a7..d1f0348cc3 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -178,7 +178,7 @@ static const struct plugin_api rockbox_api = {
&global_settings,
&global_status,
language_strings,
-
+ &core_bitmaps[0],
/* lcd */
splash,
splashf,
@@ -439,7 +439,7 @@ static const struct plugin_api rockbox_api = {
talk_file_or_spell,
talk_dir_or_spell,
talk_number,
- talk_value,
+ talk_value_decimal,
talk_spell,
talk_time,
talk_date,
@@ -1013,7 +1013,7 @@ static void plugin_tsr(bool (*exit_callback)(bool))
pfn_tsr_exit = exit_callback; /* remember the callback for later */
}
-int plugin_open(char *plugin, char *parameter)
+int plugin_open(const char *plugin, const char *parameter)
{
open_plugin_add_path(ID2P(LANG_OPEN_PLUGIN), plugin, parameter);
return PLUGIN_GOTO_PLUGIN;
diff --git a/apps/plugin.h b/apps/plugin.h
index 64ced00bfa..bd95331143 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -49,7 +49,7 @@
char* strncpy(char *, const char *, size_t);
void* plugin_get_buffer(size_t *buffer_size);
-int plugin_open(char *plugin, char *parameter);
+int plugin_open(const char *plugin, const char *parameter);
#ifndef __PCTOOL__
#include "config.h"
@@ -188,6 +188,7 @@ struct plugin_api {
struct user_settings* global_settings;
struct system_status *global_status;
unsigned char **language_strings;
+ const struct cbmp_bitmap_info_entry *core_bitmaps;
/* lcd */
void (*splash)(int ticks, const char *str);
@@ -495,7 +496,7 @@ struct plugin_api {
int (*talk_dir_or_spell)(const char* filename,
const long *prefix_ids, bool enqueue);
int (*talk_number)(long n, bool enqueue);
- int (*talk_value)(long n, int unit, bool enqueue);
+ int (*talk_value_decimal)(long n, int unit, int decimals, bool enqueue);
int (*talk_spell)(const char* spell, bool enqueue);
void (*talk_time)(const struct tm *tm, bool enqueue);
void (*talk_date)(const struct tm *tm, bool enqueue);
@@ -700,7 +701,7 @@ struct plugin_api {
void (*dsp_eq_enable)(bool enable);
void (*dsp_dither_enable)(bool enable);
#ifdef HAVE_PITCHCONTROL
- void (*dsp_set_timestretch)(int32_t percent);
+ void (*dsp_set_timestretch)(int32_t percent);
#endif
intptr_t (*dsp_configure)(struct dsp_config *dsp,
unsigned int setting, intptr_t value);
@@ -910,7 +911,7 @@ struct plugin_api {
void (*led)(bool on);
/*plugin*/
- int (*plugin_open)(char *path, char *parameter);
+ int (*plugin_open)(const char *path, const char *parameter);
void* (*plugin_get_buffer)(size_t *buffer_size);
void* (*plugin_get_audio_buffer)(size_t *buffer_size);
void (*plugin_release_audio_buffer)(void);
diff --git a/apps/plugins/2048.c b/apps/plugins/2048.c
index 1604b73c62..2633753071 100644
--- a/apps/plugins/2048.c
+++ b/apps/plugins/2048.c
@@ -811,8 +811,7 @@ static int do_2048_pause_menu(void)
"Help",
"Quit without Saving",
"Quit");
- bool quit = false;
- while(!quit)
+ while(1)
{
switch(rb->do_menu(&menu, &sel, NULL, false))
{
@@ -849,9 +848,10 @@ static int do_2048_pause_menu(void)
}
case 6:
return 3;
+ default:
+ break;
}
}
- return 0;
}
static void exit_handler(void)
@@ -1017,8 +1017,7 @@ static enum plugin_status do_2048_menu(void)
"Help",
"Quit without Saving",
"Quit");
- bool quit = false;
- while(!quit)
+ while(true)
{
switch(rb->do_menu(&menu, &sel, NULL, false))
{
@@ -1065,6 +1064,7 @@ static enum plugin_status do_2048_menu(void)
case 5:
if(confirm_quit())
return PLUGIN_OK;
+ break;
case 6:
if(loaded)
save_game();
@@ -1073,7 +1073,6 @@ static enum plugin_status do_2048_menu(void)
break;
}
}
- return PLUGIN_OK;
}
/* plugin entry point */
diff --git a/apps/plugins/announce_status.c b/apps/plugins/announce_status.c
index 84a44556ef..a9958f198d 100644
--- a/apps/plugins/announce_status.c
+++ b/apps/plugins/announce_status.c
@@ -27,6 +27,7 @@
****************************************************************************/
#include "plugin.h"
+#include "lib/helper.h"
#include "lib/kbd_helper.h"
#include "lib/configfile.h"
@@ -185,7 +186,6 @@ static void config_reset_voice(void)
}
/****************** helper fuctions ******************/
-
void announce(void)
{
rb->talk_force_shutup();
@@ -658,7 +658,7 @@ static unsigned char* voice_info_group(unsigned char* current_token, bool testin
if (current_char == 'T')
{
runtime = rb->global_status->runtime;
- rb->talk_value(runtime, UNIT_TIME, true);
+ talk_val(runtime, UNIT_TIME, true);
}
/* prefix suffix connectives */
else if (current_char == '1')
@@ -669,7 +669,7 @@ static unsigned char* voice_info_group(unsigned char* current_token, bool testin
{
if (current_char == 'S')
{
- rb->talk_value(sleep_remaining, UNIT_TIME, true);
+ talk_val(sleep_remaining, UNIT_TIME, true);
}
/* prefix suffix connectives */
else if (current_char == '2')
@@ -704,15 +704,15 @@ static unsigned char* voice_info_group(unsigned char* current_token, bool testin
if (current_char == 'E')
{
- rb->talk_value(elapsed_length, UNIT_TIME, true);
+ talk_val(elapsed_length, UNIT_TIME, true);
}
else if (current_char == 'L')
{
- rb->talk_value(track_length, UNIT_TIME, true);
+ talk_val(track_length, UNIT_TIME, true);
}
else if (current_char == 'R')
{
- rb->talk_value(track_remaining, UNIT_TIME, true);
+ talk_val(track_remaining, UNIT_TIME, true);
}
else if (current_char == 'T' && id3->title)
{
@@ -797,11 +797,11 @@ static unsigned char* voice_info_group(unsigned char* current_token, bool testin
if (current_char == 'P')
{
- rb->talk_value(rb->battery_level(), UNIT_PERCENT, true);
+ talk_val(rb->battery_level(), UNIT_PERCENT, true);
}
else if (current_char == 'M')
{
- rb->talk_value(rb->battery_time() * 60, UNIT_TIME, true);
+ talk_val(rb->battery_time() * 60, UNIT_TIME, true);
}
/* prefix suffix connectives */
else if (current_char == '1')
diff --git a/apps/plugins/blackjack.c b/apps/plugins/blackjack.c
index 24cfbe583c..3065802716 100644
--- a/apps/plugins/blackjack.c
+++ b/apps/plugins/blackjack.c
@@ -185,22 +185,6 @@ enum {
#define BJACK_RIGHT BUTTON_RIGHT
#define BJACK_LEFT BUTTON_LEFT
-#elif CONFIG_KEYPAD == TATUNG_TPJ1022_PAD
-#define BJACK_SELECT_NAME "MAIN"
-#define BJACK_STAY_NAME "MENU"
-#define BJACK_QUIT_NAME "POWER"
-#define BJACK_DOUBLE_NAME "DOWN"
-#define BJACK_SELECT BUTTON_MAIN
-#define BJACK_QUIT BUTTON_POWER
-#define BJACK_MAX (BUTTON_REC|BUTTON_UP)
-#define BJACK_MIN (BUTTON_REC|BUTTON_DOWN)
-#define BJACK_STAY BUTTON_MENU
-#define BJACK_DOUBLEDOWN BUTTON_DOWN
-#define BJACK_UP BUTTON_UP
-#define BJACK_DOWN BUTTON_DOWN
-#define BJACK_RIGHT BUTTON_RIGHT
-#define BJACK_LEFT BUTTON_LEFT
-
#elif CONFIG_KEYPAD == GIGABEAT_S_PAD
#define BJACK_SELECT_NAME "PLAY"
#define BJACK_STAY_NAME "VOL-"
diff --git a/apps/plugins/bubbles.c b/apps/plugins/bubbles.c
index ffc814e7a0..88d7228d72 100644
--- a/apps/plugins/bubbles.c
+++ b/apps/plugins/bubbles.c
@@ -76,7 +76,7 @@ enum {
#endif
#define ANGLE_STEP 2
-#define ANGLE_STEP_REP 4
+#define ANGLE_STEP_REP 6
#define BUBBLES_QUIT1 PLA_EXIT
#define BUBBLES_QUIT2 PLA_CANCEL
@@ -2367,12 +2367,14 @@ static int bubbles_handlebuttons(struct game_context* bb, bool animblock,
switch(button){
case BUBBLES_LEFT_REP:
if(bb->angle > MIN_ANGLE) bb->angle -= ANGLE_STEP_REP;
+ break;
case BUBBLES_LEFT: /* change angle to the left */
if(bb->angle > MIN_ANGLE) bb->angle -= ANGLE_STEP;
break;
case BUBBLES_RIGHT_REP:
if(bb->angle < MAX_ANGLE) bb->angle += ANGLE_STEP_REP;
+ break;
case BUBBLES_RIGHT: /* change angle to the right */
if(bb->angle < MAX_ANGLE) bb->angle += ANGLE_STEP;
break;
diff --git a/apps/plugins/calculator.c b/apps/plugins/calculator.c
index bd09330529..5bab15d7ed 100644
--- a/apps/plugins/calculator.c
+++ b/apps/plugins/calculator.c
@@ -755,6 +755,7 @@ double strtod(const char *nptr, char **endptr)
case '.':
case '\'':
end=1;
+ /* fallthrough */
default:
nptr++;
}
@@ -1687,6 +1688,7 @@ static void typingProcess(void){
clearInput();
*typingbufPointer = '0';
typingbufPointer++;
+ /* Fallthrough */
case cal_typing:
calStatus = cal_dotted;
*typingbufPointer = '.';
diff --git a/apps/plugins/chessbox/chessbox.c b/apps/plugins/chessbox/chessbox.c
index 397fd0e559..13df4f177e 100644
--- a/apps/plugins/chessbox/chessbox.c
+++ b/apps/plugins/chessbox/chessbox.c
@@ -780,6 +780,7 @@ static bool cb_start_viewer(const char* filename){
break;
case COMMAND_QUIT:
exit_app = true;
+ /* fallthrough */
case COMMAND_RETURN:
exit_viewer = true;
break;
diff --git a/apps/plugins/doom/p_ceilng.c b/apps/plugins/doom/p_ceilng.c
index db5a701b1a..f83bdc0260 100644
--- a/apps/plugins/doom/p_ceilng.c
+++ b/apps/plugins/doom/p_ceilng.c
@@ -121,6 +121,7 @@ void T_MoveCeiling (ceiling_t* ceiling)
// crushers reverse direction at the top
case silentCrushAndRaise:
S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop);
+ /* fallthrough */
case genSilentCrusher:
case genCrusher:
case fastCrushAndRaise:
@@ -177,8 +178,10 @@ void T_MoveCeiling (ceiling_t* ceiling)
// except generalized ones, reset speed, start back up
case silentCrushAndRaise:
S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop);
+ /* fallthrough */
case crushAndRaise:
ceiling->speed = CEILSPEED;
+ /* fallthrough */
case fastCrushAndRaise:
ceiling->direction = 1;
break;
diff --git a/apps/plugins/doom/p_floor.c b/apps/plugins/doom/p_floor.c
index f4dbcd04f5..953e4dd09d 100644
--- a/apps/plugins/doom/p_floor.c
+++ b/apps/plugins/doom/p_floor.c
@@ -503,6 +503,7 @@ int EV_DoFloor
case raiseFloorCrush:
floor->crush = true;
+ /* fallthrough */
case raiseFloor:
floor->direction = 1;
floor->sector = sec;
diff --git a/apps/plugins/goban/goban.c b/apps/plugins/goban/goban.c
index 7b378eebff..b041f7cd73 100644
--- a/apps/plugins/goban/goban.c
+++ b/apps/plugins/goban/goban.c
@@ -524,6 +524,7 @@ plugin_start (const void *parameter)
case BUTTON_NONE:
is_idle = true;
+ /* fallthrough */
default:
if (rb->default_event_handler (btn) == SYS_USB_CONNECTED)
{
diff --git a/apps/plugins/imageviewer/imageviewer.c b/apps/plugins/imageviewer/imageviewer.c
index 4b1a982438..508cf1a5b5 100644
--- a/apps/plugins/imageviewer/imageviewer.c
+++ b/apps/plugins/imageviewer/imageviewer.c
@@ -600,6 +600,7 @@ static int scroll_bmp(struct image_info *info)
if (entries > 1 && info->width <= LCD_WIDTH
&& info->height <= LCD_HEIGHT)
return change_filename(DIR_PREV);
+ /* fallthrough */
case IMGVIEW_LEFT | BUTTON_REPEAT:
pan_view_left(info);
break;
@@ -608,6 +609,7 @@ static int scroll_bmp(struct image_info *info)
if (entries > 1 && info->width <= LCD_WIDTH
&& info->height <= LCD_HEIGHT)
return change_filename(DIR_NEXT);
+ /* fallthrough */
case IMGVIEW_RIGHT | BUTTON_REPEAT:
pan_view_right(info);
break;
diff --git a/apps/plugins/imageviewer/jpeg/jpeg_decoder.c b/apps/plugins/imageviewer/jpeg/jpeg_decoder.c
index b014fa0ed1..ef7d5ddb3d 100644
--- a/apps/plugins/imageviewer/jpeg/jpeg_decoder.c
+++ b/apps/plugins/imageviewer/jpeg/jpeg_decoder.c
@@ -61,14 +61,9 @@ INLINE unsigned range_limit(int value)
return value;
#else
value += 128;
-
- if ((unsigned)value <= 255)
- return value;
-
- if (value < 0)
- return 0;
-
- return 255;
+ if(value < 0) return 0;
+ if(value > 255) return 255;
+ return value;
#endif
}
diff --git a/apps/plugins/invadrox.c b/apps/plugins/invadrox.c
index 5eedb6ffc5..a164b95cf0 100644
--- a/apps/plugins/invadrox.c
+++ b/apps/plugins/invadrox.c
@@ -141,14 +141,6 @@
#define RIGHT BUTTON_RIGHT
#define FIRE BUTTON_SELECT
-#elif CONFIG_KEYPAD == TATUNG_TPJ1022_PAD
-
-/* TODO: Figure out which buttons to use for Tatung Elio TPJ-1022 */
-#define QUIT BUTTON_AB
-#define LEFT BUTTON_LEFT
-#define RIGHT BUTTON_RIGHT
-#define FIRE BUTTON_MENU
-
#elif CONFIG_KEYPAD == GIGABEAT_S_PAD
#define QUIT BUTTON_BACK
@@ -617,7 +609,7 @@ CONFIG_KEYPAD == MROBE500_PAD
#elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
-/* TPJ1022, H300, iPod Color: 220x176x16
+/* H300, iPod Color: 220x176x16
* ============================
* X: 0p padding at left/right gives 220p playfield in middle.
* 8p "border" gives 204p actual playfield. UFO use full 220p.
diff --git a/apps/plugins/keybox.c b/apps/plugins/keybox.c
index 1689321abe..a074ffc598 100644
--- a/apps/plugins/keybox.c
+++ b/apps/plugins/keybox.c
@@ -75,7 +75,7 @@ static void encrypt_buffer(char *buf, size_t size, uint32_t *key);
static void decrypt_buffer(char *buf, size_t size, uint32_t *key);
/* the following two functions are the reference TEA implementation by
- David Wheeler and Roger Needham taken from
+ David Wheeler and Roger Needham taken from
http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm */
static void do_encrypt(uint32_t* v, uint32_t* k)
diff --git a/apps/plugins/lib/SOURCES b/apps/plugins/lib/SOURCES
index 811771e0ca..bdea07315e 100644
--- a/apps/plugins/lib/SOURCES
+++ b/apps/plugins/lib/SOURCES
@@ -2,6 +2,8 @@ sha1.c
gcc-support.c
pluginlib_actions.c
helper.c
+icon_helper.c
+arg_helper.c
md5.c
jhash.c
configfile.c
diff --git a/apps/plugins/lib/arg_helper.c b/apps/plugins/lib/arg_helper.c
new file mode 100644
index 0000000000..d402300900
--- /dev/null
+++ b/apps/plugins/lib/arg_helper.c
@@ -0,0 +1,310 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2021 William Wilgus
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "plugin.h"
+#include "arg_helper.h"
+
+#ifndef logf
+#define logf(...) {}
+#endif
+
+#define SWCHAR '-'
+#define DECSEPCHAR '.'
+
+int string_parse(const char **parameter, char* buf, size_t buf_sz)
+{
+/* fills buf with a string upto buf_sz, null terminates the buffer
+ * strings break on WS by default but can be enclosed in single or double quotes
+ * opening and closing quotes will not be included in the buffer but will be counted
+ * use alternating quotes if you really want them included '"text"' or "'text'"
+ * failure to close the string will result in eating all remaining args till \0
+ * If buffer full remaining chars are discarded till stopchar or \0 is reached */
+
+ char stopchar = ' ';
+ char stopchars[] = "\'\"";
+ int skipped = 0;
+ int found = 0;
+ const char* start = *parameter;
+
+ if (strchr(stopchars, *start))
+ {
+ logf("stop char %c\n", *start);
+ stopchar = *start;
+ skipped++;
+ start++;
+ }
+ while (*start && *start != stopchar)
+ {
+ if (buf_sz > 1)
+ {
+ *buf++ = *start;
+ buf_sz--;
+ }
+ found++;
+ start++;
+ }
+ if (*start == stopchar && skipped)
+ {
+ start++;
+ skipped++;
+ }
+
+ *buf = '\0';
+
+ if (found > 0)
+ *parameter = start;
+ else
+ skipped = 0;
+
+ return found + skipped;
+}
+
+int char_parse(const char **parameter, char* character)
+{
+/* passes *character a single character eats remaining non-WS characters */
+ char buf[2];
+ int ret = string_parse(parameter, buf, sizeof(buf));
+ if (ret && character)
+ *character = buf[0];
+ return ret;
+
+}
+
+int bool_parse(const char **parameter, bool *choice)
+{
+/* determine true false using the first character the rest are skipped/ignored */
+ int found = 0;
+ const char tf_val[]="fn0ty1";/* false chars on left f/t should be balanced fffttt */
+ const char* start = *parameter;
+
+
+ char c = tolower(*start);
+ const char *tfval = strchr(tf_val, c);
+ while(isalnum(*++start)) {;}
+
+ if (tfval)
+ {
+ found = start - (*parameter);
+ *parameter = start;
+ }
+
+ if (choice)
+ *choice = (tfval - tf_val) > (signed int) (sizeof(tf_val) / 2) - 1;
+
+ return found;
+}
+
+int longnum_parse(const char **parameter, long *number, long *decimal)
+{
+/* passes number and or decimal portion of number base 10 only..
+ fractional portion is scaled by ARGPARSE_FRAC_DEC_MULTIPLIER
+ Example (if ARGPARSE_FRAC_DEC_MULTIPLIER = 10 000)
+ meaning .0009 returns 9 , 9 / 10000 = .0009
+ .009 returns 90
+ .099 returns 990
+ .09 returns 900
+ .9 returns 9000
+ .9999 returns 9999
+*/
+
+ long num = 0;
+ long dec = 0;
+ int found = 0;
+ int neg = 0;
+ int digits = 0;
+ //logf ("n: %s\n", *parameter);
+ const char *start = *parameter;
+
+ if (*start == '-')
+ {
+ neg = 1;
+ start++;
+ }
+ while (isdigit(*start))
+ {
+ found++;
+ num = num *10 + *start - '0';
+ start++;
+ }
+
+ if (*start == DECSEPCHAR)
+ {
+ start++;
+ while(*start == '0')
+ {
+ digits++;
+ start++;
+ }
+ while (isdigit(*start))
+ {
+ dec = dec *10 + *start - '0';
+ digits++;
+ start++;
+ }
+ if (decimal && digits <= ARGPARSE_MAX_FRAC_DIGITS)
+ {
+ if(digits < ARGPARSE_MAX_FRAC_DIGITS)
+ {
+ digits = ARGPARSE_MAX_FRAC_DIGITS - digits;
+ while (digits--)
+ dec *= 10;
+ }
+ }
+ else
+ dec = -1; /* error */
+ }
+
+ if (found > 0)
+ {
+ found = start - (*parameter);
+ *parameter = start;
+ }
+
+ if(number)
+ *number = neg ? -num : num;
+
+ if (decimal)
+ *decimal = dec;
+
+ return found;
+}
+
+int num_parse(const char **parameter, int *number, int *decimal)
+{
+ long num, dec;
+ int ret = longnum_parse(parameter, &num, &dec);
+ if(number)
+ *number = num;
+ if (decimal)
+ *decimal = dec;
+ return ret;
+}
+
+/*
+*argparse(const char *parameter, int parameter_len,
+* int (*arg_callback)(char argchar, const char **parameter))
+* parameter : constant char string of arguments
+* parameter_len : may be set to -1 if your parameter string is NULL (\0) terminated
+* arg_callback : function gets called for each SWCHAR found in the parameter string
+* Note: WS at beginning is stripped, **parameter starts at the first NON WS char
+* return 0 for arg_callback to quit parsing immediately
+*/
+void argparse(const char *parameter, int parameter_len, int (*arg_callback)(char argchar, const char **parameter))
+{
+ bool lastchr;
+ char argchar;
+ const char *start = parameter;
+ while (parameter_len < 0 || (parameter - start) < parameter_len)
+ {
+ switch (*parameter++)
+ {
+ case SWCHAR:
+ {
+ if ((*parameter) == '\0')
+ return;
+ logf ("%s\n",parameter);
+ argchar = *parameter;
+ lastchr = (*(parameter + 1) == '\0');
+ while (*++parameter || lastchr)
+ {
+ lastchr = false;
+ if (isspace(*parameter))
+ continue; /* eat spaces at beginning */
+ if (!arg_callback(argchar, &parameter))
+ return;
+ break;
+ }
+ break;
+ }
+ case '\0':
+ {
+ if (parameter_len <= 0)
+ return;
+ }
+ }
+ }
+}
+
+/* EXAMPLE USAGE
+argparse("-n 42 -N 9.9 -n -78.9009 -f -P /rockbox/path/f -s 'Yestest' -B false -B 0 -B true -b n -by -b 1-c ops -c s -k", -1, &arg_callback);
+
+int arg_callback(char argchar, const char **parameter)
+{
+ int ret;
+ int num, dec;
+ char c;
+ char buf[32];
+ bool bret;
+ logf ("Arg: %c\n", argchar);
+ switch (tolower(argchar))
+ {
+ case 'k' :
+ logf("Option K!");
+ break;
+ case 'c' :
+ ret = char_parse(parameter, &c);
+ if (ret)
+ {
+ logf ("Val: %c\n", c);
+ logf("ate %d chars\n", ret);
+ }
+ break;
+
+ case 'n' :
+ ret = num_parse(parameter, &num, &dec);
+ if (ret)
+ {
+ logf ("Val: %d.%d\n", num, dec);
+ logf("ate %d chars\n", ret);
+ }
+ break;
+ case 's' :
+ ret = string_parse(parameter, buf, sizeof(buf));
+ if (ret)
+ {
+ logf ("Val: %s\n", buf);
+ logf("ate %d chars\n", ret);
+ }
+ break;
+ case 'p' :
+ ret = string_parse(parameter, buf, sizeof(buf));
+ if (ret)
+ {
+ logf ("Path: %s\n", buf);
+ logf("ate %d chars\n", ret);
+ }
+ break;
+ case 'b' :
+ ret = bool_parse(parameter, &bret);
+ if (ret)
+ {
+ logf ("Val: %s\n", bret ? "true" : "false");
+ logf("ate %d chars\n", ret);
+ }
+ break;
+ default :
+ logf ("Unknown switch '%c'\n",argchar);
+ //return 0;
+ }
+ return 1;
+}
+*/
+
diff --git a/apps/plugins/lib/arg_helper.h b/apps/plugins/lib/arg_helper.h
new file mode 100644
index 0000000000..c7b14f7f7a
--- /dev/null
+++ b/apps/plugins/lib/arg_helper.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2021 William Wilgus
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _LIB_ARG_HELPER_H_
+#define _LIB_ARG_HELPER_H_
+
+#include "plugin.h"
+
+#define ARGPARSE_MAX_FRAC_DIGITS 9 /* Uses 30 bits max (0.999999999) */
+
+#define ARGP_EXP(a, b) (a ##E## b)
+#define ARGP_FRAC_DEC_MULTIPLIER(n) AP_EXP(1,n) /*1x10^n*/
+#define ARGPARSE_FRAC_DEC_MULTIPLIER \
+ (long)ARGP_FRAC_DEC_MULTIPLIER(ARGPARSE_MAX_FRAC_DIGITS)
+
+/* fills buf with a string upto buf_sz, null terminates the buffer
+ * strings break on WS by default but can be enclosed in single or double quotes
+ * opening and closing quotes will not be included in the buffer but will be counted
+ * use alternating quotes if you really want them included '"text"' or "'text'"
+ * failure to close the string will result in eating all remaining args till \0
+ * If buffer full remaining chars are discarded till stopchar or \0 is reached */
+int string_parse(const char **parameter, char* buf, size_t buf_sz);
+/* passes *character a single character eats remaining non-WS characters */
+int char_parse(const char **parameter, char* character);
+/* determine true false using the first character the rest are skipped/ignored */
+int bool_parse(const char **parameter, bool *choice);
+/* passes number and or decimal portion of number base 10 only.. */
+int longnum_parse(const char **parameter, long *number, long *decimal);
+int num_parse(const char **parameter, int *number, int *decimal);
+
+/*
+*argparse(const char *parameter, int parameter_len,
+* int (*arg_callback)(char argchar, const char **parameter))
+* parameter : constant char string of arguments
+* parameter_len : may be set to -1 if your parameter string is NULL (\0) terminated
+* arg_callback : function gets called for each SWCHAR found in the parameter string
+* Note: WS at beginning is stripped, **parameter starts at the first NON WS char
+* return 0 for arg_callback to quit parsing immediately
+*/
+void argparse(const char *parameter, int parameter_len,
+ int (*arg_callback)(char argchar, const char **parameter));
+
+#endif /* _LIB_ARG_HELPER_H_ */
diff --git a/apps/plugins/lib/helper.c b/apps/plugins/lib/helper.c
index f36c01b23e..018c1616c8 100644
--- a/apps/plugins/lib/helper.c
+++ b/apps/plugins/lib/helper.c
@@ -22,6 +22,12 @@
#include "plugin.h"
#include "helper.h"
+int talk_val(long n, int unit, bool enqueue)
+{
+ #define NODECIMALS 0
+ return rb->talk_value_decimal(n, unit, NODECIMALS, enqueue);
+}
+
#ifdef HAVE_BACKLIGHT
/* Force the backlight on */
void backlight_force_on(void)
diff --git a/apps/plugins/lib/helper.h b/apps/plugins/lib/helper.h
index f2e9187a96..00ad8ac087 100644
--- a/apps/plugins/lib/helper.h
+++ b/apps/plugins/lib/helper.h
@@ -23,6 +23,8 @@
#include "plugin.h"
+int talk_val(long n, int unit, bool enqueue);
+
/**
* Backlight on/off operations
*/
diff --git a/firmware/target/arm/tatung/tpj1022/button-tpj1022.c b/apps/plugins/lib/icon_helper.c
index ce9d7ab24d..857bddb128 100644
--- a/firmware/target/arm/tatung/tpj1022/button-tpj1022.c
+++ b/apps/plugins/lib/icon_helper.c
@@ -7,7 +7,7 @@
* \/ \/ \/ \/ \/
* $Id$
*
- * Copyright (C) 2006 by Robert Kukla
+ * Copyright (C) 2021 William Wilgus
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,31 +19,30 @@
*
****************************************************************************/
-#include "system.h"
-#include "button.h"
+#include "plugin.h"
+#include "icon_helper.h"
-bool button_hold(void)
+const unsigned char* cbmp_get_icon(unsigned int cbmp_fmt, unsigned int index, int *width, int *height)
{
- return (GPIOK_INPUT_VAL & 0x40) ? true : false;
-}
-
-int button_read_device(void)
-{
- int btn = BUTTON_NONE;
-
- if (!button_hold())
+ const unsigned char* bmp = NULL;
+ while (cbmp_fmt < CBMP_BitmapFormatLast)
{
- btn = (GPIOA_INPUT_VAL & 0xfe) ^ 0xfe;
+ const struct cbmp_bitmap_info_entry *cbmp = &rb->core_bitmaps[cbmp_fmt];
+ if (index > cbmp->count)
+ break;
+ int w = cbmp->width;
+ int h = cbmp->height;
+ /* ((height/CHAR_BIT) Should always be 1 thus far */
- if ((GPIOK_INPUT_VAL & 0x20) == 0) btn |= BUTTON_VOL_DOWN;
+ off_t offset = (((unsigned)h/CHAR_BIT) * (index * w));
+ bmp = cbmp->pbmp + offset;
- /* to be found
- if ((GPIO?_INPUT_VAL & 0x??) == 0) btn |= BUTTON_MENU;
- if ((GPIO?_INPUT_VAL & 0x??) == 0) btn |= BUTTON_REC;
- if ((GPIO?_INPUT_VAL & 0x??) == 0) btn |= BUTTON_VOL_UP;
- if ((GPIO?_INPUT_VAL & 0x??) == 0) btn |= BUTTON_LEFT;
- */
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+ break;
}
-
- return btn;
+
+ return bmp;
}
diff --git a/firmware/target/arm/tatung/tpj1022/backlight-target.h b/apps/plugins/lib/icon_helper.h
index 4a5e677599..e30a607a3f 100644
--- a/firmware/target/arm/tatung/tpj1022/backlight-target.h
+++ b/apps/plugins/lib/icon_helper.h
@@ -7,7 +7,7 @@
* \/ \/ \/ \/ \/
* $Id$
*
- * Copyright (C) 2006 by Barry Wardell
+ * Copyright (C) 2021 William Wilgus
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -18,14 +18,9 @@
* KIND, either express or implied.
*
****************************************************************************/
+#ifndef _LIB_ICON_HELPER_H_
+#define _LIB_ICON_HELPER_H_
-/* Taken from the x5's implementation */
-
-#ifndef BACKLIGHT_TARGET_H
-#define BACKLIGHT_TARGET_H
-
-#define backlight_hw_init() true
-void backlight_hw_on(void);
-void backlight_hw_off(void);
-
-#endif
+#include "plugin.h"
+const unsigned char* cbmp_get_icon(unsigned int cbmp_fmt, unsigned int index, int *width, int *height);
+#endif /* _LIB_ICON_HELPER_H_ */
diff --git a/apps/plugins/lrcplayer.c b/apps/plugins/lrcplayer.c
index 2abfbef6c9..f42b96b5b3 100644
--- a/apps/plugins/lrcplayer.c
+++ b/apps/plugins/lrcplayer.c
@@ -227,6 +227,7 @@ static int lrc_set_time(const char *title, const char *unit, long *pval,
case PLA_UP_REPEAT:
case PLA_DOWN_REPEAT:
mult *= 10;
+ /* fallthrough */
case PLA_DOWN:
case PLA_UP:
if (button == PLA_DOWN_REPEAT || button == PLA_DOWN)
@@ -427,8 +428,8 @@ static struct lrc_brpos *calc_brpos(struct lrc_line *lrc_line, int i)
int nword;
int word_count, word_width;
const unsigned char *str;
- }
- sp,
+ }
+ sp,
cr;
lrc_buffer_used = (lrc_buffer_used+3)&~3; /* 4 bytes aligned */
diff --git a/apps/plugins/lua/lauxlib.c b/apps/plugins/lua/lauxlib.c
index b8332427f0..9a5939aff9 100644
--- a/apps/plugins/lua/lauxlib.c
+++ b/apps/plugins/lua/lauxlib.c
@@ -803,8 +803,10 @@ static int panic (lua_State *L) {
LUALIB_API lua_State *luaL_newstate (void) {
lua_State *L = lua_newstate(l_alloc, NULL);
- lua_setallocf(L, l_alloc, L); /* allocator needs lua_State. */
- if (L) lua_atpanic(L, &panic);
+ if (L){
+ lua_setallocf(L, l_alloc, L); /* allocator needs lua_State. */
+ lua_atpanic(L, &panic);
+ }
return L;
}
diff --git a/apps/plugins/lua/lcode.c b/apps/plugins/lua/lcode.c
index 18102d460e..bf031436e8 100644
--- a/apps/plugins/lua/lcode.c
+++ b/apps/plugins/lua/lcode.c
@@ -802,8 +802,10 @@ static unsigned char *growLineInfo(FuncState *fs) {
unsigned char, MAX_INT, "code size overflow");
p = &f->packedlineinfo[start];
- memset(p, INFO_FILL_BYTE, f->sizelineinfo - start);
- f->packedlineinfo[f->sizelineinfo - 1] = '\0';
+ if (p && f->sizelineinfo > 0) {
+ memset(p, INFO_FILL_BYTE, f->sizelineinfo - start);
+ f->packedlineinfo[f->sizelineinfo - 1] = '\0';
+ }
return p;
}
diff --git a/apps/plugins/lua/lmathlib.c b/apps/plugins/lua/lmathlib.c
index 56c79afced..839d2014ad 100644
--- a/apps/plugins/lua/lmathlib.c
+++ b/apps/plugins/lua/lmathlib.c
@@ -96,7 +96,10 @@ static int math_floor (lua_State *L) {
static int math_fmod (lua_State *L) {
/* Was: lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); */
- lua_pushnumber(L, luaL_checknumber(L, 1) % luaL_checknumber(L, 2));
+ lua_Number n = luaL_checknumber(L, 1);
+ lua_Number d = luaL_checknumber(L, 2);
+ luaL_argcheck(L, d != 0, 2, "division by zero");
+ lua_pushnumber(L, n % d);
return 1;
}
diff --git a/apps/plugins/lua/lparser.c b/apps/plugins/lua/lparser.c
index 23d3972036..06c62cedde 100644
--- a/apps/plugins/lua/lparser.c
+++ b/apps/plugins/lua/lparser.c
@@ -359,6 +359,8 @@ static void open_func (LexState *ls, FuncState *fs) {
static void close_func (LexState *ls) {
+ if (!ls || !ls->fs || !ls->fs->f)
+ return;
lua_State *L = ls->L;
FuncState *fs = ls->fs;
Proto *f = fs->f;
diff --git a/apps/plugins/lua/rbdefines_helper.pl b/apps/plugins/lua/rbdefines_helper.pl
index e788855e87..5fb0946a6a 100755
--- a/apps/plugins/lua/rbdefines_helper.pl
+++ b/apps/plugins/lua/rbdefines_helper.pl
@@ -50,6 +50,7 @@ if ($def_type eq "rb_defines") {
'^SYS_(TIMEOUT|POWEROFF|BATTERY_UPDATE)$',
'^SYS_USB_(DIS|)CONNECTED$',
'^HOME_DIR$',
+ '^PLUGIN(_OK|_USB_CONNECTED|_POWEROFF|_GOTO_WPS|_GOTO_PLUGIN)$',
'^PLUGIN_DIR$',
'^PLUGIN(_APPS_|_GAMES_|_)DATA_DIR$',
'^ROCKBOX_DIR$',
diff --git a/apps/plugins/lua/rockaux.c b/apps/plugins/lua/rockaux.c
index 929dea798b..c4af2b3e96 100644
--- a/apps/plugins/lua/rockaux.c
+++ b/apps/plugins/lua/rockaux.c
@@ -257,7 +257,7 @@ int filetol(int fd, long *num)
{
case '-':
{
- if (retn) /* 0 preceeds, this negative sign must be in error */
+ if (retn > 0) /* 0 preceeds, this negative sign must be in error */
goto get_digits;
neg = true;
continue;
diff --git a/apps/plugins/lua/rocklua.c b/apps/plugins/lua/rocklua.c
index 3909f3008f..3cf0fce945 100644
--- a/apps/plugins/lua/rocklua.c
+++ b/apps/plugins/lua/rocklua.c
@@ -175,9 +175,10 @@ static int loadfile_newstate(lua_State **L, const char *filename)
static void lua_atexit(void)
{
char *filename;
-
+ int err_n;
if(Ls && lua_gettop(Ls) > 1)
{
+ err_n = lua_tointeger(Ls, -1); /* os.exit? */
if (Ls == lua_touserdata(Ls, -1)) /* signal from restart_lua */
{
filename = (char *) malloc((MAX_PATH * 2) + 1);
@@ -195,7 +196,12 @@ static void lua_atexit(void)
free(filename);
plugin_start(NULL);
}
- else if (lua_tointeger(Ls, -1) != 0) /* os.exit */
+ else if (err_n >= PLUGIN_USB_CONNECTED) /* INTERNAL PLUGIN RETVAL */
+ {
+ lua_close(Ls);
+ _exit(err_n); /* don't call exit handler */
+ }
+ else if (err_n != 0)
{
ERR_RUN:
lu_status = LUA_ERRRUN;
@@ -205,7 +211,7 @@ ERR_RUN:
else
lua_close(Ls);
}
- _exit(0); /* don't call exit handler */
+ _exit(PLUGIN_OK); /* don't call exit handler */
}
/* split filename at argchar
diff --git a/apps/plugins/lua/strftime.c b/apps/plugins/lua/strftime.c
index c6152bf492..cc110469bf 100644
--- a/apps/plugins/lua/strftime.c
+++ b/apps/plugins/lua/strftime.c
@@ -35,6 +35,9 @@ size_t strftime ( char* dst, size_t max, const char* format, const struct tm* t
const char* src;
unsigned long no;
char buf [5];
+#if CONFIG_RTC
+ char sbuf[101];
+#endif
if (!max) return 0;
for ( ; *format != '\0'; format++ ) {
@@ -83,7 +86,6 @@ again:
case 's': {
#if CONFIG_RTC
time_t t = rb->mktime((struct tm*)tm);
- char sbuf[101];
char* c;
sbuf[100]=0;
for (c=sbuf+99; c>sbuf; --c) {
diff --git a/apps/plugins/lua/tlsf_helper.c b/apps/plugins/lua/tlsf_helper.c
index 52ef269bcd..664d87c34e 100644
--- a/apps/plugins/lua/tlsf_helper.c
+++ b/apps/plugins/lua/tlsf_helper.c
@@ -48,7 +48,7 @@ static size_t check_sentinel(void* buf, size_t size)
{
unused++;
while(++i < sz && b[i] == SENTINEL(i) && ++unused)
- ;;
+ {;;}
}
return unused * sizeof(sentinel);
}
diff --git a/apps/plugins/lua_scripts/return2WPS.lua b/apps/plugins/lua_scripts/return2WPS.lua
new file mode 100644
index 0000000000..9202237691
--- /dev/null
+++ b/apps/plugins/lua_scripts/return2WPS.lua
@@ -0,0 +1,19 @@
+--[[
+ __________ __ ___.
+ Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ \/ \/ \/ \/ \/
+ $Id$
+ Example Lua Return to WPS on exit
+ Copyright (C) 2021 William Wilgus
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ KIND, either express or implied.
+]]--
+
+os.exit(rb.PLUGIN_GOTO_WPS)
diff --git a/apps/plugins/main_menu_config.c b/apps/plugins/main_menu_config.c
index f66165e63d..9f651094b1 100644
--- a/apps/plugins/main_menu_config.c
+++ b/apps/plugins/main_menu_config.c
@@ -171,7 +171,7 @@ enum plugin_status plugin_start(const void* parameter)
struct gui_synclist list;
bool done = false;
int action, cur_sel;
-
+
menu_table = rb->root_menu_get_options(&menu_item_count);
load_from_cfg();
diff --git a/apps/plugins/metronome.c b/apps/plugins/metronome.c
index a6b4181df2..157d116ff9 100644
--- a/apps/plugins/metronome.c
+++ b/apps/plugins/metronome.c
@@ -1663,11 +1663,13 @@ enum plugin_status plugin_start(const void* file)
break;
case METRONOME_LEFT:
bpm_step_counter = 0;
+ /* fallthrough */
case METRONOME_LEFT_REP:
change_bpm(-1);
break;
case METRONOME_RIGHT:
bpm_step_counter = 0;
+ /* fallthrough */
case METRONOME_RIGHT_REP:
change_bpm(1);
break;
diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c
index bb295f1029..6622b5fdb6 100644
--- a/apps/plugins/mikmod/mikmod.c
+++ b/apps/plugins/mikmod/mikmod.c
@@ -682,7 +682,9 @@ static int main_menu(void)
/* double buffering thread */
static void thread(void)
{
- struct queue_event ev;
+ struct queue_event ev = {
+ .id = 0,
+ };
while (1)
{
diff --git a/apps/plugins/mpegplayer/libmpeg2/header.c b/apps/plugins/mpegplayer/libmpeg2/header.c
index 001cafe7d5..b40193a338 100644
--- a/apps/plugins/mpegplayer/libmpeg2/header.c
+++ b/apps/plugins/mpegplayer/libmpeg2/header.c
@@ -307,6 +307,7 @@ static int sequence_ext (mpeg2dec_t * mpeg2dec)
return 1;
case 2: /* 4:2:0 */
sequence->chroma_height >>= 1;
+ /* fallthrough */
case 4: /* 4:2:2 */
sequence->chroma_width >>= 1;
}
diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c
index b1445781d0..c904de466d 100644
--- a/apps/plugins/mpegplayer/mpeg_settings.c
+++ b/apps/plugins/mpegplayer/mpeg_settings.c
@@ -988,8 +988,8 @@ static int get_start_time(uint32_t duration)
mpegplayer_iram_preserve();
#endif
rb->talk_disable(false);
- rb->talk_value(resume_time / TS_SECOND, UNIT_TIME, false);
- rb->talk_value(resume_time * 100 / duration, UNIT_PERCENT, true);
+ talk_val(resume_time / TS_SECOND, UNIT_TIME, false);
+ talk_val(resume_time * 100 / duration, UNIT_PERCENT, true);
}
sliding = false;
}
diff --git a/apps/plugins/open_plugins.c b/apps/plugins/open_plugins.c
index f9133f91bb..3a0c34d8d6 100644
--- a/apps/plugins/open_plugins.c
+++ b/apps/plugins/open_plugins.c
@@ -49,7 +49,8 @@
static int fd_dat;
static struct gui_synclist lists;
struct open_plugin_entry_t op_entry;
-const off_t op_entry_sz = sizeof(struct open_plugin_entry_t);
+static const uint32_t open_plugin_csum = OPEN_PLUGIN_CHECKSUM;
+static const off_t op_entry_sz = sizeof(struct open_plugin_entry_t);
/* we only need the names for the first menu so don't bother reading paths yet */
const off_t op_name_sz = OPEN_PLUGIN_NAMESZ + (op_entry.name - (char*)&op_entry);
@@ -101,6 +102,15 @@ static bool op_entry_read_name(int fd, int selected_item)
return op_entry_read(fd, selected_item, op_name_sz);
}
+static int op_entry_checksum(void)
+{
+ if (op_entry.checksum != open_plugin_csum)
+ {
+ return 0;
+ }
+ return 1;
+}
+
static int op_entry_read_opx(const char *path)
{
int ret = -1;
@@ -112,13 +122,14 @@ static int op_entry_read_opx(const char *path)
if(len > OP_LEN && rb->strcasecmp(&((path)[len-OP_LEN]), "." OP_EXT) == 0)
{
fd_opx = rb->open(path, O_RDONLY);
- if (fd_opx)
+ if (fd_opx >= 0)
{
filesize = rb->filesize(fd_opx);
ret = filesize;
if (filesize == op_entry_sz && !op_entry_read(fd_opx, 0, op_entry_sz))
ret = 0;
-
+ else if (op_entry_checksum() <= 0)
+ ret = 0;
rb->close(fd_opx);
}
}
@@ -131,7 +142,7 @@ static void op_entry_export(int selection)
int fd = -1;
char filename [MAX_PATH + 1];
- if (!op_entry_read(fd_dat, selection, op_entry_sz))
+ if (!op_entry_read(fd_dat, selection, op_entry_sz) || op_entry_checksum() <= 0)
goto failure;
rb->snprintf(filename, MAX_PATH, "%s/%s", PLUGIN_APPS_DIR, op_entry.name);
@@ -161,6 +172,11 @@ failure:
}
+static void op_entry_set_checksum(void)
+{
+ op_entry.checksum = open_plugin_csum;
+}
+
static void op_entry_set_name(void)
{
char tmp_buf[OPEN_PLUGIN_NAMESZ+1];
@@ -277,12 +293,12 @@ static int op_entry_transfer(int fd, int fd_tmp,
void *data)
{
int entries = -1;
- if (fd_tmp && fd && rb->lseek(fd, 0, SEEK_SET) == 0)
+ if (fd_tmp >= 0 && fd >= 0 && rb->lseek(fd, 0, SEEK_SET) == 0)
{
entries = 0;
while (rb->read(fd, &op_entry, op_entry_sz) == op_entry_sz)
{
- if (compfn && compfn(&op_entry, entries, data) > 0)
+ if (compfn && compfn(&op_entry, entries, data) > 0 && op_entry_checksum() > 0)
{
rb->write(fd_tmp, &op_entry, op_entry_sz);
entries++;
@@ -296,6 +312,7 @@ static uint32_t op_entry_add_path(const char *key, const char *plugin, const cha
{
int len;
uint32_t hash;
+ uint32_t newhash;
char *pos = "";;
int fd_tmp = -1;
use_key = (use_key == true && key != NULL);
@@ -309,7 +326,8 @@ static uint32_t op_entry_add_path(const char *key, const char *plugin, const cha
{
/* need to keep the old hash so we can remove the old entry */
hash = op_entry.hash;
- open_plugin_get_hash(plugin, &op_entry.hash);
+ open_plugin_get_hash(plugin, &newhash);
+ op_entry.hash = newhash;
}
else
hash = op_entry.hash;
@@ -352,9 +370,12 @@ static uint32_t op_entry_add_path(const char *key, const char *plugin, const cha
/* hash on the parameter path if it is a file */
if (op_entry.lang_id <0 && key == op_entry.path &&
rb->file_exists(op_entry.param))
- open_plugin_get_hash(op_entry.path, &op_entry.hash);
+ {
+ open_plugin_get_hash(op_entry.path, &newhash);
+ op_entry.hash = newhash;
+ }
}
-
+ op_entry_set_checksum();
rb->write(fd_tmp, &op_entry, op_entry_sz); /* add new entry first */
}
else if(op_entry_read_opx(plugin) == op_entry_sz)
@@ -369,13 +390,13 @@ static uint32_t op_entry_add_path(const char *key, const char *plugin, const cha
open_plugin_get_hash(op_entry.path, &hash);
op_entry.hash = hash;
-
+ op_entry_set_checksum();
rb->write(fd_tmp, &op_entry, op_entry_sz); /* add new entry first */
}
else
{
if (op_entry.lang_id != LANG_SHORTCUTS)
- rb->splashf(HZ / 2, rb->str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), pos);
+ rb->splashf(HZ * 2, rb->str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), pos);
return 0;
}
}
@@ -495,7 +516,7 @@ static const char* list_get_name_cb(int selected_item, void* data,
char* buf, size_t buf_len)
{
/*TODO memoize names so we don't keep reading the disk when not necessary */
- if (data == &MENU_ID_MAIN)
+ if (data == (void*) &MENU_ID_MAIN) /* check address */
{
if (op_entry_read_name(fd_dat, selected_item))
{
@@ -549,7 +570,7 @@ static const char* list_get_name_cb(int selected_item, void* data,
static int list_voice_cb(int list_index, void* data)
{
- if (data == &MENU_ID_MAIN)
+ if (data == (void*) &MENU_ID_MAIN) /* check address */
{
if (op_entry_read_name(fd_dat, list_index))
{
@@ -840,7 +861,7 @@ reopen_datfile:
synclist_set(MENU_ID_MAIN, selection, items, 1);
rb->gui_synclist_draw(&lists);
- while (!exit)
+ while (!exit && fd_dat >= 0)
{
action = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c
index 9731d92d35..a170a57ec4 100644
--- a/apps/plugins/pictureflow/pictureflow.c
+++ b/apps/plugins/pictureflow/pictureflow.c
@@ -571,7 +571,7 @@ static bool confirm_quit(void)
{ (const char*[]) {"Quit?", "Progress will be lost"}, 2};
enum yesno_res response = rb->gui_syncyesno_run(&prompt, NULL, NULL);
while (rb->button_get(false) == BUTTON_NONE)
- ;;
+ {;;}
if(response == YESNO_NO)
return false;
@@ -1056,8 +1056,8 @@ static int create_album_untagged(struct tagcache_search *tcs,
draw_splashscreen(*buf, *bufsz);
draw_progressbar(0, total_count, "Searching " UNTAGGED);
- /* search tagcache for all <untagged> albums & save the albumartist seek pos */
- if (rb->tagcache_search(tcs, tag_albumartist))
+ /* search tagcache for all <untagged> albums & save the canonicalartist seek pos */
+ if (rb->tagcache_search(tcs, tag_virt_canonicalartist))
{
rb->tagcache_search_add_filter(tcs, tag_album, pf_idx.album_untagged_seek);
@@ -1160,7 +1160,7 @@ static int build_artist_index(struct tagcache_search *tcs,
/* artist names starts at beginning of buf */
pf_idx.artist_names = *buf;
- rb->tagcache_search(tcs, tag_albumartist);
+ rb->tagcache_search(tcs, tag_virt_canonicalartist);
res = get_tcs_search_res(ePFS_ARTIST, tcs, &(*buf), bufsz);
rb->tagcache_search_finish(tcs);
if (res < SUCCESS)
@@ -1267,7 +1267,7 @@ static int create_album_index(void)
draw_progressbar(j, pf_idx.album_ct, NULL);
if (pf_idx.album_index[j].artist_seek >= 0) { continue; }
- rb->tagcache_search(&tcs, tag_albumartist);
+ rb->tagcache_search(&tcs, tag_virt_canonicalartist);
rb->tagcache_search_add_filter(&tcs, tag_album, pf_idx.album_index[j].seek);
last = 0;
@@ -1601,7 +1601,7 @@ static void create_track_index(const int slide_index)
if (pf_idx.album_index[slide_index].artist_idx >= 0)
{
- rb->tagcache_search_add_filter(&tcs, tag_albumartist,
+ rb->tagcache_search_add_filter(&tcs, tag_virt_canonicalartist,
pf_idx.album_index[slide_index].artist_seek);
}
@@ -1756,7 +1756,7 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf,
rb->tagcache_search_add_filter(&tcs, tag_album,
pf_idx.album_index[slide_index].seek);
- rb->tagcache_search_add_filter(&tcs, tag_albumartist,
+ rb->tagcache_search_add_filter(&tcs, tag_virt_canonicalartist,
pf_idx.album_index[slide_index].artist_seek);
if ( rb->tagcache_get_next(&tcs) ) {
@@ -2286,7 +2286,7 @@ static bool free_slide_prio(int prio)
static void free_all_slide_prio(int prio)
{
while (free_slide_prio(prio))
- ;;
+ {;;}
}
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
index 28f539f49f..6e706248aa 100644
--- a/apps/plugins/properties.c
+++ b/apps/plugins/properties.c
@@ -33,9 +33,18 @@ char str_date[64];
char str_time[64];
char str_title[MAX_PATH];
+char str_composer[MAX_PATH];
char str_artist[MAX_PATH];
+char str_albumartist[MAX_PATH];
char str_album[MAX_PATH];
+char str_genre[MAX_PATH];
+char str_comment[MAX_PATH];
+char str_year[MAX_PATH];
+char str_discnum[MAX_PATH];
+char str_tracknum[MAX_PATH];
char str_duration[32];
+char str_bitrate[32];
+char str_frequency[32];
unsigned nseconds;
unsigned long nsize;
@@ -51,10 +60,19 @@ static const unsigned char* const props_file[] =
ID2P(LANG_PROPERTIES_SIZE), str_size,
ID2P(LANG_PROPERTIES_DATE), str_date,
ID2P(LANG_PROPERTIES_TIME), str_time,
+ ID2P(LANG_PROPERTIES_COMPOSER), str_composer,
ID2P(LANG_PROPERTIES_ARTIST), str_artist,
+ ID2P(LANG_PROPERTIES_ALBUMARTIST), str_albumartist,
ID2P(LANG_PROPERTIES_TITLE), str_title,
ID2P(LANG_PROPERTIES_ALBUM), str_album,
+ ID2P(LANG_PROPERTIES_GENRE), str_genre,
+ ID2P(LANG_PROPERTIES_COMMENT), str_comment,
+ ID2P(LANG_PROPERTIES_YEAR), str_year,
+ ID2P(LANG_PROPERTIES_DISCNUM), str_discnum,
+ ID2P(LANG_PROPERTIES_TRACKNUM), str_tracknum,
ID2P(LANG_PROPERTIES_DURATION), str_duration,
+ ID2P(LANG_PROPERTIES_BITRATE), str_bitrate,
+ ID2P(LANG_PROPERTIES_FREQUENCY), str_frequency,
};
static const unsigned char* const props_dir[] =
{
@@ -117,13 +135,31 @@ static bool file_properties(const char* selected_file)
rb->get_metadata(&id3, fd, selected_file))
{
long dur = id3.length / 1000; /* seconds */
+ rb->snprintf(str_composer, sizeof str_composer,
+ "%s", id3.composer ? id3.composer : "");
rb->snprintf(str_artist, sizeof str_artist,
"%s", id3.artist ? id3.artist : "");
+ rb->snprintf(str_albumartist, sizeof str_albumartist,
+ "%s", id3.albumartist ? id3.albumartist : "");
rb->snprintf(str_title, sizeof str_title,
"%s", id3.title ? id3.title : "");
rb->snprintf(str_album, sizeof str_album,
"%s", id3.album ? id3.album : "");
- num_properties += 3;
+ rb->snprintf(str_genre, sizeof str_genre,
+ "%s", id3.genre_string ? id3.genre_string : "");
+ rb->snprintf(str_comment, sizeof str_comment,
+ "%s", id3.comment ? id3.comment : "");
+ rb->snprintf(str_year, sizeof str_year,
+ "%s", id3.year_string ? id3.year_string : "");
+ rb->snprintf(str_discnum, sizeof str_discnum,
+ "%s", id3.disc_string ? id3.disc_string : "");
+ rb->snprintf(str_tracknum, sizeof str_tracknum,
+ "%s", id3.track_string ? id3.track_string : "");
+ rb->snprintf(str_bitrate, sizeof str_bitrate,
+ "%d kbps", id3.bitrate ? : 0);
+ rb->snprintf(str_frequency, sizeof str_frequency,
+ "%ld Hz", id3.frequency ? : 0);
+ num_properties += 12;
if (dur > 0)
{
@@ -334,7 +370,7 @@ static int speak_property_selection(int selected_item, void *data)
rb->talk_time(&tm, true);
break;
case LANG_PROPERTIES_DURATION:
- rb->talk_value(nseconds, UNIT_TIME, true);
+ rb->talk_value_decimal(nseconds, UNIT_TIME, 0, true);
break;
case LANG_PROPERTIES_SUBDIRS:
rb->talk_number(dps->dc, true);
diff --git a/apps/plugins/random_folder_advance_config.c b/apps/plugins/random_folder_advance_config.c
index c9dce0223b..2c9fb411ac 100644
--- a/apps/plugins/random_folder_advance_config.c
+++ b/apps/plugins/random_folder_advance_config.c
@@ -211,7 +211,7 @@ static bool custom_dir(void)
rb->close(fd2);
if(errors)
/* Press button to continue */
- rb->get_action(CONTEXT_STD, TIMEOUT_BLOCK);
+ rb->get_action(CONTEXT_STD, TIMEOUT_BLOCK);
}
else
return false;
@@ -259,11 +259,11 @@ static int load_list(void)
{
return -2;
}
-
+
rb->read(myfd,buffer,buffer_size);
rb->close(myfd);
list = (struct file_format *)buffer;
-
+
return 0;
}
@@ -288,7 +288,7 @@ static int save_list(void)
rb->lseek(myfd,0,SEEK_SET);
rb->write(myfd,&dirs_count,sizeof(int));
rb->close(myfd);
-
+
return 1;
}
@@ -298,22 +298,22 @@ static int edit_list(void)
bool exit = false;
int button,i;
int selection, ret = 0;
-
+
/* load the dat file if not already done */
if ((list == NULL || list->count == 0) && (i = load_list()) != 0)
{
rb->splashf(HZ*2, "Could not load %s, rv = %d", RFA_FILE, i);
return -1;
}
-
+
dirs_count = list->count;
-
+
rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1, NULL);
rb->gui_synclist_set_icon_callback(&lists,NULL);
rb->gui_synclist_set_nb_items(&lists,list->count);
rb->gui_synclist_limit_scroll(&lists,true);
rb->gui_synclist_select_item(&lists, 0);
-
+
while (!exit)
{
rb->gui_synclist_draw(&lists);
@@ -366,6 +366,7 @@ static int edit_list(void)
{
case 0:
save_list();
+ /* fallthrough */
case 1:
exit = true;
ret = -2;
@@ -386,22 +387,22 @@ static int export_list_to_file_text(void)
rb->splashf(HZ*2, "Could not load %s, rv = %d", RFA_FILE, i);
return 0;
}
-
+
if (list->count <= 0)
{
rb->splashf(HZ*2, "no dirs in list file: %s", RFA_FILE);
return 0;
}
-
+
/* create and open the file */
int myfd = rb->creat(RFA_FILE_TEXT, 0666);
if (myfd < 0)
{
- rb->splashf(HZ*4, "failed to open: fd = %d, file = %s",
+ rb->splashf(HZ*4, "failed to open: fd = %d, file = %s",
myfd, RFA_FILE_TEXT);
return -1;
}
-
+
/* write each directory to file */
for (i = 0; i < list->count; i++)
{
@@ -410,7 +411,7 @@ static int export_list_to_file_text(void)
rb->fdprintf(myfd, "%s\n", list->folder[i]);
}
}
-
+
rb->close(myfd);
rb->splash(HZ, "Done");
return 1;
@@ -419,7 +420,7 @@ static int export_list_to_file_text(void)
static int import_list_from_file_text(void)
{
char line[MAX_PATH];
-
+
buffer = rb->plugin_get_audio_buffer(&buffer_size);
if (buffer == NULL)
{
@@ -433,11 +434,11 @@ static int import_list_from_file_text(void)
rb->splashf(HZ*2, "failed to open: %s", RFA_FILE_TEXT);
return -1;
}
-
+
/* set the list structure, and initialize count */
list = (struct file_format *)buffer;
list->count = 0;
-
+
while ((rb->read_line(myfd, line, MAX_PATH - 1)) > 0)
{
/* copy the dir name, and skip the newline */
@@ -447,16 +448,16 @@ static int import_list_from_file_text(void)
{
if (line[len-1] == 0x0A || line[len-1] == 0x0D)
line[len-1] = 0x00;
- if (len > 1 &&
+ if (len > 1 &&
(line[len-2] == 0x0A || line[len-2] == 0x0D))
line[len-2] = 0x00;
}
-
+
rb->strcpy(list->folder[list->count++], line);
}
-
+
rb->close(myfd);
-
+
if (list->count == 0)
{
load_list();
@@ -483,14 +484,14 @@ static int start_shuffled_play(void)
rb->splashf(HZ*2, "Not enough memory for shuffling");
return 0;
}
-
+
/* load the dat file if not already done */
if ((list == NULL || list->count == 0) && (i = load_list()) != 0)
{
rb->splashf(HZ*2, "Could not load %s, rv = %d", RFA_FILE, i);
return 0;
}
-
+
if (list->count <= 0)
{
rb->splashf(HZ*2, "no dirs in list file: %s", RFA_FILE);
@@ -506,7 +507,7 @@ static int start_shuffled_play(void)
}
for(i=0;i<list->count;i++)
order[i]=i;
-
+
for(i = list->count - 1; i >= 0; i--)
{
/* the rand is from 0 to RAND_MAX, so adjust to our value range */
@@ -517,7 +518,7 @@ static int start_shuffled_play(void)
order[candidate] = order[i];
order[i] = store;
}
-
+
/* We don't want whatever is playing */
if (!(rb->playlist_remove_all_tracks(NULL) == 0
&& rb->playlist_create(NULL, NULL) == 0))
@@ -642,6 +643,6 @@ enum plugin_status plugin_start(const void* parameter)
#endif
cancel = false;
-
+
return main_menu();
}
diff --git a/apps/plugins/resistor.c b/apps/plugins/resistor.c
index 2e204010a9..d32ac3fad9 100644
--- a/apps/plugins/resistor.c
+++ b/apps/plugins/resistor.c
@@ -953,9 +953,9 @@ static void color_to_resistance(void)
if(third_band==RES_INVALID) break;
fourth_band = do_fourth_band_menu();
- if(third_band==RES_INVALID) break;
-
- total_resistance_centiunits = calculate_resistance(first_band,
+ if(fourth_band==RES_INVALID) break;
+
+ total_resistance_centiunits = calculate_resistance(first_band,
second_band,
third_band);
diff --git a/apps/plugins/rocklife.c b/apps/plugins/rocklife.c
index 0be48dcce8..99297abd0f 100644
--- a/apps/plugins/rocklife.c
+++ b/apps/plugins/rocklife.c
@@ -150,6 +150,7 @@ static bool load_cellfile(const char *file, char *pgrid){
switch(c) {
case '!':
comment = true;
+ break;
case '.':
if (!comment)
x++;
diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c
index a0d9b26ec2..09fa2c8c5f 100644
--- a/apps/plugins/rockpaint.c
+++ b/apps/plugins/rockpaint.c
@@ -1907,6 +1907,7 @@ static void draw_text( int x, int y )
rb->lcd_set_foreground( rp_colors[ drawcolor ] );
buffer_putsxyofs( save_buffer, COLS, ROWS, x, y, 0,
buffer->text.text );
+ /* fallthrough */
case TEXT_MENU_CANCEL:
default:
restore_screen();
diff --git a/apps/plugins/test_disk.c b/apps/plugins/test_disk.c
index b689ba672e..1429668556 100644
--- a/apps/plugins/test_disk.c
+++ b/apps/plugins/test_disk.c
@@ -156,7 +156,7 @@ static bool test_fs(void)
fd = rb->open(TEST_FILE, O_RDONLY);
if (fd < 0)
{
- rb->splashf(0, "open() failed: %d", ret);
+ rb->splashf(0, "open() failed: %d", fd);
goto error;
}
diff --git a/apps/plugins/test_viewports.c b/apps/plugins/test_viewports.c
index 669766a207..2bada01f79 100644
--- a/apps/plugins/test_viewports.c
+++ b/apps/plugins/test_viewports.c
@@ -245,7 +245,7 @@ enum plugin_status plugin_start(const void* parameter)
#endif
rb->button_clear_queue();
while(rb->button_get(true) <= BUTTON_NONE)
- ;;
+ {;;}
rb->button_get(true);
diff --git a/apps/plugins/vbrfix.c b/apps/plugins/vbrfix.c
index 768ec9d99f..88f0a6579e 100644
--- a/apps/plugins/vbrfix.c
+++ b/apps/plugins/vbrfix.c
@@ -37,7 +37,7 @@ static void xingupdate(int percent)
long now = *(rb->current_tick) / HZ;
if (now - last_talk >= 5)
{
- rb->talk_value(percent, UNIT_PERCENT, false);
+ rb->talk_value_decimal(percent, UNIT_PERCENT, 0, false);
last_talk = now;
}
}
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index cc53716674..de623d28b7 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -122,3 +122,11 @@ const unsigned char bitmap_icon_disk[12] =
{0x00,0x00,0x00,0x1c,0x2e,0x4f,0x77,0x79,0x3a,0x1c,0x00,0x00};
#endif
+const struct cbmp_bitmap_info_entry core_bitmaps[CBMP_BitmapFormatLast] = /* */
+{
+/* index, pointer, w, h, count */
+[CBMP_Mono_5x8] = {bitmap_icons_5x8[0], 5,8, Icon5x8Last},
+[CBMP_Mono_7x8] = {bitmap_icons_7x8[0], 7, 8, Icon7x8Last},
+[CBMP_Mono_12x8] = {bitmap_icon_disk, 12, 8, 1},
+};
+
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index 249453a943..944f319415 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -32,7 +32,25 @@
#ifdef HAVE_REMOTE_LCD
#include "bitmaps/remote_rockboxlogo.h"
#endif
+#endif /* PLUGIN */
+
+struct cbmp_bitmap_info_entry /* */
+{
+ const unsigned char* pbmp;
+ unsigned char width;
+ unsigned char height; /* !ASSUMES MULTIPLES OF 8! */
+ unsigned char count;
+};
+
+enum cbmp_bitmap_format
+{
+ CBMP_Mono_5x8 = 0,
+ CBMP_Mono_7x8,
+ CBMP_Mono_12x8,
+ CBMP_BitmapFormatLast
+};
+extern const struct cbmp_bitmap_info_entry core_bitmaps[CBMP_BitmapFormatLast];
/* Symbolic names for icons */
enum icons_5x8 {
@@ -65,6 +83,12 @@ enum icons_7x8 {
Icon7x8Last
};
+enum icons_12x8 {
+ Icon_Disk,
+ Icon12x8Last
+};
+
+#ifndef PLUGIN
#if defined (HAVE_RECORDING)
#define BM_GLYPH_WIDTH 4
enum Glyphs_4x8 {
diff --git a/apps/recorder/jpeg_common.h b/apps/recorder/jpeg_common.h
index c2abce8f49..de998f1ddd 100644
--- a/apps/recorder/jpeg_common.h
+++ b/apps/recorder/jpeg_common.h
@@ -83,8 +83,8 @@ union uint8_rgbyuv {
static inline int clamp_component(int x)
{
- if ((unsigned)x > 255)
- x = x < 0 ? 0 : 255;
+ if(x > 255) return 255;
+ if(x < 0) return 0;
return x;
}
#include <debug.h>
diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c
index b5de670c0d..9b0e779485 100644
--- a/apps/recorder/pcm_record.c
+++ b/apps/recorder/pcm_record.c
@@ -873,46 +873,58 @@ static bool open_rec_file(bool create)
static void * ICODE_ATTR
copy_buffer_mono_lr(void *dst, const void *src, size_t src_size)
{
- int16_t *d = dst;
- int16_t const *s = src;
-
- /* mono = (L + R) / 2 */
+ int16_t *d = (int16_t*) dst;
+ int16_t const *s = (int16_t const*) src;
+ ssize_t copy_size = src_size;
+
+ /* mono = (L + R) / 2 */
do
- *d++ = ((int32_t){ *s++ } + *s++ + 1) >> 1;
- while (src_size -= PCM_SAMP_SIZE);
+ {
+ *d++ = ((int32_t){s[0]} + s[1] + 1) >> 1;
+ s+=2;
+ }
+ while ((copy_size -= PCM_SAMP_SIZE) > 0);
return dst;
}
/* Copy with mono conversion - output 1/2 size of input */
static void * ICODE_ATTR
-copy_buffer_mono_l(void *dst, const void *src, size_t src_size)
+copy_buffer_mono_r(void *dst, const void *src, size_t src_size)
{
- int16_t *d = dst;
- int16_t const *s = (int16_t *)src - 2;
-
- /* mono = L */
+ int16_t *d = (int16_t*)dst;
+ int16_t const *s = (int16_t const*)src - 1;
+ ssize_t copy_size = src_size;
+ /* mono = R */
do
*d++ = *(s += 2);
- while (src_size -= PCM_SAMP_SIZE);
+ while ((copy_size -= PCM_SAMP_SIZE) > 0);
return dst;
}
+#if 1
+static void * ICODE_ATTR
+copy_buffer_mono_l(void *dst, const void *src, size_t src_size)
+{
+ return copy_buffer_mono_r(dst, src -1, src_size);
+}
+#else
/* Copy with mono conversion - output 1/2 size of input */
static void * ICODE_ATTR
-copy_buffer_mono_r(void *dst, const void *src, size_t src_size)
+copy_buffer_mono_l(void *dst, const void *src, size_t src_size)
{
- int16_t *d = dst;
- int16_t const *s = (int16_t *)src - 1;
-
- /* mono = R */
+ int16_t *d = (int16_t*)dst;
+ int16_t const *s = (int16_t const*)src - 2;
+ ssize_t copy_size = src_size;
+ /* mono = L */
do
*d++ = *(s += 2);
- while (src_size -= PCM_SAMP_SIZE);
+ while ((copy_size -= PCM_SAMP_SIZE) > 0);
return dst;
}
+#endif
/** pcm_rec_* group **/
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c
index e8e5db551a..900bb6d7c3 100644
--- a/apps/recorder/peakmeter.c
+++ b/apps/recorder/peakmeter.c
@@ -46,9 +46,7 @@
#include "pcm_record.h"
#endif
-#if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
static bool pm_playback = true; /* selects between playback and recording peaks */
-#endif
static struct meter_scales scales[NB_SCREENS];
@@ -543,11 +541,7 @@ void pm_reset_clipcount(void)
*/
void peak_meter_playback(bool playback)
{
-#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
- (void)playback;
-#else
pm_playback = playback;
-#endif
/* reset the scales just in case recording and playback
use different viewport sizes. Normally we should be checking viewport
sizes every time but this will do for now */
@@ -582,10 +576,6 @@ void peak_meter_peek(void)
bool was_clipping = pm_clip_left || pm_clip_right;
#endif
/* read current values */
-#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
- pm_cur_left = left = 8000;
- pm_cur_right = right = 9000;
-#else
if (pm_playback)
{
static struct pcm_peaks chan_peaks; /* *MUST* be static */
@@ -600,7 +590,6 @@ void peak_meter_peek(void)
#endif
left = pm_cur_left;
right = pm_cur_right;
-#endif
/* check for clips
An clip is assumed when two consecutive readouts
@@ -1078,9 +1067,7 @@ static void peak_meter_draw(struct screen *display, struct meter_scales *scales,
/* cliplight */
if ((pm_clip_left || pm_clip_right) &&
global_settings.cliplight
-#if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
&& !pm_playback
-#endif
)
{
/* if clipping, cliplight setting on and in recording screen */
diff --git a/apps/root_menu.c b/apps/root_menu.c
index 62014b619d..15d03a7cda 100644
--- a/apps/root_menu.c
+++ b/apps/root_menu.c
@@ -166,7 +166,7 @@ static int browser(void* param)
}
}
if (!in_hotswap)
-#endif
+#endif /*HAVE_HOTSWAP*/
strcpy(folder, last_folder);
}
push_current_activity(ACTIVITY_FILEBROWSER);
@@ -266,7 +266,7 @@ static int browser(void* param)
tc->selected_item = last_db_selection;
push_current_activity(ACTIVITY_DATABASEBROWSER);
break;
-#endif
+#endif /*HAVE_TAGCACHE*/
}
browse_context_init(&browse, filter, 0, NULL, NOICON, folder, NULL);
@@ -705,7 +705,7 @@ static int load_context_screen(int selection)
return retval;
}
-static int load_plugin_screen(char *plug_path, void* plug_param)
+static int load_plugin_screen(char *key)
{
int ret_val;
int old_previous = last_screen;
@@ -713,7 +713,15 @@ static int load_plugin_screen(char *plug_path, void* plug_param)
global_status.last_screen = (char)next_screen;
status_save();
- switch (plugin_load(plug_path, plug_param))
+
+ int opret = open_plugin_get_entry(key, &open_plugin_entry);
+ bool flush = (opret == OPEN_PLUGIN_NEEDS_FLUSHED);
+ char *path = open_plugin_entry.path;
+ char *param = open_plugin_entry.param;
+ if (param[0] == '\0')
+ param = NULL;
+
+ switch (plugin_load(path, param))
{
case PLUGIN_GOTO_WPS:
ret_val = GO_TO_WPS;
@@ -729,59 +737,88 @@ static int load_plugin_screen(char *plug_path, void* plug_param)
break;
}
+ if (!flush && ret_val != GO_TO_PLUGIN)
+ open_plugin_add_path(NULL, NULL, NULL);
+
if (ret_val == GO_TO_PREVIOUS)
last_screen = (old_previous == next_screen) ? GO_TO_ROOT : old_previous;
return ret_val;
}
-void root_menu(void)
+static void ignore_back_button_stub(bool ignore)
{
- int previous_browser = GO_TO_FILEBROWSER;
- int selected = 0;
- int shortcut_origin = GO_TO_ROOT;
-
- push_current_activity(ACTIVITY_MAINMENU);
+#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
+ /* BACK button to be handled by Android instead of rockbox */
+ android_ignore_back_button(ignore);
+#else
+ (void) ignore;
+#endif
+}
+static int root_menu_setup_screens(void)
+{
+ int new_screen = next_screen;
if (global_settings.start_in_screen == 0)
- next_screen = (int)global_status.last_screen;
- else next_screen = global_settings.start_in_screen - 2;
+ new_screen = (int)global_status.last_screen;
+ else new_screen = global_settings.start_in_screen - 2;
#if CONFIG_TUNER
add_event(PLAYBACK_EVENT_START_PLAYBACK, rootmenu_start_playback_callback);
#endif
add_event(PLAYBACK_EVENT_TRACK_CHANGE, rootmenu_track_changed_callback);
#ifdef HAVE_RTC_ALARM
+ int alarm_wake_up_screen = 0;
if ( rtc_check_alarm_started(true) )
{
rtc_enable_alarm(false);
- next_screen = GO_TO_WPS;
+
+#if (defined(HAVE_RECORDING) || CONFIG_TUNER)
+ alarm_wake_up_screen = global_settings.alarm_wake_up_screen;
+#endif
+ switch (alarm_wake_up_screen)
+ {
#if CONFIG_TUNER
- if (global_settings.alarm_wake_up_screen == ALARM_START_FM)
- next_screen = GO_TO_FM;
+ case ALARM_START_FM:
+ new_screen = GO_TO_FM;
+ break;
#endif
#ifdef HAVE_RECORDING
- if (global_settings.alarm_wake_up_screen == ALARM_START_REC)
- {
- recording_start_automatic = true;
- next_screen = GO_TO_RECSCREEN;
- }
+ case ALARM_START_REC:
+ recording_start_automatic = true;
+ new_screen = GO_TO_RECSCREEN;
+ break;
#endif
+ default:
+ new_screen = GO_TO_WPS;
+ break;
+ } /* switch() */
}
#endif /* HAVE_RTC_ALARM */
#if defined(HAVE_HEADPHONE_DETECTION) || defined(HAVE_LINEOUT_DETECTION)
- if (next_screen == GO_TO_WPS && global_settings.unplug_autoresume)
+ if (new_screen == GO_TO_WPS && global_settings.unplug_autoresume)
{
- next_screen = GO_TO_ROOT;
+ new_screen = GO_TO_ROOT;
#ifdef HAVE_HEADPHONE_DETECTION
if (headphones_inserted())
- next_screen = GO_TO_WPS;
+ new_screen = GO_TO_WPS;
#endif
#ifdef HAVE_LINEOUT_DETECTION
if (lineout_inserted())
- next_screen = GO_TO_WPS;
+ new_screen = GO_TO_WPS;
#endif
}
#endif /*(HAVE_HEADPHONE_DETECTION) || (HAVE_LINEOUT_DETECTION)*/
+ return new_screen;
+}
+
+void root_menu(void)
+{
+ int previous_browser = GO_TO_FILEBROWSER;
+ int selected = 0;
+ int shortcut_origin = GO_TO_ROOT;
+
+ push_current_activity(ACTIVITY_MAINMENU);
+ next_screen = root_menu_setup_screens();
while (true)
{
@@ -793,18 +830,32 @@ void root_menu(void)
case GO_TO_ROOT:
if (last_screen != GO_TO_ROOT)
selected = get_selection(last_screen);
-#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
+
/* When we are in the main menu we want the hardware BACK
- * button to be handled by Android instead of rockbox */
- android_ignore_back_button(true);
-#endif
+ * button to be handled by HOST instead of rockbox */
+ ignore_back_button_stub(true);
+
next_screen = do_menu(&root_menu_, &selected, NULL, false);
-#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
- android_ignore_back_button(false);
-#endif
+
+ ignore_back_button_stub(false);
+
if (next_screen != GO_TO_PREVIOUS)
last_screen = GO_TO_ROOT;
break;
+#ifdef HAVE_TAGCACHE
+ case GO_TO_FILEBROWSER:
+ case GO_TO_DBBROWSER:
+ previous_browser = next_screen;
+ goto load_next_screen;
+ break;
+#endif /* With !HAVE_TAGCACHE previous_browser is always GO_TO_FILEBROWSER */
+#if CONFIG_TUNER
+ case GO_TO_WPS:
+ case GO_TO_FM:
+ previous_music = next_screen;
+ goto load_next_screen;
+ break;
+#endif /* With !CONFIG_TUNER previous_music is always GO_TO_WPS */
case GO_TO_PREVIOUS:
next_screen = last_screen;
@@ -826,7 +877,6 @@ void root_menu(void)
if (global_status.last_screen == GO_TO_SHORTCUTMENU)
{
shortcut_origin = last_screen;
- global_status.last_screen = last_screen;
key = ID2P(LANG_SHORTCUTS);
}
else
@@ -848,16 +898,7 @@ void root_menu(void)
}
}
- open_plugin_get_entry(key, &open_plugin_entry);
- char *path = open_plugin_entry.path;
- char *param = open_plugin_entry.param;
- if (param[0] == '\0')
- param = NULL;
-
- next_screen = load_plugin_screen(path, param);
-
- if (next_screen != GO_TO_PLUGIN)
- open_plugin_add_path(NULL, NULL, NULL);
+ next_screen = load_plugin_screen(key);
/* shortcuts may take several trips through the GO_TO_PLUGIN case
make sure we preserve and restore the origin */
@@ -872,18 +913,12 @@ void root_menu(void)
break;
}
default:
-#ifdef HAVE_TAGCACHE
-/* With !HAVE_TAGCACHE previous_browser is always GO_TO_FILEBROWSER */
- if (next_screen == GO_TO_FILEBROWSER || next_screen == GO_TO_DBBROWSER)
- previous_browser = next_screen;
-#endif
-#if CONFIG_TUNER
-/* With !CONFIG_TUNER previous_music is always GO_TO_WPS */
- if (next_screen == GO_TO_WPS || next_screen == GO_TO_FM)
- previous_music = next_screen;
-#endif
- next_screen = load_screen(next_screen);
+ goto load_next_screen;
break;
} /* switch() */
+ continue;
+load_next_screen: /* load_screen is inlined */
+ next_screen = load_screen(next_screen);
}
+
}
diff --git a/apps/settings.c b/apps/settings.c
index f89fc581ca..3f257e093a 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -83,11 +83,7 @@ struct system_status global_status;
#include "pcm_sampr.h"
#define NVRAM_DATA_START 8
-#ifdef HAVE_RTC_RAM
-#define NVRAM_BLOCK_SIZE 44
-#else
#define NVRAM_BLOCK_SIZE (sizeof(struct system_status) + NVRAM_DATA_START)
-#endif
#define MAX_LINES 10
@@ -118,7 +114,6 @@ static bool read_nvram_data(char* buf, int max_len)
{
unsigned crc32 = 0xffffffff;
int var_count = 0, i = 0, buf_pos = 0;
-#ifndef HAVE_RTC_RAM
int fd = open(NVRAM_FILE, O_RDONLY);
int bytes;
if (fd < 0)
@@ -128,12 +123,6 @@ static bool read_nvram_data(char* buf, int max_len)
close(fd);
if (bytes < 8) /* min is 8 bytes,magic, ver, vars, crc32 */
return false;
-#else
- memset(buf,0,max_len);
- /* read rtc block */
- for (i=0; i < max_len; i++ )
- buf[i] = rtc_read(0x14+i);
-#endif
/* check magic, version */
if ((buf[0] != 'R') || (buf[1] != 'b')
|| (buf[2] != NVRAM_CONFIG_VERSION))
@@ -171,9 +160,7 @@ static bool write_nvram_data(char* buf, int max_len)
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';
@@ -195,7 +182,6 @@ static bool write_nvram_data(char* buf, int max_len)
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, 0666);
if (fd >= 0)
{
@@ -204,16 +190,6 @@ static bool write_nvram_data(char* buf, int max_len)
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)
- return false;
- }
-#endif
return true;
}
@@ -586,12 +562,12 @@ static bool settings_write_config(const char* filename, int options)
close(fd);
return true;
}
-#ifndef HAVE_RTC_RAM
+
static void flush_global_status_callback(void)
{
write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
}
-#endif
+
static void flush_config_block_callback(void)
{
write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
@@ -621,23 +597,12 @@ static void update_runtime(void)
void status_save(void)
{
update_runtime();
-#ifdef HAVE_RTC_RAM
- /* this will be done in the storage_callback if
- target doesnt have rtc ram */
- write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
-#else
register_storage_idle_func(flush_global_status_callback);
-#endif
}
int settings_save(void)
{
update_runtime();
-#ifdef HAVE_RTC_RAM
- /* this will be done in the storage_callback if
- target doesnt have rtc ram */
- write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
-#endif
register_storage_idle_func(flush_config_block_callback);
return 0;
}
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 5464416b21..d9ffd8cf3e 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -345,6 +345,12 @@ static const char graphic_numeric[] = "graphic,numeric";
#endif
#endif /* HAVE_BACKLIGHT */
+#if defined(HAVE_USB_CHARGING_ENABLE)
+# if !defined(TARGET_USB_CHARGING_DEFAULT)
+# define TARGET_USB_CHARGING_DEFAULT USB_CHARGING_ENABLE
+# endif
+#endif
+
#if LCD_DEPTH > 1
static const char* list_pad_formatter(char *buffer, size_t buffer_size,
int val, const char *unit)
@@ -1570,106 +1576,12 @@ const struct settings_list settings[] = {
/* equalizer */
OFFON_SETTING(F_EQSETTING, eq_enabled, LANG_EQUALIZER_ENABLED, false,
- "eq enabled", NULL),
+ "eq enabled", eq_enabled_option_callback),
INT_SETTING_NOWRAP(F_EQSETTING, eq_precut, LANG_EQUALIZER_PRECUT, 0,
"eq precut", UNIT_DB, 0, 240, 1, eq_precut_format,
get_precut_talkid, dsp_set_eq_precut),
- /* 0..32768 Hz */
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[0].cutoff, LANG_EQUALIZER_BAND_CUTOFF,
- 32, "eq band 0 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[1].cutoff, LANG_EQUALIZER_BAND_CENTER,
- 64, "eq band 1 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[2].cutoff, LANG_EQUALIZER_BAND_CENTER,
- 125, "eq band 2 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[3].cutoff, LANG_EQUALIZER_BAND_CENTER,
- 250, "eq band 3 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[4].cutoff, LANG_EQUALIZER_BAND_CENTER,
- 500, "eq band 4 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[5].cutoff, LANG_EQUALIZER_BAND_CENTER,
- 1000, "eq band 5 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[6].cutoff, LANG_EQUALIZER_BAND_CENTER,
- 2000, "eq band 6 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[7].cutoff, LANG_EQUALIZER_BAND_CENTER,
- 4000, "eq band 7 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[8].cutoff, LANG_EQUALIZER_BAND_CENTER,
- 8000, "eq band 8 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[9].cutoff, LANG_EQUALIZER_BAND_CUTOFF,
- 16000, "eq band 9 cutoff", UNIT_HERTZ, EQ_CUTOFF_MIN,
- EQ_CUTOFF_MAX, EQ_CUTOFF_STEP, NULL, NULL, NULL),
- /* 0..64 (or 0.0 to 6.4) */
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[0].q, LANG_EQUALIZER_BAND_Q, 7,
- "eq band 0 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[1].q, LANG_EQUALIZER_BAND_Q, 10,
- "eq band 1 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[2].q, LANG_EQUALIZER_BAND_Q, 10,
- "eq band 2 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[3].q, LANG_EQUALIZER_BAND_Q, 10,
- "eq band 3 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[4].q, LANG_EQUALIZER_BAND_Q, 10,
- "eq band 4 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[5].q, LANG_EQUALIZER_BAND_Q, 10,
- "eq band 5 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[6].q, LANG_EQUALIZER_BAND_Q, 10,
- "eq band 6 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[7].q, LANG_EQUALIZER_BAND_Q, 10,
- "eq band 7 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[8].q, LANG_EQUALIZER_BAND_Q, 10,
- "eq band 8 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[9].q, LANG_EQUALIZER_BAND_Q, 7,
- "eq band 9 q", UNIT_INT, EQ_Q_MIN, EQ_Q_MAX, EQ_Q_STEP,
- eq_q_format, get_dec_talkid, NULL),
- /* -240..240 (or -24db to +24db) */
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[0].gain, LANG_GAIN, 0,
- "eq band 0 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[1].gain, LANG_GAIN, 0,
- "eq band 1 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[2].gain, LANG_GAIN, 0,
- "eq band 2 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[3].gain, LANG_GAIN, 0,
- "eq band 3 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[4].gain, LANG_GAIN, 0,
- "eq band 4 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[5].gain, LANG_GAIN, 0,
- "eq band 5 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[6].gain, LANG_GAIN, 0,
- "eq band 6 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[7].gain, LANG_GAIN, 0,
- "eq band 7 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[8].gain, LANG_GAIN, 0,
- "eq band 8 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
- INT_SETTING_NOWRAP(F_DEPRECATED|F_EQSETTING, eq_band_settings[9].gain, LANG_GAIN, 0,
- "eq band 9 gain", UNIT_DB, EQ_GAIN_MIN, EQ_GAIN_MAX,
- EQ_GAIN_STEP, db_format, get_dec_talkid, NULL),
-
#define EQ_BAND(id, string) \
CUSTOM_SETTING(F_EQSETTING, eq_band_settings[id], -1, \
&eq_defaults[id], string, \
@@ -1921,7 +1833,7 @@ const struct settings_list settings[] = {
#endif
TEXT_SETTING(0,kbd_file,"kbd","-",ROCKBOX_DIR "/",".kbd"),
#ifdef HAVE_USB_CHARGING_ENABLE
- CHOICE_SETTING(0, usb_charging, LANG_USB_CHARGING, 1, "usb charging",
+ CHOICE_SETTING(0, usb_charging, LANG_USB_CHARGING, TARGET_USB_CHARGING_DEFAULT, "usb charging",
"off,on,force", NULL, 3, ID2P(LANG_SET_BOOL_NO),
ID2P(LANG_SET_BOOL_YES), ID2P(LANG_FORCE)),
#endif
diff --git a/apps/tagcache.c b/apps/tagcache.c
index e6a4e8e3c4..bf23ac74dc 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -21,12 +21,12 @@
/*
* TagCache API
- *
+ *
* ----------x---------x------------------x-----
* | | | External
* +---------------x-------+ | TagCache | Libraries
- * | Modification routines | | Core |
- * +-x---------x-----------+ | |
+ * | Modification routines | | Core |
+ * +-x---------x-----------+ | |
* | (R/W) | | | |
* | +------x-------------x-+ +-------------x-----+ |
* | | x==x Filters & clauses | |
@@ -50,9 +50,9 @@
* +-----------------+ \===x | |
* | | | | (R) | Ram DB Loader x============x DirCache
* +-x----x---x---x---+ /==x | | (optional)
- * | Tagcache Disk DB x==/ +-----------------+ |
+ * | Tagcache Disk DB x==/ +-----------------+ |
* +------------------+ |
- *
+ *
*/
/*#define LOGF_ENABLE*/
@@ -101,9 +101,12 @@ static struct event_queue tagcache_queue SHAREDBSS_ATTR;
static long tagcache_stack[(DEFAULT_STACK_SIZE + 0x4000)/sizeof(long)];
static const char tagcache_thread_name[] = "tagcache";
#endif
+/* buffer size for all the (stack allocated & static) buffers handling tc data */
+#define TAGCACHE_BUFSZ (TAG_MAXLEN+32)
+
/* Previous path when scanning directory tree recursively. */
-static char curpath[TAG_MAXLEN+32];
+static char curpath[TAGCACHE_BUFSZ];
/* Used when removing duplicates. */
static char *tempbuf; /* Allocated when needed. */
@@ -115,7 +118,7 @@ static long tempbuf_pos;
static int tempbuf_handle;
#endif
-#define SORTED_TAGS_COUNT 8
+#define SORTED_TAGS_COUNT 9
#define TAGCACHE_IS_UNIQUE(tag) (BIT_N(tag) & TAGCACHE_UNIQUE_TAGS)
#define TAGCACHE_IS_SORTED(tag) (BIT_N(tag) & TAGCACHE_SORTED_TAGS)
#define TAGCACHE_IS_NUMERIC_OR_NONUNIQUE(tag) \
@@ -123,18 +126,21 @@ static int tempbuf_handle;
/* Tags we want to get sorted (loaded to the tempbuf). */
#define TAGCACHE_SORTED_TAGS ((1LU << tag_artist) | (1LU << tag_album) | \
(1LU << tag_genre) | (1LU << tag_composer) | (1LU << tag_comment) | \
- (1LU << tag_albumartist) | (1LU << tag_grouping) | (1LU << tag_title))
+ (1LU << tag_albumartist) | (1LU << tag_grouping) | (1LU << tag_title) | \
+ (1LU << tag_virt_canonicalartist))
/* Uniqued tags (we can use these tags with filters and conditional clauses). */
#define TAGCACHE_UNIQUE_TAGS ((1LU << tag_artist) | (1LU << tag_album) | \
(1LU << tag_genre) | (1LU << tag_composer) | (1LU << tag_comment) | \
- (1LU << tag_albumartist) | (1LU << tag_grouping))
+ (1LU << tag_albumartist) | (1LU << tag_grouping) | \
+ (1LU << tag_virt_canonicalartist))
/* String presentation of the tags defined in tagcache.h. Must be in correct order! */
-static const char *tags_str[] = { "artist", "album", "genre", "title",
- "filename", "composer", "comment", "albumartist", "grouping", "year",
- "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating",
- "playtime", "lastplayed", "commitid", "mtime", "lastelapsed", "lastoffset" };
+static const char *tags_str[] = { "artist", "album", "genre", "title",
+ "filename", "composer", "comment", "albumartist", "grouping", "year",
+ "discnumber", "tracknumber", "canonicalartist", "bitrate", "length",
+ "playcount", "rating", "playtime", "lastplayed", "commitid", "mtime",
+ "lastelapsed", "lastoffset" };
/* Status information of the tagcache. */
static struct tagcache_stat tc_stat;
@@ -146,7 +152,7 @@ enum tagcache_queue {
Q_IMPORT_CHANGELOG,
Q_UPDATE,
Q_REBUILD,
-
+
/* Internal tagcache command queue. */
CMD_UPDATE_MASTER_HEADER,
CMD_UPDATE_NUMERIC,
@@ -200,7 +206,7 @@ static const char * const tagfile_entry_ec = "ll";
/**
Note: This should be (1 + TAG_COUNT) amount of l's.
*/
-static const char * const index_entry_ec = "lllllllllllllllllllllll";
+static const char * const index_entry_ec = "llllllllllllllllllllllll";
static const char * const tagcache_header_ec = "lll";
static const char * const master_header_ec = "llllll";
@@ -263,14 +269,14 @@ static inline void tcrc_buffer_unlock(void)
#endif /* HAVE_TC_RAMCACHE */
-/**
- * Full tag entries stored in a temporary file waiting
+/**
+ * Full tag entries stored in a temporary file waiting
* for commit to the cache. */
struct temp_file_entry {
long tag_offset[TAG_COUNT];
short tag_length[TAG_COUNT];
long flag;
-
+
long data_length;
};
@@ -303,6 +309,11 @@ static volatile int read_lock;
static bool delete_entry(long idx_id);
+static inline void str_setlen(char *buf, size_t len)
+{
+ buf[len] = '\0';
+}
+
static void allocate_tempbuf(void)
{
/* Yeah, malloc would be really nice now :) */
@@ -349,6 +360,27 @@ static ssize_t ecread_tagfile_entry(int fd, struct tagfile_entry *buf)
return ecread(fd, buf, 1, tagfile_entry_ec, tc_stat.econ);
}
+enum e_ecread_errors {e_SUCCESS = 0, e_ENTRY_SIZEMISMATCH = 1, e_TAG_TOOLONG, e_TAG_SIZEMISMATCH};
+static enum e_ecread_errors ecread_tagfile_entry_and_tag
+ (int fd, struct tagfile_entry *tfe, char* buf, int bufsz)
+{
+ long tag_length;
+ str_setlen(buf, 0);
+ if (ecread_tagfile_entry(fd, tfe)!= sizeof(struct tagfile_entry))
+ {
+ return e_ENTRY_SIZEMISMATCH;
+ }
+ tag_length = tfe->tag_length;
+ if (tag_length >= bufsz)
+ return e_TAG_TOOLONG;
+
+ if (read(fd, buf, tag_length) != tag_length)
+ return e_TAG_SIZEMISMATCH;
+
+ str_setlen(buf, tag_length);
+ return e_SUCCESS;
+}
+
static ssize_t ecread_index_entry(int fd, struct index_entry *buf)
{
return ecread(fd, buf, 1, index_entry_ec, tc_stat.econ);
@@ -363,13 +395,14 @@ static int open_tag_fd(struct tagcache_header *hdr, int tag, bool write)
{
int fd;
char buf[MAX_PATH];
+ const int bufsz = sizeof(buf);
int rc;
-
+
if (TAGCACHE_IS_NUMERIC(tag) || tag < 0 || tag >= TAG_COUNT)
return -1;
-
- snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tag);
-
+
+ snprintf(buf, bufsz, TAGCACHE_FILE_INDEX, tag);
+
fd = open(buf, write ? O_RDWR : O_RDONLY);
if (fd < 0)
{
@@ -377,7 +410,7 @@ static int open_tag_fd(struct tagcache_header *hdr, int tag, bool write)
tc_stat.ready = false;
return fd;
}
-
+
/* Check the header. */
rc = ecread(fd, hdr, 1, tagcache_header_ec, tc_stat.econ);
if (hdr->magic != TAGCACHE_MAGIC || rc != sizeof(struct tagcache_header))
@@ -395,7 +428,7 @@ static int open_master_fd(struct master_header *hdr, bool write)
{
int fd;
int rc;
-
+
fd = open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY);
if (fd < 0)
{
@@ -403,9 +436,9 @@ static int open_master_fd(struct master_header *hdr, bool write)
tc_stat.ready = false;
return fd;
}
-
+
tc_stat.econ = false;
-
+
/* Check the header. */
rc = read(fd, hdr, sizeof(struct master_header));
if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header))
@@ -413,10 +446,10 @@ static int open_master_fd(struct master_header *hdr, bool write)
/* Success. */
return fd;
}
-
+
/* Trying to read again, this time with endianess correction enabled. */
lseek(fd, 0, SEEK_SET);
-
+
rc = ecread(fd, hdr, 1, master_header_ec, true);
if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header))
{
@@ -427,7 +460,7 @@ static int open_master_fd(struct master_header *hdr, bool write)
}
tc_stat.econ = true;
-
+
return fd;
}
@@ -453,7 +486,7 @@ static long find_entry_ram(const char *filename)
{
static long last_pos = 0;
struct dircache_fileref dcfref;
-
+
/* Check if tagcache is loaded into ram. */
if (!tc_stat.ramcache)
return -1;
@@ -507,7 +540,8 @@ static long find_entry_disk(const char *filename_raw, bool localfd)
bool found = false;
struct tagfile_entry tfe;
int fd;
- char buf[TAG_MAXLEN+32];
+ char buf[TAGCACHE_BUFSZ];
+ const long bufsz = sizeof(buf);
int i;
int pos = -1;
@@ -520,7 +554,7 @@ static long find_entry_disk(const char *filename_raw, bool localfd)
if (!tc_stat.ready)
return -2;
-
+
fd = filenametag_fd;
if (fd < 0 || localfd)
{
@@ -528,9 +562,9 @@ static long find_entry_disk(const char *filename_raw, bool localfd)
if ( (fd = open_tag_fd(&tch, tag_filename, false)) < 0)
return -1;
}
-
+
check_again:
-
+
if (last_pos > 0)
lseek(fd, last_pos, SEEK_SET);
else
@@ -543,43 +577,45 @@ static long find_entry_disk(const char *filename_raw, bool localfd)
pos_history[i+1] = pos_history[i];
pos_history[0] = pos;
- if (ecread_tagfile_entry(fd, &tfe)
- != sizeof(struct tagfile_entry))
- {
- break ;
- }
-
- if (tfe.tag_length >= (long)sizeof(buf))
- {
- logf("too long tag #1");
- close(fd);
- if (!localfd)
- filenametag_fd = -1;
- last_pos = -1;
- return -2;
- }
-
- if (read(fd, buf, tfe.tag_length) != tfe.tag_length)
+ int res = ecread_tagfile_entry_and_tag(fd, &tfe, buf, bufsz);
+ if (res == e_SUCCESS)
+ {;;}
+ else if (res == e_ENTRY_SIZEMISMATCH)
+ break;
+ else
{
- logf("read error #2");
- close(fd);
- if (!localfd)
- filenametag_fd = -1;
- last_pos = -1;
- return -3;
+ switch (res)
+ {
+ case e_TAG_TOOLONG:
+ logf("too long tag #1");
+ close(fd);
+ if (!localfd)
+ filenametag_fd = -1;
+ last_pos = -1;
+ return -2;
+ case e_TAG_SIZEMISMATCH:
+ logf("read error #2");
+ close(fd);
+ if (!localfd)
+ filenametag_fd = -1;
+ last_pos = -1;
+ return -3;
+ default:
+ break;
+ }
}
-
+
if (!strcmp(filename, buf))
{
last_pos = pos_history[pos_history_idx];
found = true;
break ;
}
-
+
if (pos_history_idx < POS_HISTORY_COUNT - 1)
pos_history_idx++;
}
-
+
/* Not found? */
if (!found)
{
@@ -589,63 +625,63 @@ static long find_entry_disk(const char *filename_raw, bool localfd)
logf("seek again");
goto check_again;
}
-
+
if (fd != filenametag_fd || localfd)
close(fd);
return -4;
}
-
+
if (fd != filenametag_fd || localfd)
close(fd);
-
+
return tfe.idx_id;
}
static int find_index(const char *filename)
{
long idx_id = -1;
-
+
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
idx_id = find_entry_ram(filename);
#endif
-
+
if (idx_id < 0)
idx_id = find_entry_disk(filename, true);
-
+
return idx_id;
}
bool tagcache_find_index(struct tagcache_search *tcs, const char *filename)
{
int idx_id;
-
+
if (!tc_stat.ready)
return false;
-
+
idx_id = find_index(filename);
if (idx_id < 0)
return false;
-
+
if (!tagcache_search(tcs, tag_filename))
return false;
-
+
tcs->entry_count = 0;
tcs->idx_id = idx_id;
-
+
return true;
}
-static bool get_index(int masterfd, int idxid,
+static bool get_index(int masterfd, int idxid,
struct index_entry *idx, bool use_ram)
{
bool localfd = false;
-
+
if (idxid < 0)
{
logf("Incorrect idxid: %d", idxid);
return false;
}
-
+
#ifdef HAVE_TC_RAMCACHE
if (tc_stat.ramcache && use_ram)
{
@@ -656,35 +692,35 @@ static bool get_index(int masterfd, int idxid,
return true;
}
#endif /* HAVE_TC_RAMCACHE */
-
+
if (masterfd < 0)
{
struct master_header tcmh;
-
+
localfd = true;
masterfd = open_master_fd(&tcmh, false);
if (masterfd < 0)
return false;
}
-
- lseek(masterfd, idxid * sizeof(struct index_entry)
+
+ lseek(masterfd, idxid * sizeof(struct index_entry)
+ sizeof(struct master_header), SEEK_SET);
- if (ecread_index_entry(masterfd, idx)
+ if (ecread_index_entry(masterfd, idx)
!= sizeof(struct index_entry))
{
logf("read error #3");
if (localfd)
close(masterfd);
-
+
return false;
}
-
+
if (localfd)
close(masterfd);
-
+
if (idx->flag & FLAG_DELETED)
return false;
-
+
return true;
(void)use_ram;
@@ -700,7 +736,7 @@ static bool write_index(int masterfd, int idxid, struct index_entry *idx)
logf("memory only flags!");
return false;
}
-
+
#ifdef HAVE_TC_RAMCACHE
/* Only update numeric data. Writing the whole index to RAM by memcpy
* destroys dircache pointers!
@@ -708,7 +744,7 @@ static bool write_index(int masterfd, int idxid, struct index_entry *idx)
if (tc_stat.ramcache)
{
struct index_entry *idx_ram = &tcramcache.hdr->indices[idxid];
-
+
for (int tag = 0; tag < TAG_COUNT; tag++)
{
if (TAGCACHE_IS_NUMERIC(tag))
@@ -716,14 +752,14 @@ static bool write_index(int masterfd, int idxid, struct index_entry *idx)
idx_ram->tag_seek[tag] = idx->tag_seek[tag];
}
}
-
+
/* Don't touch the dircache flag or attributes. */
- idx_ram->flag = (idx->flag & 0x0000ffff)
+ idx_ram->flag = (idx->flag & 0x0000ffff)
| (idx_ram->flag & (0xffff0000 | FLAG_DIRCACHE));
}
#endif /* HAVE_TC_RAMCACHE */
-
- lseek(masterfd, idxid * sizeof(struct index_entry)
+
+ lseek(masterfd, idxid * sizeof(struct index_entry)
+ sizeof(struct master_header), SEEK_SET);
if (ecwrite_index_entry(masterfd, idx) != sizeof(struct index_entry))
{
@@ -731,7 +767,7 @@ static bool write_index(int masterfd, int idxid, struct index_entry *idx)
logf("idxid: %d", idxid);
return false;
}
-
+
return true;
}
@@ -746,41 +782,41 @@ static bool open_files(struct tagcache_search *tcs, int tag)
snprintf(fn, sizeof fn, TAGCACHE_FILE_INDEX, tag);
tcs->idxfd[tag] = open(fn, O_RDONLY);
}
-
+
if (tcs->idxfd[tag] < 0)
{
logf("File not open!");
return false;
}
-
+
return true;
}
static bool retrieve(struct tagcache_search *tcs, IF_DIRCACHE(int idx_id,)
- struct index_entry *idx, int tag, char *buf, long size)
+ struct index_entry *idx, int tag, char *buf, long bufsz)
{
struct tagfile_entry tfe;
long seek;
-
- *buf = '\0';
-
+
+ str_setlen(buf, 0);
+
if (TAGCACHE_IS_NUMERIC(tag))
return false;
-
+
seek = idx->tag_seek[tag];
if (seek < 0)
{
logf("Retrieve failed");
return false;
}
-
+
#ifdef HAVE_TC_RAMCACHE
if (tcs->ramsearch)
{
#ifdef HAVE_DIRCACHE
if (tag == tag_filename && (idx->flag & FLAG_DIRCACHE))
{
- if (dircache_get_fileref_path(&tcrc_dcfrefs[idx_id], buf, size) >= 0)
+ if (dircache_get_fileref_path(&tcrc_dcfrefs[idx_id], buf, bufsz) >= 0)
return true;
}
else
@@ -789,38 +825,34 @@ static bool retrieve(struct tagcache_search *tcs, IF_DIRCACHE(int idx_id,)
{
struct tagfile_entry *ep =
(struct tagfile_entry *)&tcramcache.hdr->tags[tag][seek];
- strlcpy(buf, ep->tag_data, size);
-
+ strlcpy(buf, ep->tag_data, bufsz);
+
return true;
}
}
#endif /* HAVE_TC_RAMCACHE */
-
+
if (!open_files(tcs, tag))
return false;
-
+
lseek(tcs->idxfd[tag], seek, SEEK_SET);
- if (ecread_tagfile_entry(tcs->idxfd[tag], &tfe)
- != sizeof(struct tagfile_entry))
- {
- logf("read error #5");
- return false;
- }
-
- if (tfe.tag_length >= size)
+ switch (ecread_tagfile_entry_and_tag(tcs->idxfd[tag], &tfe, buf, bufsz))
{
- logf("too small buffer");
- return false;
- }
-
- if (read(tcs->idxfd[tag], buf, tfe.tag_length) !=
- tfe.tag_length)
- {
- logf("read error #6");
- return false;
+ case e_SUCCESS:
+ break;
+ case e_ENTRY_SIZEMISMATCH:
+ logf("read error #5");
+ return false;
+ case e_TAG_TOOLONG:
+ logf("too long tag #5");
+ return false;
+ case e_TAG_SIZEMISMATCH:
+ logf("read error #6");
+ return false;
+ default:
+ logf("unknown_error");
+ break;;
}
-
- buf[tfe.tag_length] = '\0';
return true;
}
@@ -844,7 +876,7 @@ static long find_tag(int tag, int idx_id, const struct index_entry *idx)
{
if (--ridx < 0)
ridx = TAGCACHE_COMMAND_QUEUE_LENGTH - 1;
-
+
if (command_queue[ridx].command == CMD_UPDATE_NUMERIC
&& command_queue[ridx].idx_id == idx_id
&& command_queue[ridx].tag == tag)
@@ -871,32 +903,41 @@ static long find_tag(int tag, int idx_id, const struct index_entry *idx)
return idx->tag_seek[tag];
}
+static inline long sec_in_ms(long ms)
+{
+ return (ms/1000) % 60;
+}
-static long check_virtual_tags(int tag, int idx_id,
+static inline long min_in_ms(long ms)
+{
+ return (ms/1000) / 60;
+}
+
+static long check_virtual_tags(int tag, int idx_id,
const struct index_entry *idx)
{
long data = 0;
-
- switch (tag)
+
+ switch (tag)
{
case tag_virt_length_sec:
- data = (find_tag(tag_length, idx_id, idx)/1000) % 60;
+ data = sec_in_ms(find_tag(tag_length, idx_id, idx));
break;
-
+
case tag_virt_length_min:
- data = (find_tag(tag_length, idx_id, idx)/1000) / 60;
+ data = min_in_ms(find_tag(tag_length, idx_id, idx));
break;
-
+
case tag_virt_playtime_sec:
- data = (find_tag(tag_playtime, idx_id, idx)/1000) % 60;
+ data = sec_in_ms(find_tag(tag_playtime, idx_id, idx));
break;
-
+
case tag_virt_playtime_min:
- data = (find_tag(tag_playtime, idx_id, idx)/1000) / 60;
+ data = min_in_ms(find_tag(tag_playtime, idx_id, idx));
break;
-
+
case tag_virt_autoscore:
- if (find_tag(tag_length, idx_id, idx) == 0
+ if (find_tag(tag_length, idx_id, idx) == 0
|| find_tag(tag_playcount, idx_id, idx) == 0)
{
data = 0;
@@ -913,21 +954,20 @@ static long check_virtual_tags(int tag, int idx_id,
autoscore = 100 * (alpha / playcout + beta / length / playcount)
Both terms should be small enough to avoid any overflow
*/
- data = 100 * (find_tag(tag_playtime, idx_id, idx)
- / find_tag(tag_length, idx_id, idx))
- + (100 * (find_tag(tag_playtime, idx_id, idx)
- % find_tag(tag_length, idx_id, idx)))
- / find_tag(tag_length, idx_id, idx);
- data /= find_tag(tag_playcount, idx_id, idx);
+ long playtime = find_tag(tag_playtime, idx_id, idx);
+ long length = find_tag(tag_length, idx_id, idx);
+ long playcount = find_tag(tag_playcount, idx_id, idx);
+ data = 100 * (playtime / length) + (100 * (playtime % length)) / length;
+ data /= playcount;
}
break;
-
+
/* How many commits before the file has been added to the DB. */
case tag_virt_entryage:
- data = current_tcmh.commitid
+ data = current_tcmh.commitid
- find_tag(tag_commitid, idx_id, idx) - 1;
break;
-
+
case tag_virt_basename:
tag = tag_filename; /* return filename; caller handles basename */
/* FALLTHRU */
@@ -935,23 +975,23 @@ static long check_virtual_tags(int tag, int idx_id,
default:
data = find_tag(tag, idx_id, idx);
}
-
+
return data;
}
long tagcache_get_numeric(const struct tagcache_search *tcs, int tag)
{
struct index_entry idx;
-
+
if (!tc_stat.ready)
return false;
-
+
if (!TAGCACHE_IS_NUMERIC(tag))
return -1;
-
+
if (!get_index(tcs->masterfd, tcs->idx_id, &idx, true))
return -2;
-
+
return check_virtual_tags(tag, tcs->idx_id, &idx);
}
@@ -959,10 +999,10 @@ inline static bool str_ends_with(const char *str1, const char *str2)
{
int str_len = strlen(str1);
int clause_len = strlen(str2);
-
+
if (clause_len > str_len)
return false;
-
+
return !strcasecmp(&str1[str_len - clause_len], str2);
}
@@ -970,7 +1010,7 @@ inline static bool str_oneof(const char *str, const char *list)
{
const char *sep;
int l, len = strlen(str);
-
+
while (*list)
{
sep = strchr(list, '|');
@@ -1001,7 +1041,7 @@ static bool check_against_clause(long numeric, const char *str,
case clause_lt:
return numeric < clause->numeric_data;
case clause_lteq:
- return numeric <= clause->numeric_data;
+ return numeric <= clause->numeric_data;
default:
logf("Incorrect numeric tag: %d", clause->type);
}
@@ -1036,7 +1076,7 @@ static bool check_against_clause(long numeric, const char *str,
return !str_ends_with(str, clause->str);
case clause_oneof:
return str_oneof(str, clause->str);
-
+
default:
logf("Incorrect tag: %d", clause->type);
}
@@ -1050,15 +1090,16 @@ static bool check_clauses(struct tagcache_search *tcs,
struct tagcache_search_clause **clauses, int count)
{
int i;
-
+
/* Go through all conditional clauses. */
for (i = 0; i < count; i++)
{
int seek;
char buf[256];
+ const int bufsz = sizeof(buf);
char *str = buf;
struct tagcache_search_clause *clause = clauses[i];
-
+
if (clause->type == clause_logical_or)
break; /* all conditions before logical-or satisfied --
stop processing clauses */
@@ -1069,14 +1110,14 @@ static bool check_clauses(struct tagcache_search *tcs,
if (tcs->ramsearch)
{
struct tagfile_entry *tfe;
-
+
if (!TAGCACHE_IS_NUMERIC(clause->tag))
{
if (clause->tag == tag_filename
|| clause->tag == tag_virt_basename)
{
retrieve(tcs, IF_DIRCACHE(tcs->idx_id,) idx, tag_filename,
- buf, sizeof buf);
+ buf, bufsz);
}
else
{
@@ -1092,7 +1133,7 @@ static bool check_clauses(struct tagcache_search *tcs,
#endif /* HAVE_TC_RAMCACHE */
{
struct tagfile_entry tfe;
-
+
if (!TAGCACHE_IS_NUMERIC(clause->tag))
{
int tag = clause->tag;
@@ -1101,16 +1142,25 @@ static bool check_clauses(struct tagcache_search *tcs,
int fd = tcs->idxfd[tag];
lseek(fd, seek, SEEK_SET);
- ecread_tagfile_entry(fd, &tfe);
- if (tfe.tag_length >= (int)sizeof(buf))
+
+ switch (ecread_tagfile_entry_and_tag(fd, &tfe, str, bufsz))
{
- logf("Too long tag read!");
- return false;
+ case e_SUCCESS:
+ break;
+ case e_ENTRY_SIZEMISMATCH:
+ logf("read error #15");
+ return false;
+ case e_TAG_TOOLONG:
+ logf("too long tag #6");
+ return false;
+ case e_TAG_SIZEMISMATCH:
+ logf("read error #16");
+ return false;
+ default:
+ logf("unknown_error");
+ break;;
}
-
- read(fd, str, tfe.tag_length);
- str[tfe.tag_length] = '\0';
-
+
/* Check if entry has been deleted. */
if (str[0] == '\0')
return false;
@@ -1132,14 +1182,14 @@ static bool check_clauses(struct tagcache_search *tcs,
if (clauses[i]->type == clause_logical_or)
break;
}
-
+
if (i < count) /* Found logical-or? */
continue; /* Check clauses after logical-or */
return false;
}
}
-
+
return true;
}
@@ -1147,40 +1197,40 @@ bool tagcache_check_clauses(struct tagcache_search *tcs,
struct tagcache_search_clause **clause, int count)
{
struct index_entry idx;
-
+
if (count == 0)
return true;
-
+
if (!get_index(tcs->masterfd, tcs->idx_id, &idx, true))
return false;
-
+
return check_clauses(tcs, &idx, clause, count);
}
static bool add_uniqbuf(struct tagcache_search *tcs, unsigned long id)
{
int i;
-
+
/* If uniq buffer is not defined we must return true for search to work. */
if (tcs->unique_list == NULL || (!TAGCACHE_IS_UNIQUE(tcs->type)
&& !TAGCACHE_IS_NUMERIC(tcs->type)))
{
return true;
}
-
+
for (i = 0; i < tcs->unique_list_count; i++)
{
/* Return false if entry is found. */
if (tcs->unique_list[i] == id)
return false;
}
-
+
if (tcs->unique_list_count < tcs->unique_list_capacity)
{
tcs->unique_list[i] = id;
tcs->unique_list_count++;
}
-
+
return true;
}
@@ -1188,9 +1238,9 @@ static bool build_lookup_list(struct tagcache_search *tcs)
{
struct index_entry entry;
int i, j;
-
+
tcs->seek_list_count = 0;
-
+
#ifdef HAVE_TC_RAMCACHE
if (tcs->ramsearch)
{
@@ -1203,11 +1253,11 @@ static bool build_lookup_list(struct tagcache_search *tcs)
struct index_entry *idx = &tcramcache.hdr->indices[i];
if (tcs->seek_list_count == SEEK_LIST_SIZE)
break ;
-
+
/* Skip deleted files. */
if (idx->flag & FLAG_DELETED)
continue;
-
+
/* Go through all filters.. */
for (j = 0; j < tcs->filter_count; j++)
{
@@ -1216,7 +1266,7 @@ static bool build_lookup_list(struct tagcache_search *tcs)
break ;
}
}
-
+
if (j < tcs->filter_count)
continue ;
@@ -1226,7 +1276,7 @@ static bool build_lookup_list(struct tagcache_search *tcs)
/* Add to the seek list if not already in uniq buffer (doesn't yield)*/
if (!add_uniqbuf(tcs, idx->tag_seek[tcs->type]))
continue;
-
+
/* Lets add it. */
seeklist = &tcs->seeklist[tcs->seek_list_count];
seeklist->seek = idx->tag_seek[tcs->type];
@@ -1238,71 +1288,72 @@ static bool build_lookup_list(struct tagcache_search *tcs)
tcrc_buffer_unlock();
tcs->seek_pos = i;
-
+
return tcs->seek_list_count > 0;
}
#endif /* HAVE_TC_RAMCACHE */
-
+
if (tcs->masterfd < 0)
{
struct master_header tcmh;
tcs->masterfd = open_master_fd(&tcmh, false);
}
-
+
lseek(tcs->masterfd, tcs->seek_pos * sizeof(struct index_entry) +
sizeof(struct master_header), SEEK_SET);
-
- while (ecread_index_entry(tcs->masterfd, &entry)
+
+ while (ecread_index_entry(tcs->masterfd, &entry)
== sizeof(struct index_entry))
{
struct tagcache_seeklist_entry *seeklist;
-
+
if (tcs->seek_list_count == SEEK_LIST_SIZE)
break ;
-
+
i = tcs->seek_pos;
tcs->seek_pos++;
-
+
/* Check if entry has been deleted. */
if (entry.flag & FLAG_DELETED)
continue;
-
+
/* Go through all filters.. */
for (j = 0; j < tcs->filter_count; j++)
{
if (entry.tag_seek[tcs->filter_tag[j]] != tcs->filter_seek[j])
break ;
}
-
+
if (j < tcs->filter_count)
continue ;
-
+
/* Check for conditions. */
if (!check_clauses(tcs, &entry, tcs->clause, tcs->clause_count))
continue;
-
+
/* Add to the seek list if not already in uniq buffer. */
if (!add_uniqbuf(tcs, entry.tag_seek[tcs->type]))
continue;
-
+
/* Lets add it. */
seeklist = &tcs->seeklist[tcs->seek_list_count];
seeklist->seek = entry.tag_seek[tcs->type];
seeklist->flag = entry.flag;
seeklist->idx_id = i;
tcs->seek_list_count++;
-
+
yield();
}
return tcs->seek_list_count > 0;
}
-
+
static void remove_files(void)
{
int i;
char buf[MAX_PATH];
+ const int bufsz = sizeof(buf);
tc_stat.ready = false;
tc_stat.ramcache = false;
@@ -1312,8 +1363,8 @@ static void remove_files(void)
{
if (TAGCACHE_IS_NUMERIC(i))
continue;
-
- snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, i);
+
+ snprintf(buf, bufsz, TAGCACHE_FILE_INDEX, i);
remove(buf);
}
}
@@ -1325,30 +1376,30 @@ static bool check_all_headers(void)
struct tagcache_header tch;
int tag;
int fd;
-
+
if ( (fd = open_master_fd(&myhdr, false)) < 0)
return false;
-
+
close(fd);
if (myhdr.dirty)
{
logf("tagcache is dirty!");
return false;
}
-
+
memcpy(&current_tcmh, &myhdr, sizeof(struct master_header));
-
+
for (tag = 0; tag < TAG_COUNT; tag++)
{
if (TAGCACHE_IS_NUMERIC(tag))
continue;
-
+
if ( (fd = open_tag_fd(&tch, tag, false)) < 0)
return false;
-
+
close(fd);
}
-
+
return true;
}
@@ -1360,11 +1411,11 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
while (read_lock)
sleep(1);
-
+
memset(tcs, 0, sizeof(struct tagcache_search));
if (tc_stat.commit_step > 0 || !tc_stat.ready)
return false;
-
+
tcs->position = sizeof(struct tagcache_header);
tcs->type = tag;
tcs->seek_pos = 0;
@@ -1392,13 +1443,13 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
tcs->masterfd = open_master_fd(&master_hdr, true);
if (tcs->masterfd < 0)
return false;
-
+
if (!TAGCACHE_IS_NUMERIC(tcs->type))
{
tcs->idxfd[tcs->type] = open_tag_fd(&tag_hdr, tcs->type, false);
if (tcs->idxfd[tcs->type] < 0)
return false;
-
+
tcs->entry_count = tag_hdr.entry_count;
}
else
@@ -1410,7 +1461,7 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
tcs->valid = true;
tcs->initialized = true;
write_lock++;
-
+
return true;
}
@@ -1430,7 +1481,7 @@ bool tagcache_search_add_filter(struct tagcache_search *tcs,
if (TAGCACHE_IS_NUMERIC_OR_NONUNIQUE(tag))
return false;
-
+
tcs->filter_tag[tcs->filter_count] = tag;
tcs->filter_seek[tcs->filter_count] = seek;
tcs->filter_count++;
@@ -1442,7 +1493,7 @@ bool tagcache_search_add_clause(struct tagcache_search *tcs,
struct tagcache_search_clause *clause)
{
int i;
-
+
if (tcs->clause_count >= TAGCACHE_MAX_CLAUSES)
{
logf("Too many clauses");
@@ -1452,32 +1503,35 @@ bool tagcache_search_add_clause(struct tagcache_search *tcs,
if (clause->type != clause_logical_or)
{
/* Check if there is already a similar filter in present (filters are
- * much faster than clauses).
+ * much faster than clauses).
*/
for (i = 0; i < tcs->filter_count; i++)
{
if (tcs->filter_tag[i] == clause->tag)
return true;
}
-
+
if (!TAGCACHE_IS_NUMERIC(clause->tag) && tcs->idxfd[clause->tag] < 0)
{
char buf[MAX_PATH];
+ const int bufsz = sizeof(buf);
- snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, clause->tag);
+ snprintf(buf, bufsz, TAGCACHE_FILE_INDEX, clause->tag);
tcs->idxfd[clause->tag] = open(buf, O_RDONLY);
}
}
-
+
tcs->clause[tcs->clause_count] = clause;
tcs->clause_count++;
-
+
return true;
}
static bool get_next(struct tagcache_search *tcs)
{
- static char buf[TAG_MAXLEN+32];
+ /* WARNING pointers into buf are used in outside functions */
+ static char buf[TAGCACHE_BUFSZ];
+ const int bufsz = sizeof(buf);
struct tagfile_entry entry;
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
long flag = 0;
@@ -1485,14 +1539,14 @@ static bool get_next(struct tagcache_search *tcs)
if (!tcs->valid || !tc_stat.ready)
return false;
-
+
if (tcs->idxfd[tcs->type] < 0 && !TAGCACHE_IS_NUMERIC(tcs->type)
#ifdef HAVE_TC_RAMCACHE
&& !tcs->ramsearch
#endif
)
return false;
-
+
/* Relative fetch. */
if (tcs->filter_count > 0 || tcs->clause_count > 0
|| TAGCACHE_IS_NUMERIC(tcs->type)
@@ -1503,12 +1557,12 @@ static bool get_next(struct tagcache_search *tcs)
)
{
struct tagcache_seeklist_entry *seeklist;
-
+
/* Check for end of list. */
if (tcs->list_position == tcs->seek_list_count)
{
tcs->list_position = 0;
-
+
/* Try to fetch more. */
if (!build_lookup_list(tcs))
{
@@ -1516,7 +1570,7 @@ static bool get_next(struct tagcache_search *tcs)
return false;
}
}
-
+
seeklist = &tcs->seeklist[tcs->list_position];
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
flag = seeklist->flag;
@@ -1532,20 +1586,20 @@ static bool get_next(struct tagcache_search *tcs)
tcs->valid = false;
return false;
}
-
+
tcs->entry_count--;
}
-
+
tcs->result_seek = tcs->position;
-
+
if (TAGCACHE_IS_NUMERIC(tcs->type))
{
- snprintf(buf, sizeof(buf), "%ld", tcs->position);
+ snprintf(buf, bufsz, "%ld", tcs->position);
tcs->result = buf;
tcs->result_len = strlen(buf) + 1;
return true;
}
-
+
/* Direct fetch. */
#ifdef HAVE_TC_RAMCACHE
if (tcs->ramsearch)
@@ -1569,58 +1623,60 @@ static bool get_next(struct tagcache_search *tcs)
if (tcs->type != tag_filename)
{
struct tagfile_entry *ep;
-
+
ep = (struct tagfile_entry *)&tcramcache.hdr->tags[tcs->type][tcs->position];
/* don't return ep->tag_data directly as it may move */
tcs->result_len = strlcpy(buf, ep->tag_data, sizeof(buf)) + 1;
tcs->result = buf;
tcs->idx_id = ep->idx_id;
tcs->ramresult = false; /* was true before we copied to buf too */
-
+
/* Increase position for the next run. This may get overwritten. */
tcs->position += sizeof(struct tagfile_entry) + ep->tag_length;
-
+
return true;
}
}
#endif /* HAVE_TC_RAMCACHE */
-
+
if (!open_files(tcs, tcs->type))
{
tcs->valid = false;
return false;
}
-
+
/* Seek stream to the correct position and continue to direct fetch. */
lseek(tcs->idxfd[tcs->type], tcs->position, SEEK_SET);
-
- if (ecread_tagfile_entry(tcs->idxfd[tcs->type], &entry) != sizeof(struct tagfile_entry))
- {
- logf("read error #5");
- tcs->valid = false;
- return false;
- }
-
- if (entry.tag_length > (long)sizeof(buf))
- {
- tcs->valid = false;
- logf("too long tag #2");
- logf("P:%lX/%lX", tcs->position, entry.tag_length);
- return false;
- }
-
- if (read(tcs->idxfd[tcs->type], buf, entry.tag_length) != entry.tag_length)
+
+ switch (ecread_tagfile_entry_and_tag(tcs->idxfd[tcs->type], &entry, buf, bufsz))
{
- tcs->valid = false;
- logf("read error #4");
- return false;
+ case e_SUCCESS:
+ break;
+ case e_ENTRY_SIZEMISMATCH:
+ logf("read error #5");
+ tcs->valid = false;
+ return false;
+ case e_TAG_TOOLONG:
+ tcs->valid = false;
+ logf("too long tag #2");
+ logf("P:%lX/%lX", tcs->position, entry.tag_length);
+ return false;
+ case e_TAG_SIZEMISMATCH:
+ tcs->valid = false;
+ logf("read error #4");
+ return false;
+ default:
+ logf("unknown_error");
+ break;;
}
-
+
/**
Update the position for the next read (this may be overridden
if filters or clauses are being used).
*/
tcs->position += sizeof(struct tagfile_entry) + entry.tag_length;
+ str_setlen(buf, entry.tag_length);
+
tcs->result = buf;
tcs->result_len = strlen(tcs->result) + 1;
tcs->idx_id = entry.idx_id;
@@ -1636,19 +1692,19 @@ bool tagcache_get_next(struct tagcache_search *tcs)
if (tcs->result_len > 1)
return true;
}
-
+
return false;
}
-bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
+bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
int tag, char *buf, long size)
{
struct index_entry idx;
-
+
*buf = '\0';
if (!get_index(tcs->masterfd, idxid, &idx, true))
return false;
-
+
return retrieve(tcs, IF_DIRCACHE(idxid,) &idx, tag, buf, size);
}
@@ -1656,32 +1712,32 @@ static bool update_master_header(void)
{
struct master_header myhdr;
int fd;
-
+
if (!tc_stat.ready)
return false;
-
+
if ( (fd = open_master_fd(&myhdr, true)) < 0)
return false;
-
+
myhdr.serial = current_tcmh.serial;
myhdr.commitid = current_tcmh.commitid;
myhdr.dirty = current_tcmh.dirty;
-
+
/* Write it back */
lseek(fd, 0, SEEK_SET);
ecwrite(fd, &myhdr, 1, master_header_ec, tc_stat.econ);
close(fd);
-
+
return true;
}
void tagcache_search_finish(struct tagcache_search *tcs)
{
int i;
-
+
if (!tcs->initialized)
return;
-
+
if (tcs->masterfd >= 0)
{
close(tcs->masterfd);
@@ -1696,7 +1752,7 @@ void tagcache_search_finish(struct tagcache_search *tcs)
tcs->idxfd[i] = -1;
}
}
-
+
tcs->ramsearch = false;
tcs->valid = false;
tcs->initialized = 0;
@@ -1725,17 +1781,17 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
{
struct index_entry *entry;
int idx_id;
-
+
if (!tc_stat.ready || !tc_stat.ramcache)
return false;
-
+
/* Find the corresponding entry in tagcache. */
idx_id = find_entry_ram(filename);
if (idx_id < 0)
return false;
-
+
entry = &tcramcache.hdr->indices[idx_id];
-
+
memset(id3, 0, sizeof(struct mp3entry));
char* buf = id3->id3v2buf;
ssize_t remaining = sizeof(id3->id3v2buf);
@@ -1755,8 +1811,8 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
} \
} \
} while(0)
-
-
+
+
SET(id3->title, tag_title);
SET(id3->artist, tag_artist);
SET(id3->album, tag_album);
@@ -1786,7 +1842,7 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
id3->title, id3->elapsed);
id3->offset = get_tag_numeric(entry, tag_lastoffset, idx_id);
- logf("tagcache_fill_tags: Set offset for %s to %lX\n",
+ logf("tagcache_fill_tags: Set offset for %s to %lX\n",
id3->title, id3->offset);
}
@@ -1817,7 +1873,7 @@ static int check_if_empty(char **tag)
{
logf("over length tag: %s", *tag);
length = TAG_MAXLEN;
- (*tag)[length] = '\0';
+ str_setlen((*tag), length);
}
return length + 1;
@@ -1831,8 +1887,8 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
{
#define ADD_TAG(entry, tag, data) \
/* Adding tag */ \
- entry.tag_offset[tag] = offset; \
entry.tag_length[tag] = check_if_empty(data); \
+ entry.tag_offset[tag] = offset; \
offset += entry.tag_length[tag]
struct mp3entry id3;
@@ -1843,7 +1899,7 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
char tracknumfix[3];
int offset = 0;
int path_length = strlen(path);
- bool has_albumartist;
+ bool has_artist;
bool has_grouping;
#ifdef SIMULATOR
@@ -1868,11 +1924,11 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
logf("Too long path: %s", path);
return ;
}
-
+
/* Check if the file is supported. */
if (probe_file_format(path) == AFMT_UNKNOWN)
return ;
-
+
/* Check if the file is already cached. */
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
idx_id = find_entry_ram(path);
@@ -1881,27 +1937,27 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
/* Be sure the entry doesn't exist. */
if (filenametag_fd >= 0 && idx_id < 0)
idx_id = find_entry_disk(path, false);
-
+
/* Check if file has been modified. */
if (idx_id >= 0)
{
struct index_entry idx;
-
+
/* TODO: Mark that the index exists (for fast reverse scan) */
//found_idx[idx_id/8] |= idx_id%8;
-
+
if (!get_index(-1, idx_id, &idx, true))
{
logf("failed to retrieve index entry");
return ;
}
-
+
if ((unsigned long)idx.tag_seek[tag_mtime] == mtime)
{
/* No changes to file. */
return ;
}
-
+
/* Metadata might have been changed. Delete the entry. */
logf("Re-adding: %s", path);
if (!delete_entry(idx_id))
@@ -1910,7 +1966,7 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
return ;
}
}
-
+
fd = open(path, O_RDONLY);
if (fd < 0)
{
@@ -1928,12 +1984,12 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
return ;
logf("-> %s", path);
-
+
if (id3.tracknum <= 0) /* Track number missing? */
{
id3.tracknum = -1;
}
-
+
/* Numeric tags */
entry.tag_offset[tag_year] = id3.year;
entry.tag_offset[tag_discnumber] = id3.discnum;
@@ -1941,10 +1997,10 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
entry.tag_offset[tag_length] = id3.length;
entry.tag_offset[tag_bitrate] = id3.bitrate;
entry.tag_offset[tag_mtime] = mtime;
-
+
/* String tags. */
- has_albumartist = id3.albumartist != NULL
- && strlen(id3.albumartist) > 0;
+ has_artist = id3.artist != NULL
+ && strlen(id3.artist) > 0;
has_grouping = id3.grouping != NULL
&& strlen(id3.grouping) > 0;
@@ -1955,13 +2011,14 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
ADD_TAG(entry, tag_genre, &id3.genre_string);
ADD_TAG(entry, tag_composer, &id3.composer);
ADD_TAG(entry, tag_comment, &id3.comment);
- if (has_albumartist)
+ ADD_TAG(entry, tag_albumartist, &id3.albumartist);
+ if (has_artist)
{
- ADD_TAG(entry, tag_albumartist, &id3.albumartist);
+ ADD_TAG(entry, tag_virt_canonicalartist, &id3.artist);
}
else
{
- ADD_TAG(entry, tag_albumartist, &id3.artist);
+ ADD_TAG(entry, tag_virt_canonicalartist, &id3.albumartist);
}
if (has_grouping)
{
@@ -1972,10 +2029,10 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
ADD_TAG(entry, tag_grouping, &id3.title);
}
entry.data_length = offset;
-
+
/* Write the header */
write(cachefd, &entry, sizeof(struct temp_file_entry));
-
+
/* And tags also... Correct order is critical */
write_item(path);
write_item(id3.title);
@@ -1984,13 +2041,14 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime)
write_item(id3.genre_string);
write_item(id3.composer);
write_item(id3.comment);
- if (has_albumartist)
+ write_item(id3.albumartist);
+ if (has_artist)
{
- write_item(id3.albumartist);
+ write_item(id3.artist);
}
else
{
- write_item(id3.artist);
+ write_item(id3.albumartist);
}
if (has_grouping)
{
@@ -2013,14 +2071,14 @@ static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
int i;
unsigned crc32;
unsigned *crcbuf = (unsigned *)&tempbuf[tempbuf_size-4];
- char buf[TAG_MAXLEN+32];
+ char buf[TAGCACHE_BUFSZ];
+ const int bufsz = sizeof(buf);
- for (i = 0; str[i] != '\0' && i < (int)sizeof(buf)-1; i++)
+ for (i = 0; str[i] != '\0' && i < bufsz-1; i++)
buf[i] = tolower(str[i]);
- buf[i] = '\0';
-
+
crc32 = crc_32(buf, i, 0xffffffff);
-
+
if (unique)
{
/* Check if the crc does not exist -> entry does not exist for sure. */
@@ -2028,7 +2086,7 @@ static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
{
if (crcbuf[-i] != crc32)
continue;
-
+
if (!strcasecmp(str, index[i].str))
{
if (id < 0 || id >= lookup_buffer_depth)
@@ -2036,22 +2094,22 @@ static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
logf("lookup buf overf.: %d", id);
return false;
}
-
+
lookup[id] = &index[i];
return true;
}
}
}
-
+
/* Insert to CRC buffer. */
crcbuf[-tempbufidx] = crc32;
tempbuf_left -= 4;
-
+
/* Insert it to the buffer. */
tempbuf_left -= len;
if (tempbuf_left - 4 < 0 || tempbufidx >= commit_entry_count-1)
return false;
-
+
if (id >= lookup_buffer_depth)
{
logf("lookup buf overf. #2: %d", id);
@@ -2065,7 +2123,7 @@ static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
}
else
index[tempbufidx].idlist.id = -1;
-
+
index[tempbufidx].idlist.next = NULL;
index[tempbufidx].idx_id = idx_id;
index[tempbufidx].seek = -1;
@@ -2073,7 +2131,7 @@ static bool tempbuf_insert(char *str, int id, int idx_id, bool unique)
memcpy(index[tempbufidx].str, str, len);
tempbuf_pos += len;
tempbufidx++;
-
+
return true;
}
@@ -2083,7 +2141,7 @@ static int compare(const void *p1, const void *p2)
struct tempbuf_searchidx *e1 = (struct tempbuf_searchidx *)p1;
struct tempbuf_searchidx *e2 = (struct tempbuf_searchidx *)p2;
-
+
if (strcmp(e1->str, UNTAGGED) == 0)
{
if (strcmp(e2->str, UNTAGGED) == 0)
@@ -2092,7 +2150,7 @@ static int compare(const void *p1, const void *p2)
}
else if (strcmp(e2->str, UNTAGGED) == 0)
return 1;
-
+
return strncasecmp(e1->str, e2->str, TAG_MAXLEN);
}
@@ -2102,26 +2160,26 @@ static int tempbuf_sort(int fd)
struct tagfile_entry fe;
int i;
int length;
-
+
/* Generate reverse lookup entries. */
for (i = 0; i < lookup_buffer_depth; i++)
{
struct tempbuf_id_list *idlist;
-
+
if (!lookup[i])
continue;
-
+
if (lookup[i]->idlist.id == i)
continue;
-
+
idlist = &lookup[i]->idlist;
while (idlist->next != NULL)
idlist = idlist->next;
-
+
tempbuf_left -= sizeof(struct tempbuf_id_list);
if (tempbuf_left - 4 < 0)
return -1;
-
+
idlist->next = (struct tempbuf_id_list *)&tempbuf[tempbuf_pos];
if (tempbuf_pos & 0x03)
{
@@ -2130,21 +2188,21 @@ static int tempbuf_sort(int fd)
idlist->next = (struct tempbuf_id_list *)&tempbuf[tempbuf_pos];
}
tempbuf_pos += sizeof(struct tempbuf_id_list);
-
+
idlist = idlist->next;
idlist->id = i;
idlist->next = NULL;
do_timed_yield();
}
-
+
qsort(index, tempbufidx, sizeof(struct tempbuf_searchidx), compare);
memset(lookup, 0, lookup_buffer_depth * sizeof(struct tempbuf_searchidx **));
-
+
for (i = 0; i < tempbufidx; i++)
{
struct tempbuf_id_list *idlist = &index[i].idlist;
-
+
/* Fix the lookup list. */
while (idlist != NULL)
{
@@ -2152,21 +2210,21 @@ static int tempbuf_sort(int fd)
lookup[idlist->id] = &index[i];
idlist = idlist->next;
}
-
+
index[i].seek = lseek(fd, 0, SEEK_CUR);
length = strlen(index[i].str) + 1;
fe.tag_length = length;
fe.idx_id = index[i].idx_id;
-
+
/* Check the chunk alignment. */
- if ((fe.tag_length + sizeof(struct tagfile_entry))
+ if ((fe.tag_length + sizeof(struct tagfile_entry))
% TAGFILE_ENTRY_CHUNK_LENGTH)
{
- fe.tag_length += TAGFILE_ENTRY_CHUNK_LENGTH -
- ((fe.tag_length + sizeof(struct tagfile_entry))
+ fe.tag_length += TAGFILE_ENTRY_CHUNK_LENGTH -
+ ((fe.tag_length + sizeof(struct tagfile_entry))
% TAGFILE_ENTRY_CHUNK_LENGTH);
}
-
+
#ifdef TAGCACHE_STRICT_ALIGN
/* Make sure the entry is long aligned. */
if (index[i].seek & 0x03)
@@ -2175,20 +2233,20 @@ static int tempbuf_sort(int fd)
return -3;
}
#endif
-
+
if (ecwrite(fd, &fe, 1, tagfile_entry_ec, tc_stat.econ) !=
sizeof(struct tagfile_entry))
{
logf("tempbuf_sort: write error #1");
return -1;
}
-
+
if (write(fd, index[i].str, length) != length)
{
logf("tempbuf_sort: write error #2");
return -2;
}
-
+
/* Write some padding. */
if (fe.tag_length - length > 0)
write(fd, "XXXXXXXX", fe.tag_length - length);
@@ -2196,12 +2254,12 @@ static int tempbuf_sort(int fd)
return i;
}
-
+
inline static struct tempbuf_searchidx* tempbuf_locate(int id)
{
if (id < 0 || id >= lookup_buffer_depth)
return NULL;
-
+
return lookup[id];
}
@@ -2227,16 +2285,18 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
int max_entries;
int entries_processed = 0;
int i, j;
- char buf[TAG_MAXLEN];
-
+
+ char buf[TAGCACHE_BUFSZ];
+ const int bufsz = sizeof(buf);
+
max_entries = tempbuf_size / sizeof(struct temp_file_entry) - 1;
-
+
logf("Building numeric indices...");
lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET);
-
+
if ( (masterfd = open_master_fd(&tcmh, true)) < 0)
return false;
-
+
masterfd_pos = lseek(masterfd, tcmh.tch.entry_count * sizeof(struct index_entry),
SEEK_CUR);
if (masterfd_pos < 0)
@@ -2249,13 +2309,13 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
while (entries_processed < h->entry_count)
{
int count = MIN(h->entry_count - entries_processed, max_entries);
-
+
/* Read in as many entries as possible. */
for (i = 0; i < count; i++)
{
struct temp_file_entry *tfe = &entrybuf[i];
int datastart;
-
+
/* Read in numeric data. */
if (read(tmpfd, tfe, sizeof(struct temp_file_entry)) !=
sizeof(struct temp_file_entry))
@@ -2266,20 +2326,20 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
}
datastart = lseek(tmpfd, 0, SEEK_CUR);
-
+
/**
* Read string data from the following tags:
* - tag_filename
* - tag_artist
* - tag_album
* - tag_title
- *
+ *
* A crc32 hash is calculated from the read data
* and stored back to the data offset field kept in memory.
*/
#define tmpdb_read_string_tag(tag) \
lseek(tmpfd, tfe->tag_offset[tag], SEEK_CUR); \
- if ((unsigned long)tfe->tag_length[tag] > sizeof buf) \
+ if ((unsigned long)tfe->tag_length[tag] > (unsigned long)bufsz) \
{ \
logf("read fail: buffer overflow"); \
close(masterfd); \
@@ -2293,88 +2353,89 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
close(masterfd); \
return false; \
} \
+ str_setlen(buf, tfe->tag_length[tag]); \
\
tfe->tag_offset[tag] = crc_32(buf, strlen(buf), 0xffffffff); \
lseek(tmpfd, datastart, SEEK_SET)
-
+
tmpdb_read_string_tag(tag_filename);
tmpdb_read_string_tag(tag_artist);
tmpdb_read_string_tag(tag_album);
tmpdb_read_string_tag(tag_title);
-
+
/* Seek to the end of the string data. */
lseek(tmpfd, tfe->data_length, SEEK_CUR);
}
-
+
/* Backup the master index position. */
masterfd_pos = lseek(masterfd, 0, SEEK_CUR);
lseek(masterfd, sizeof(struct master_header), SEEK_SET);
-
+
/* Check if we can resurrect some deleted runtime statistics data. */
for (i = 0; i < tcmh.tch.entry_count; i++)
{
/* Read the index entry. */
- if (ecread_index_entry(masterfd, &idx)
+ if (ecread_index_entry(masterfd, &idx)
!= sizeof(struct index_entry))
{
logf("read fail #3");
close(masterfd);
return false;
}
-
+
/**
* Skip unless the entry is marked as being deleted
* or the data has already been resurrected.
*/
if (!(idx.flag & FLAG_DELETED) || (idx.flag & FLAG_RESURRECTED))
continue;
-
+
/* Now try to match the entry. */
/**
* To succesfully match a song, the following conditions
* must apply:
- *
+ *
* For numeric fields: tag_length
* - Full identical match is required
- *
+ *
* If tag_filename matches, no further checking necessary.
- *
+ *
* For string hashes: tag_artist, tag_album, tag_title
* - All three of these must match
*/
for (j = 0; j < count; j++)
{
struct temp_file_entry *tfe = &entrybuf[j];
-
+
/* Try to match numeric fields first. */
if (tfe->tag_offset[tag_length] != idx.tag_seek[tag_length])
continue;
-
+
/* Now it's time to do the hash matching. */
if (tfe->tag_offset[tag_filename] != idx.tag_seek[tag_filename])
{
int match_count = 0;
-
+
/* No filename match, check if we can match two other tags. */
#define tmpdb_match(tag) \
if (tfe->tag_offset[tag] == idx.tag_seek[tag]) \
match_count++
-
+
tmpdb_match(tag_artist);
tmpdb_match(tag_album);
tmpdb_match(tag_title);
-
+
if (match_count < 3)
{
/* Still no match found, give up. */
continue;
}
}
-
+
/* A match found, now copy & resurrect the statistical data. */
#define tmpdb_copy_tag(tag) \
tfe->tag_offset[tag] = idx.tag_seek[tag]
-
+
tmpdb_copy_tag(tag_playcount);
tmpdb_copy_tag(tag_rating);
tmpdb_copy_tag(tag_playtime);
@@ -2382,10 +2443,10 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
tmpdb_copy_tag(tag_commitid);
tmpdb_copy_tag(tag_lastelapsed);
tmpdb_copy_tag(tag_lastoffset);
-
+
/* Avoid processing this entry again. */
idx.flag |= FLAG_RESURRECTED;
-
+
lseek(masterfd, -(off_t)sizeof(struct index_entry), SEEK_CUR);
if (ecwrite_index_entry(masterfd, &idx) != sizeof(struct index_entry))
{
@@ -2393,36 +2454,36 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
close(masterfd);
return false;
}
-
+
logf("Entry resurrected");
}
}
-
-
+
+
/* Restore the master index position. */
lseek(masterfd, masterfd_pos, SEEK_SET);
-
+
/* Commit the data to the index. */
for (i = 0; i < count; i++)
{
int loc = lseek(masterfd, 0, SEEK_CUR);
-
+
if (ecread_index_entry(masterfd, &idx) != sizeof(struct index_entry))
{
logf("read fail #3");
close(masterfd);
return false;
}
-
+
for (j = 0; j < TAG_COUNT; j++)
{
if (!TAGCACHE_IS_NUMERIC(j))
continue;
-
+
idx.tag_seek[j] = entrybuf[i].tag_offset[j];
}
idx.flag = entrybuf[i].flag;
-
+
if (idx.tag_seek[tag_commitid])
{
/* Data has been resurrected. */
@@ -2433,7 +2494,7 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
idx.tag_seek[tag_commitid] = current_tcmh.commitid;
idx.flag |= FLAG_DIRTYNUM;
}
-
+
/* Write back the updated index. */
lseek(masterfd, loc, SEEK_SET);
if (ecwrite_index_entry(masterfd, &idx) != sizeof(struct index_entry))
@@ -2443,13 +2504,13 @@ static bool build_numeric_indices(struct tagcache_header *h, int tmpfd)
return false;
}
}
-
+
entries_processed += count;
logf("%d/%ld entries processed", entries_processed, h->entry_count);
}
-
+
close(masterfd);
-
+
return true;
}
@@ -2466,17 +2527,18 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
struct master_header tcmh;
struct index_entry idxbuf[IDX_BUF_DEPTH];
int idxbuf_pos;
- char buf[TAG_MAXLEN+32];
+ char buf[TAGCACHE_BUFSZ];
+ const long bufsz = sizeof(buf);
int fd = -1, masterfd;
bool error = false;
int init;
int masterfd_pos;
-
+
logf("Building index: %d", index_type);
-
+
/* Check the number of entries we need to allocate ram for. */
commit_entry_count = h->entry_count + 1;
-
+
masterfd = open_master_fd(&tcmh, false);
if (masterfd >= 0)
{
@@ -2501,10 +2563,10 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
/* First part */ commit_entry_count +
/* Second part */ 0;
}
-
+
logf("lookup_buffer_depth=%ld", lookup_buffer_depth);
logf("commit_entry_count=%ld", commit_entry_count);
-
+
/* Allocate buffer for all index entries from both old and new
* tag files. */
tempbufidx = 0;
@@ -2513,21 +2575,21 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
/* Allocate lookup buffer. The first portion of commit_entry_count
* contains the new tags in the temporary file and the second
* part for locating entries already in the db.
- *
+ *
* New tags Old tags
* +---------+---------------------------+
* | index | position/ENTRY_CHUNK_SIZE | lookup buffer
* +---------+---------------------------+
- *
+ *
* Old tags are inserted to a temporary buffer with position:
* tempbuf_insert(position/ENTRY_CHUNK_SIZE, ...);
* And new tags with index:
* tempbuf_insert(idx, ...);
- *
+ *
* The buffer is sorted and written into tag file:
* tempbuf_sort(...);
* leaving master index locations messed up.
- *
+ *
* That is fixed using the lookup buffer for old tags:
* new_seek = tempbuf_find_location(old_seek, ...);
* and for new tags:
@@ -2536,13 +2598,14 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
lookup = (struct tempbuf_searchidx **)&tempbuf[tempbuf_pos];
tempbuf_pos += lookup_buffer_depth * sizeof(void **);
memset(lookup, 0, lookup_buffer_depth * sizeof(void **));
-
+
/* And calculate the remaining data space used mainly for storing
* tag data (strings). */
tempbuf_left = tempbuf_size - tempbuf_pos - 8;
if (tempbuf_left - TAGFILE_ENTRY_AVG_LENGTH * commit_entry_count < 0)
{
logf("Buffer way too small!");
+ close(fd);
return 0;
}
@@ -2561,38 +2624,37 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
struct tagfile_entry entry;
int loc = lseek(fd, 0, SEEK_CUR);
bool ret;
-
- if (ecread_tagfile_entry(fd, &entry) != sizeof(struct tagfile_entry))
- {
- logf("read error #7");
- close(fd);
- return -2;
- }
-
- if (entry.tag_length >= (int)sizeof(buf))
- {
- logf("too long tag #3");
- close(fd);
- return -2;
- }
-
- if (read(fd, buf, entry.tag_length) != entry.tag_length)
+ switch (ecread_tagfile_entry_and_tag(fd, &entry, buf, bufsz))
{
- logf("read error #8");
- close(fd);
- return -2;
+ case e_SUCCESS:
+ break;
+ case e_ENTRY_SIZEMISMATCH:
+ logf("read error #7");
+ close(fd);
+ return -2;
+ case e_TAG_TOOLONG:
+ logf("too long tag #3");
+ close(fd);
+ return -2;
+ case e_TAG_SIZEMISMATCH:
+ logf("read error #8");
+ close(fd);
+ return -2;
+ default:
+ logf("unknown_error");
+ break;;
}
/* Skip deleted entries. */
if (buf[0] == '\0')
continue;
-
+
/**
* Save the tag and tag id in the memory buffer. Tag id
* is saved so we can later reindex the master lookup
* table when the index gets resorted.
*/
- ret = tempbuf_insert(buf, loc/TAGFILE_ENTRY_CHUNK_LENGTH
+ ret = tempbuf_insert(buf, loc/TAGFILE_ENTRY_CHUNK_LENGTH
+ commit_entry_count, entry.idx_id,
TAGCACHE_IS_UNIQUE(index_type));
if (!ret)
@@ -2613,19 +2675,19 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
* Creating new index file to store the tags. No need to preload
* anything whether the index type is sorted or not.
*/
- snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, index_type);
+ snprintf(buf, bufsz, TAGCACHE_FILE_INDEX, index_type);
fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
{
logf("%s open fail", buf);
return -2;
}
-
+
tch.magic = TAGCACHE_MAGIC;
tch.entry_count = 0;
tch.datasize = 0;
-
- if (ecwrite(fd, &tch, 1, tagcache_header_ec, tc_stat.econ)
+
+ if (ecwrite(fd, &tch, 1, tagcache_header_ec, tc_stat.econ)
!= sizeof(struct tagcache_header))
{
logf("header write failed");
@@ -2705,7 +2767,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
for (i = 0; i < h->entry_count; i++)
{
struct temp_file_entry entry;
-
+
if (read(tmpfd, &entry, sizeof(struct temp_file_entry)) !=
sizeof(struct temp_file_entry))
{
@@ -2715,7 +2777,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
}
/* Read data. */
- if (entry.tag_length[index_type] >= (long)sizeof(buf))
+ if (entry.tag_length[index_type] >= (long)bufsz)
{
logf("too long entry!");
error = true;
@@ -2730,18 +2792,19 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
error = true;
goto error_exit;
}
-
+ str_setlen(buf, entry.tag_length[index_type]);
+
if (TAGCACHE_IS_UNIQUE(index_type))
error = !tempbuf_insert(buf, i, -1, true);
else
error = !tempbuf_insert(buf, i, tcmh.tch.entry_count + i, false);
-
+
if (error)
{
logf("insert error");
goto error_exit;
}
-
+
/* Skip to next. */
lseek(tmpfd, entry.data_length - entry.tag_offset[index_type] -
entry.tag_length[index_type], SEEK_CUR);
@@ -2757,12 +2820,12 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
* entry_count and don't crash with that).
*/
ftruncate(fd, lseek(fd, 0, SEEK_CUR));
-
+
i = tempbuf_sort(fd);
if (i < 0)
goto error_exit;
logf("sorted %d tags", i);
-
+
/**
* Now update all indexes in the master lookup file.
*/
@@ -2772,10 +2835,10 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
{
int j;
int loc = lseek(masterfd, 0, SEEK_CUR);
-
+
idxbuf_pos = MIN(tcmh.tch.entry_count - i, IDX_BUF_DEPTH);
-
- if (ecread(masterfd, idxbuf, idxbuf_pos, index_entry_ec, tc_stat.econ)
+
+ if (ecread(masterfd, idxbuf, idxbuf_pos, index_entry_ec, tc_stat.econ)
!= (int)sizeof(struct index_entry)*idxbuf_pos)
{
logf("read fail #5");
@@ -2783,7 +2846,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
goto error_exit ;
}
lseek(masterfd, loc, SEEK_SET);
-
+
for (j = 0; j < idxbuf_pos; j++)
{
if (idxbuf[j].flag & FLAG_DELETED)
@@ -2792,22 +2855,22 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
// idxbuf[j].tag_seek[index_type] = 0;
continue;
}
-
+
idxbuf[j].tag_seek[index_type] = tempbuf_find_location(
idxbuf[j].tag_seek[index_type]/TAGFILE_ENTRY_CHUNK_LENGTH
+ commit_entry_count);
-
+
if (idxbuf[j].tag_seek[index_type] < 0)
{
- logf("update error: %ld/%d/%ld",
+ logf("update error: %ld/%d/%ld",
idxbuf[j].flag, i+j, tcmh.tch.entry_count);
error = true;
goto error_exit;
}
-
+
do_timed_yield();
}
-
+
/* Write back the updated index. */
if (ecwrite(masterfd, idxbuf, idxbuf_pos,
index_entry_ec, tc_stat.econ) !=
@@ -2832,7 +2895,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
for (i = 0; i < h->entry_count; i += idxbuf_pos)
{
int j;
-
+
idxbuf_pos = MIN(h->entry_count - i, IDX_BUF_DEPTH);
if (init)
{
@@ -2841,8 +2904,8 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
else
{
int loc = lseek(masterfd, 0, SEEK_CUR);
-
- if (ecread(masterfd, idxbuf, idxbuf_pos, index_entry_ec, tc_stat.econ)
+
+ if (ecread(masterfd, idxbuf, idxbuf_pos, index_entry_ec, tc_stat.econ)
!= (int)sizeof(struct index_entry)*idxbuf_pos)
{
logf("read fail #6");
@@ -2859,7 +2922,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
{
struct temp_file_entry entry;
struct tagfile_entry fe;
-
+
if (read(tmpfd, &entry, sizeof(struct temp_file_entry)) !=
sizeof(struct temp_file_entry))
{
@@ -2867,7 +2930,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
error = true;
break ;
}
-
+
/* Read data. */
if (entry.tag_length[index_type] >= (int)sizeof(buf))
{
@@ -2877,7 +2940,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
error = true;
break ;
}
-
+
lseek(tmpfd, entry.tag_offset[index_type], SEEK_CUR);
if (read(tmpfd, buf, entry.tag_length[index_type]) !=
entry.tag_length[index_type])
@@ -2923,29 +2986,29 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
error = true;
break ;
}
-
+
do_timed_yield();
}
logf("done");
-
+
/* Finally write the header. */
tch.magic = TAGCACHE_MAGIC;
tch.entry_count = tempbufidx;
tch.datasize = lseek(fd, 0, SEEK_END) - sizeof(struct tagcache_header);
lseek(fd, 0, SEEK_SET);
ecwrite(fd, &tch, 1, tagcache_header_ec, tc_stat.econ);
-
+
if (index_type != tag_filename)
h->datasize += tch.datasize;
logf("s:%d/%ld/%ld", index_type, tch.datasize, h->datasize);
error_exit:
-
+
close(fd);
close(masterfd);
if (error)
return -2;
-
+
return 1;
}
@@ -2963,7 +3026,7 @@ static bool commit(void)
bool ramcache_buffer_stolen = false;
#endif
logf("committing tagcache");
-
+
while (write_lock)
sleep(1);
@@ -2973,12 +3036,12 @@ static bool commit(void)
logf("nothing to commit");
return true;
}
-
-
+
+
/* Load the header. */
len = sizeof(struct tagcache_header);
rc = read(tmpfd, &tch, len);
-
+
if (tch.magic != TAGCACHE_MAGIC || rc != len)
{
logf("incorrect tmpheader");
@@ -2992,11 +3055,11 @@ static bool commit(void)
/* Fully initialize existing headers (if any) before going further. */
tc_stat.ready = check_all_headers();
-
+
#ifdef HAVE_EEPROM_SETTINGS
remove(TAGCACHE_STATEFILE);
#endif
-
+
/* At first be sure to unload the ramcache! */
#ifdef HAVE_TC_RAMCACHE
tc_stat.ramcache = false;
@@ -3005,7 +3068,7 @@ static bool commit(void)
/* Beyond here, jump to commit_error to undo locks and restore dircache */
rc = false;
read_lock++;
-
+
/* Try to steal every buffer we can :) */
#ifdef HAVE_DIRCACHE
if (tempbuf_size == 0)
@@ -3017,7 +3080,7 @@ static bool commit(void)
allocate_tempbuf();
}
#endif /* HAVE_DIRCACHE */
-
+
#ifdef HAVE_TC_RAMCACHE
if (tempbuf_size == 0 && tc_stat.ramcache_allocated > 0)
{
@@ -3028,7 +3091,7 @@ static bool commit(void)
ramcache_buffer_stolen = true;
}
#endif /* HAVE_TC_RAMCACHE */
-
+
/* And finally fail if there are no buffers available. */
if (tempbuf_size == 0)
{
@@ -3037,25 +3100,25 @@ static bool commit(void)
close(tmpfd);
goto commit_error;
}
-
+
logf("commit %ld entries...", tch.entry_count);
-
+
/* Mark DB dirty so it will stay disabled if commit fails. */
current_tcmh.dirty = true;
update_master_header();
-
+
/* Now create the index files. */
tc_stat.commit_step = 0;
tch.datasize = 0;
tc_stat.commit_delayed = false;
-
+
for (i = 0; i < TAG_COUNT; i++)
{
int ret;
-
+
if (TAGCACHE_IS_NUMERIC(i))
continue;
-
+
tc_stat.commit_step++;
ret = build_index(i, &tch, tmpfd);
if (ret <= 0)
@@ -3064,12 +3127,12 @@ static bool commit(void)
logf("tagcache failed init");
if (ret == 0)
tc_stat.commit_delayed = true;
-
+
tc_stat.commit_step = 0;
goto commit_error;
}
}
-
+
if (!build_numeric_indices(&tch, tmpfd))
{
logf("Failure to commit numeric indices");
@@ -3077,19 +3140,19 @@ static bool commit(void)
tc_stat.commit_step = 0;
goto commit_error;
}
-
+
close(tmpfd);
-
+
tc_stat.commit_step = 0;
-
+
/* Update the master index headers. */
if ( (masterfd = open_master_fd(&tcmh, true)) < 0)
goto commit_error;
-
+
remove(TAGCACHE_FILE_TEMP);
tcmh.tch.entry_count += tch.entry_count;
- tcmh.tch.datasize = sizeof(struct master_header)
+ tcmh.tch.datasize = sizeof(struct master_header)
+ sizeof(struct index_entry) * tcmh.tch.entry_count
+ tch.datasize;
tcmh.dirty = false;
@@ -3098,11 +3161,11 @@ static bool commit(void)
lseek(masterfd, 0, SEEK_SET);
ecwrite(masterfd, &tcmh, 1, master_header_ec, tc_stat.econ);
close(masterfd);
-
+
logf("tagcache committed");
tc_stat.ready = check_all_headers();
tc_stat.readyvalid = true;
-
+
#ifdef HAVE_TC_RAMCACHE
if (ramcache_buffer_stolen)
{
@@ -3116,7 +3179,7 @@ static bool commit(void)
if (tc_stat.ramcache_allocated > 0)
tagcache_start_scan();
#endif /* HAVE_TC_RAMCACHE */
-
+
rc = true;
commit_error:
@@ -3139,7 +3202,7 @@ commit_error:
dircache_resume();
}
#endif /* HAVE_DIRCACHE */
-
+
return rc;
}
@@ -3148,34 +3211,34 @@ commit_error:
static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data)
{
struct index_entry idx;
-
+
if (!tc_stat.ready)
return false;
-
+
if (!TAGCACHE_IS_NUMERIC(tag))
return false;
-
+
if (!get_index(masterfd, idx_id, &idx, false))
return false;
-
+
idx.tag_seek[tag] = data;
idx.flag |= FLAG_DIRTYNUM;
-
+
return write_index(masterfd, idx_id, &idx);
}
#if 0
-bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
+bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
int tag, long data)
{
struct master_header myhdr;
-
+
if (tcs->masterfd < 0)
{
if ( (tcs->masterfd = open_master_fd(&myhdr, true)) < 0)
return false;
}
-
+
return modify_numeric_entry(tcs->masterfd, tcs->idx_id, tag, data);
}
#endif
@@ -3183,11 +3246,11 @@ bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
static bool command_queue_is_full(void)
{
int next;
-
+
next = command_queue_widx + 1;
if (next >= TAGCACHE_COMMAND_QUEUE_LENGTH)
next = 0;
-
+
return (next == command_queue_ridx);
}
@@ -3195,27 +3258,27 @@ static void command_queue_sync_callback(void)
{
struct master_header myhdr;
int masterfd;
-
+
mutex_lock(&command_queue_mutex);
-
+
if ( (masterfd = open_master_fd(&myhdr, true)) < 0)
return;
-
+
while (command_queue_ridx != command_queue_widx)
{
struct tagcache_command_entry *ce = &command_queue[command_queue_ridx];
-
+
switch (ce->command)
{
case CMD_UPDATE_MASTER_HEADER:
{
close(masterfd);
update_master_header();
-
+
/* Re-open the masterfd. */
if ( (masterfd = open_master_fd(&myhdr, true)) < 0)
return;
-
+
break;
}
case CMD_UPDATE_NUMERIC:
@@ -3224,13 +3287,13 @@ static void command_queue_sync_callback(void)
break;
}
}
-
+
if (++command_queue_ridx >= TAGCACHE_COMMAND_QUEUE_LENGTH)
command_queue_ridx = 0;
}
-
+
close(masterfd);
-
+
tc_stat.queue_length = 0;
mutex_unlock(&command_queue_mutex);
}
@@ -3239,7 +3302,7 @@ static void run_command_queue(bool force)
{
if (COMMAND_QUEUE_IS_EMPTY)
return;
-
+
if (force || command_queue_is_full())
command_queue_sync_callback();
else
@@ -3251,30 +3314,30 @@ static void queue_command(int cmd, long idx_id, int tag, long data)
while (1)
{
int next;
-
+
mutex_lock(&command_queue_mutex);
next = command_queue_widx + 1;
if (next >= TAGCACHE_COMMAND_QUEUE_LENGTH)
next = 0;
-
+
/* Make sure queue is not full. */
if (next != command_queue_ridx)
{
struct tagcache_command_entry *ce = &command_queue[command_queue_widx];
-
+
ce->command = cmd;
ce->idx_id = idx_id;
ce->tag = tag;
ce->data = data;
-
+
command_queue_widx = next;
-
+
tc_stat.queue_length++;
-
+
mutex_unlock(&command_queue_mutex);
break;
}
-
+
/* Queue is full, try again later... */
mutex_unlock(&command_queue_mutex);
sleep(1);
@@ -3284,16 +3347,16 @@ static void queue_command(int cmd, long idx_id, int tag, long data)
long tagcache_increase_serial(void)
{
long old;
-
+
if (!tc_stat.ready)
return -2;
-
+
while (read_lock)
sleep(1);
-
+
old = current_tcmh.serial++;
queue_command(CMD_UPDATE_MASTER_HEADER, 0, 0, 0);
-
+
return old;
}
@@ -3306,51 +3369,54 @@ void tagcache_update_numeric(int idx_id, int tag, long data)
static bool write_tag(int fd, const char *tagstr, const char *datastr)
{
char buf[512];
+ const int bufsz = sizeof(buf);
int i;
-
- snprintf(buf, sizeof buf, "%s=\"", tagstr);
+
+ snprintf(buf, bufsz, "%s=\"", tagstr);
+
for (i = strlen(buf); i < (long)sizeof(buf)-4; i++)
{
if (*datastr == '\0')
break;
-
+
if (*datastr == '"' || *datastr == '\\')
buf[i++] = '\\';
-
+
else if (*datastr == '\n')
{
buf[i++] = '\\';
buf[i] = 'n';
continue;
}
-
+
buf[i] = *(datastr++);
}
-
- strcpy(&buf[i], "\" ");
-
+
+ str_setlen(buf, bufsz - 1);
+ strlcpy(&buf[i], "\" ", (bufsz - i - 1));
+
write(fd, buf, i + 2);
-
+
return true;
}
#ifndef __PCTOOL__
-static bool read_tag(char *dest, long size,
+static bool read_tag(char *dest, long size,
const char *src, const char *tagstr)
{
int pos;
char current_tag[32];
-
+
while (*src != '\0')
{
/* Skip all whitespace */
while (*src == ' ')
src++;
-
+
if (*src == '\0')
break;
-
+
pos = 0;
/* Read in tag name */
while (*src != '=' && *src != ' ')
@@ -3358,27 +3424,28 @@ static bool read_tag(char *dest, long size,
current_tag[pos] = *src;
src++;
pos++;
-
- if (*src == '\0' || pos >= (long)sizeof(current_tag))
+
+ if (*src == '\0' || pos >= (int) sizeof(current_tag))
return false;
}
- current_tag[pos] = '\0';
-
+
+ str_setlen(current_tag, pos);
+
/* Read in tag data */
-
+
/* Find the start. */
while (*src != '"' && *src != '\0')
src++;
if (*src == '\0' || *(++src) == '\0')
return false;
-
+
/* Read the data. */
for (pos = 0; pos < size; pos++)
{
if (*src == '\0')
break;
-
+
if (*src == '\\')
{
src++;
@@ -3386,36 +3453,36 @@ static bool read_tag(char *dest, long size,
dest[pos] = '\n';
else
dest[pos] = *src;
-
+
src++;
continue;
}
-
+
if (*src == '\0')
break;
-
+
if (*src == '"')
{
src++;
break;
}
-
+
dest[pos] = *(src++);
}
-
- dest[pos] = '\0';
+
+ str_setlen(dest, pos);
if (!strcasecmp(tagstr, current_tag))
return true;
}
-
+
return false;
}
static int parse_changelog_line(int line_n, char *buf, void *parameters)
{
struct index_entry idx;
- char tag_data[TAG_MAXLEN+32];
+ char tag_data[TAGCACHE_BUFSZ];
int idx_id;
long masterfd = (long)(intptr_t)parameters;
const int import_tags[] = { tag_playcount, tag_rating, tag_playtime,
@@ -3423,10 +3490,10 @@ static int parse_changelog_line(int line_n, char *buf, void *parameters)
tag_lastoffset };
int i;
(void)line_n;
-
+
if (*buf == '#')
return 0;
-
+
/* logf("%d/%s", line_n, buf); */
if (!read_tag(tag_data, sizeof tag_data, buf, "filename"))
{
@@ -3434,49 +3501,49 @@ static int parse_changelog_line(int line_n, char *buf, void *parameters)
logf("-> %s", buf);
return 0;
}
-
+
idx_id = find_index(tag_data);
if (idx_id < 0)
{
logf("%d/entry not found", line_n);
return 0;
}
-
+
if (!get_index(masterfd, idx_id, &idx, false))
{
logf("%d/failed to retrieve index entry", line_n);
return 0;
}
-
+
/* Stop if tag has already been modified. */
if (idx.flag & FLAG_DIRTYNUM)
return 0;
-
+
logf("%d/import: %s", line_n, tag_data);
-
+
idx.flag |= FLAG_DIRTYNUM;
for (i = 0; i < (long)(sizeof(import_tags)/sizeof(import_tags[0])); i++)
{
int data;
-
+
if (!read_tag(tag_data, sizeof tag_data, buf,
tagcache_tag_to_str(import_tags[i])))
{
continue;
}
-
+
data = atoi(tag_data);
if (data < 0)
continue;
-
+
idx.tag_seek[import_tags[i]] = data;
-
+
if (import_tags[i] == tag_lastplayed && data >= current_tcmh.serial)
current_tcmh.serial = data + 1;
else if (import_tags[i] == tag_commitid && data >= current_tcmh.commitid)
current_tcmh.commitid = data + 1;
}
-
+
return write_index(masterfd, idx_id, &idx) ? 0 : -5;
}
@@ -3487,46 +3554,47 @@ bool tagcache_import_changelog(void)
int clfd;
long masterfd;
char buf[2048];
-
+ const int bufsz = sizeof(buf);
+
if (!tc_stat.ready)
return false;
-
+
while (read_lock)
sleep(1);
-
+
clfd = open(TAGCACHE_FILE_CHANGELOG, O_RDONLY);
if (clfd < 0)
{
logf("failure to open changelog");
return false;
}
-
+
if ( (masterfd = open_master_fd(&myhdr, true)) < 0)
{
close(clfd);
return false;
}
-
+
write_lock++;
-
+
filenametag_fd = open_tag_fd(&tch, tag_filename, false);
- fast_readline(clfd, buf, sizeof buf, (void *)(intptr_t)masterfd,
+ fast_readline(clfd, buf, bufsz, (void *)(intptr_t)masterfd,
parse_changelog_line);
-
+
close(clfd);
close(masterfd);
-
+
if (filenametag_fd >= 0)
{
close(filenametag_fd);
filenametag_fd = -1;
}
-
+
write_lock--;
-
+
update_master_header();
-
+
return true;
}
@@ -3536,17 +3604,18 @@ bool tagcache_create_changelog(struct tagcache_search *tcs)
{
struct master_header myhdr;
struct index_entry idx;
- char buf[TAG_MAXLEN+32];
+ char buf[TAGCACHE_BUFSZ];
+ const int bufsz = sizeof(buf);
char temp[32];
int clfd;
int i, j;
-
+
if (!tc_stat.ready)
return false;
-
+
if (!tagcache_search(tcs, tag_filename))
return false;
-
+
/* Initialize the changelog */
clfd = open(TAGCACHE_FILE_CHANGELOG, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (clfd < 0)
@@ -3554,7 +3623,7 @@ bool tagcache_create_changelog(struct tagcache_search *tcs)
logf("failure to open changelog");
return false;
}
-
+
if (tcs->masterfd < 0)
{
if ( (tcs->masterfd = open_master_fd(&myhdr, false)) < 0)
@@ -3568,9 +3637,9 @@ bool tagcache_create_changelog(struct tagcache_search *tcs)
lseek(tcs->masterfd, 0, SEEK_SET);
ecread(tcs->masterfd, &myhdr, 1, master_header_ec, tc_stat.econ);
}
-
+
write(clfd, "## Changelog version 1\n", 23);
-
+
for (i = 0; i < myhdr.tch.entry_count; i++)
{
if (ecread_index_entry(tcs->masterfd, &idx) != sizeof(struct index_entry))
@@ -3580,15 +3649,15 @@ bool tagcache_create_changelog(struct tagcache_search *tcs)
close(clfd);
return false;
}
-
+
/* Skip until the entry found has been modified. */
if (! (idx.flag & FLAG_DIRTYNUM) )
continue;
-
+
/* Skip deleted entries too. */
if (idx.flag & FLAG_DELETED)
continue;
-
+
/* Now retrieve all tags. */
for (j = 0; j < TAG_COUNT; j++)
{
@@ -3598,20 +3667,20 @@ bool tagcache_create_changelog(struct tagcache_search *tcs)
write_tag(clfd, tagcache_tag_to_str(j), temp);
continue;
}
-
+
tcs->type = j;
- tagcache_retrieve(tcs, i, tcs->type, buf, sizeof buf);
+ tagcache_retrieve(tcs, i, tcs->type, buf, bufsz);
write_tag(clfd, tagcache_tag_to_str(j), buf);
}
-
+
write(clfd, "\n", 1);
do_timed_yield();
}
-
+
close(clfd);
-
+
tagcache_search_finish(tcs);
-
+
return true;
}
@@ -3622,33 +3691,34 @@ static bool delete_entry(long idx_id)
int tag, i;
struct index_entry idx, myidx;
struct master_header myhdr;
- char buf[TAG_MAXLEN+32];
+ char buf[TAGCACHE_BUFSZ];
+ const int bufsz = sizeof(buf);
int in_use[TAG_COUNT];
-
+
logf("delete_entry(): %ld", idx_id);
-
+
#ifdef HAVE_TC_RAMCACHE
/* At first mark the entry removed from ram cache. */
if (tc_stat.ramcache)
tcramcache.hdr->indices[idx_id].flag |= FLAG_DELETED;
#endif
-
+
if ( (masterfd = open_master_fd(&myhdr, true) ) < 0)
return false;
-
+
lseek(masterfd, idx_id * sizeof(struct index_entry), SEEK_CUR);
if (ecread_index_entry(masterfd, &myidx) != sizeof(struct index_entry))
{
logf("delete_entry(): read error");
goto cleanup;
}
-
+
if (myidx.flag & FLAG_DELETED)
{
logf("delete_entry(): already deleted!");
goto cleanup;
}
-
+
myidx.flag |= FLAG_DELETED;
lseek(masterfd, -(off_t)sizeof(struct index_entry), SEEK_CUR);
if (ecwrite_index_entry(masterfd, &myidx) != sizeof(struct index_entry))
@@ -3660,12 +3730,12 @@ static bool delete_entry(long idx_id)
/* Now check which tags are no longer in use (if any) */
for (tag = 0; tag < TAG_COUNT; tag++)
in_use[tag] = 0;
-
+
lseek(masterfd, sizeof(struct master_header), SEEK_SET);
for (i = 0; i < myhdr.tch.entry_count; i++)
{
struct index_entry *idxp;
-
+
#ifdef HAVE_TC_RAMCACHE
/* Use RAM DB if available for greater speed */
if (tc_stat.ramcache)
@@ -3680,30 +3750,30 @@ static bool delete_entry(long idx_id)
}
idxp = &idx;
}
-
+
if (idxp->flag & FLAG_DELETED)
continue;
-
+
for (tag = 0; tag < TAG_COUNT; tag++)
{
if (TAGCACHE_IS_NUMERIC(tag))
continue;
-
+
if (idxp->tag_seek[tag] == myidx.tag_seek[tag])
in_use[tag]++;
}
}
-
+
/* Now delete all tags no longer in use. */
for (tag = 0; tag < TAG_COUNT; tag++)
{
struct tagcache_header tch;
int oldseek = myidx.tag_seek[tag];
-
+
if (TAGCACHE_IS_NUMERIC(tag))
continue;
-
- /**
+
+ /**
* Replace tag seek with a hash value of the field string data.
* That way runtime statistics of moved or altered files can be
* resurrected.
@@ -3724,28 +3794,35 @@ static bool delete_entry(long idx_id)
#endif /* HAVE_TC_RAMCACHE */
{
struct tagfile_entry tfe;
-
+
/* Open the index file, which contains the tag names. */
if ((fd = open_tag_fd(&tch, tag, true)) < 0)
goto cleanup;
-
+
/* Skip the header block */
lseek(fd, myidx.tag_seek[tag], SEEK_SET);
- if (ecread_tagfile_entry(fd, &tfe) != sizeof(struct tagfile_entry))
- {
- logf("delete_entry(): read error #3");
- goto cleanup;
- }
-
- if (read(fd, buf, tfe.tag_length) != tfe.tag_length)
+
+ switch (ecread_tagfile_entry_and_tag(fd, &tfe, buf, bufsz))
{
- logf("delete_entry(): read error #4");
- goto cleanup;
+ case e_SUCCESS:
+ break;
+ case e_ENTRY_SIZEMISMATCH:
+ logf("delete_entry(): read error #3");
+ goto cleanup;
+ case e_TAG_TOOLONG:
+ logf("too long tag #4");
+ goto cleanup;
+ case e_TAG_SIZEMISMATCH:
+ logf("delete_entry(): read error #3");
+ goto cleanup;
+ default:
+ logf("unknown_error");
+ break;;
}
-
+
myidx.tag_seek[tag] = crc_32(buf, strlen(buf), 0xffffffff);
}
-
+
if (in_use[tag])
{
logf("in use: %d/%d", tag, in_use[tag]);
@@ -3756,42 +3833,42 @@ static bool delete_entry(long idx_id)
}
continue;
}
-
+
#ifdef HAVE_TC_RAMCACHE
/* Delete from ram. */
if (tc_stat.ramcache && tag != tag_filename)
{
struct tagfile_entry *tagentry =
(struct tagfile_entry *)&tcramcache.hdr->tags[tag][oldseek];
- tagentry->tag_data[0] = '\0';
+ str_setlen(tagentry->tag_data, 0);
}
#endif /* HAVE_TC_RAMCACHE */
-
+
/* Open the index file, which contains the tag names. */
if (fd < 0)
{
if ((fd = open_tag_fd(&tch, tag, true)) < 0)
goto cleanup;
}
-
+
/* Skip the header block */
lseek(fd, oldseek + sizeof(struct tagfile_entry), SEEK_SET);
-
+
/* Debug, print 10 first characters of the tag
read(fd, buf, 10);
buf[10]='\0';
logf("TAG:%s", buf);
lseek(fd, -10, SEEK_CUR);
*/
-
+
/* Write first data byte in tag as \0 */
write(fd, "", 1);
-
+
/* Now tag data has been removed */
close(fd);
fd = -1;
}
-
+
/* Write index entry back into master index. */
lseek(masterfd, sizeof(struct master_header) +
(idx_id * sizeof(struct index_entry)), SEEK_SET);
@@ -3800,17 +3877,17 @@ static bool delete_entry(long idx_id)
logf("delete_entry(): write_error #2");
goto cleanup;
}
-
+
close(masterfd);
-
+
return true;
-
+
cleanup:
if (fd >= 0)
close(fd);
if (masterfd >= 0)
close(masterfd);
-
+
return false;
}
@@ -3822,10 +3899,10 @@ static bool check_event_queue(void)
{
#ifndef __PCTOOL__
struct queue_event ev;
-
+
if(!queue_peek(&tagcache_queue, &ev))
return false;
-
+
switch (ev.id)
{
case Q_STOP_SCAN:
@@ -3834,7 +3911,7 @@ static bool check_event_queue(void)
return true;
}
#endif /* __PCTOOL__ */
-
+
return false;
}
@@ -3874,12 +3951,12 @@ static bool allocate_tagcache(void)
int fd = open_master_fd(&tcmh, false);
if (fd < 0)
return false;
-
+
close(fd);
-
- /**
- * Now calculate the required cache size plus
- * some extra space for alignment fixes.
+
+ /**
+ * Now calculate the required cache size plus
+ * some extra space for alignment fixes.
*/
size_t alloc_size = tcmh.tch.datasize + 256 + TAGCACHE_RESERVE +
sizeof(struct ramcache_header) + TAG_COUNT*sizeof(void *);
@@ -3910,14 +3987,14 @@ static bool tagcache_dumpload(void)
tcramcache.handle = 0;
tcramcache.hdr = NULL;
-
+
fd = open(TAGCACHE_STATEFILE, O_RDONLY);
if (fd < 0)
{
logf("no tagcache statedump");
return false;
}
-
+
/* Check the statefile memory placement */
rc = read(fd, &shdr, sizeof(struct statefile_header));
if (rc != sizeof(struct statefile_header)
@@ -3953,13 +4030,13 @@ static bool tagcache_dumpload(void)
}
tc_stat = shdr.tc_stat;
-
+
/* Now fix the pointers */
fix_ramcache(shdr.hdr, tcramcache.hdr);
-
+
/* Load the tagcache master header (should match the actual DB file header). */
memcpy(&current_tcmh, &shdr.mh, sizeof current_tcmh);
-
+
return true;
}
@@ -3967,30 +4044,30 @@ static bool tagcache_dumpsave(void)
{
struct statefile_header shdr;
int fd;
-
+
if (!tc_stat.ramcache)
return false;
-
+
fd = open(TAGCACHE_STATEFILE, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
{
logf("failed to create a statedump");
return false;
}
-
+
/* Create the header */
shdr.magic = TAGCACHE_STATEFILE_MAGIC;
shdr.hdr = tcramcache.hdr;
memcpy(&shdr.mh, &current_tcmh, sizeof current_tcmh);
memcpy(&shdr.tc_stat, &tc_stat, sizeof tc_stat);
write(fd, &shdr, sizeof shdr);
-
+
/* And dump the data too */
tcrc_buffer_lock();
write(fd, tcramcache.hdr, tc_stat.ramcache_allocated);
tcrc_buffer_unlock();
close(fd);
-
+
return true;
}
#endif /* HAVE_EEPROM_SETTINGS */
@@ -4014,7 +4091,7 @@ static bool load_tagcache(void)
logf("loading tagcache to ram...");
tcrc_buffer_lock(); /* lock for the rest of the scan, simpler to handle */
-
+
fd = open(TAGCACHE_FILE_MASTER, O_RDONLY);
if (fd < 0)
{
@@ -4100,7 +4177,7 @@ static bool load_tagcache(void)
logf("Too big tagcache #10.75");
goto failure;
}
-
+
struct tagfile_entry *fe = (struct tagfile_entry *)p;
off_t pos = lseek(fd, 0, SEEK_CUR);
@@ -4149,11 +4226,11 @@ static bool load_tagcache(void)
bytesleft -= sizeof (struct dircache_fileref);
#endif /* HAVE_DIRCACHE */
- char filename[TAG_MAXLEN+32];
+ char filename[TAGCACHE_BUFSZ];
if (fe->tag_length >= (long)sizeof(filename)-1)
{
read(fd, filename, 10);
- filename[10] = '\0';
+ str_setlen(filename, 10);
logf("TAG:%s", filename);
logf("too long filename");
goto failure;
@@ -4234,7 +4311,7 @@ static bool load_tagcache(void)
close(fd);
}
-
+
tc_stat.ramcache_used = tc_stat.ramcache_allocated - bytesleft;
logf("tagcache loaded into ram!");
logf("utilization: %d%%", 100*tc_stat.ramcache_used / tc_stat.ramcache_allocated);
@@ -4253,13 +4330,14 @@ failure:
static bool check_deleted_files(void)
{
int fd;
- char buf[TAG_MAXLEN+32];
+ char buf[TAGCACHE_BUFSZ];
+ const int bufsz = sizeof(buf);
struct tagfile_entry tfe;
-
+
logf("reverse scan...");
- snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tag_filename);
+ snprintf(buf, bufsz, TAGCACHE_FILE_INDEX, tag_filename);
fd = open(buf, O_RDONLY);
-
+
if (fd < 0)
{
logf("%s open fail", buf);
@@ -4267,27 +4345,28 @@ static bool check_deleted_files(void)
}
lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
- while (ecread_tagfile_entry(fd, &tfe) == sizeof(struct tagfile_entry)
+ while (ecread_tagfile_entry(fd, &tfe) == sizeof(struct tagfile_entry)
&& !check_event_queue())
{
- if (tfe.tag_length >= (long)sizeof(buf)-1)
+ if (tfe.tag_length >= (long)bufsz-1)
{
logf("too long tag");
close(fd);
return false;
}
-
+
if (read(fd, buf, tfe.tag_length) != tfe.tag_length)
{
logf("read error #14");
close(fd);
return false;
}
-
+ str_setlen(buf, tfe.tag_length);
+
/* Check if the file has already deleted from the db. */
if (*buf == '\0')
continue;
-
+
/* Now check if the file exists. */
if (!file_exists(buf))
{
@@ -4298,11 +4377,11 @@ static bool check_deleted_files(void)
do_timed_yield();
}
-
+
close(fd);
-
+
logf("done");
-
+
return true;
}
@@ -4314,12 +4393,13 @@ static void NO_INLINE check_ignore(const char *dirname,
int *ignore, int *unignore)
{
char newpath[MAX_PATH];
+ const int bufsz = sizeof(newpath);
/* check for a database.ignore file */
- snprintf(newpath, MAX_PATH, "%s/database.ignore", dirname);
+ snprintf(newpath, bufsz, "%s/database.ignore", dirname);
*ignore = file_exists(newpath);
/* check for a database.unignore file */
- snprintf(newpath, MAX_PATH, "%s/database.unignore", dirname);
+ snprintf(newpath, bufsz, "%s/database.unignore", dirname);
*unignore = file_exists(newpath);
}
@@ -4354,7 +4434,7 @@ static bool search_root_exists(const char *path)
* search root.
*
* Returns true if it added the path to the search roots
- *
+ *
* Windows 2000 and greater supports symlinks, but they don't provide
* realpath() or readlink(), and symlinks are rarely used on them so
* ignore this for windows for now
@@ -4365,6 +4445,7 @@ static bool add_search_root(const char *name)
#ifndef WIN32
struct search_roots_ll *this, *prev = NULL;
char target[MAX_PATH];
+ const int target_bufsz = sizeof(target);
/* Okay, realpath() is almost completely broken on android
*
* It doesn't accept NULL for resolved_name to dynamically allocate
@@ -4378,11 +4459,11 @@ static bool add_search_root(const char *name)
static char abs_target[PATH_MAX];
ssize_t len;
- len = readlink(name, target, sizeof(target)-1);
+ len = readlink(name, target, target_bufsz-1);
if (len < 0)
return false;
- target[len] = '\0';
+ str_setlen(target, len);
if (realpath(target, abs_target) == NULL)
return false;
@@ -4396,7 +4477,7 @@ static bool add_search_root(const char *name)
{
size_t len = strlen(abs_target) + 1; /* count \0 */
this = malloc(sizeof(struct search_roots_ll) + len );
- if (!this || len > MAX_PATH)
+ if (!this || len > MIN(PATH_MAX, MAX_PATH))
{
logf("Error at adding a search root: %s", this ? "path too long":"OOM");
free(this);
@@ -4490,20 +4571,20 @@ static bool check_dir(const char *dirname, int add_files)
else if (add_files)
{
tc_stat.curentry = curpath;
-
+
/* Add a new entry to the temporary db file. */
add_tagcache(curpath, info.mtime);
-
+
/* Wait until current path for debug screen is read and unset. */
while (tc_stat.syncscreen && tc_stat.curentry != NULL)
yield();
-
+
tc_stat.curentry = NULL;
}
- curpath[len] = '\0';
+ str_setlen(curpath, len);
}
-
+
closedir(dir);
return success;
@@ -4528,17 +4609,17 @@ void do_tagcache_build(const char *path[])
struct tagcache_header header;
bool ret;
- curpath[0] = '\0';
+ str_setlen(curpath, 0);
data_size = 0;
total_entry_count = 0;
processed_dir_count = 0;
-
+
#ifdef HAVE_DIRCACHE
dircache_wait();
#endif
-
+
logf("updating tagcache");
-
+
cachefd = open(TAGCACHE_FILE_TEMP, O_RDONLY);
if (cachefd >= 0)
{
@@ -4546,7 +4627,7 @@ void do_tagcache_build(const char *path[])
close(cachefd);
return ;
}
-
+
cachefd = open(TAGCACHE_FILE_TEMP, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (cachefd < 0)
{
@@ -4555,7 +4636,7 @@ void do_tagcache_build(const char *path[])
}
filenametag_fd = open_tag_fd(&header, tag_filename, false);
-
+
cpu_boost(true);
logf("Scanning files...");
@@ -4583,7 +4664,7 @@ void do_tagcache_build(const char *path[])
/* check_dir might add new roots */
for(this = &roots_ll[0]; this; this = this->next)
{
- strcpy(curpath, this->path);
+ strlcpy(curpath, this->path, sizeof(curpath));
ret = ret && check_dir(this->path, true);
}
free_search_roots(&roots_ll[0]);
@@ -4620,7 +4701,7 @@ void do_tagcache_build(const char *path[])
#ifdef __PCTOOL__
free_tempbuf();
#endif
-
+
#ifdef HAVE_TC_RAMCACHE
if (tcramcache.hdr)
{
@@ -4629,7 +4710,7 @@ void do_tagcache_build(const char *path[])
queue_post(&tagcache_queue, Q_IMPORT_CHANGELOG, 0);
}
#endif
-
+
cpu_boost(false);
}
@@ -4652,9 +4733,9 @@ static void load_ramcache(void)
{
if (!tcramcache.hdr)
return ;
-
+
cpu_boost(true);
-
+
/* At first we should load the cache (if exists). */
tc_stat.ramcache = load_tagcache();
@@ -4668,7 +4749,7 @@ static void load_ramcache(void)
tcramcache.handle = 0;
core_free(handle);
}
-
+
cpu_boost(false);
}
@@ -4692,7 +4773,7 @@ static void tagcache_thread(void)
allocate_tempbuf();
commit();
free_tempbuf();
-
+
#ifdef HAVE_TC_RAMCACHE
#ifdef HAVE_EEPROM_SETTINGS
if (firmware_settings.initialized && firmware_settings.disk_clean
@@ -4703,15 +4784,15 @@ static void tagcache_thread(void)
remove(TAGCACHE_STATEFILE);
#endif /* HAVE_EEPROM_SETTINGS */
-
+
/* Allocate space for the tagcache if found on disk. */
if (global_settings.tagcache_ram && !tc_stat.ramcache)
allocate_tagcache();
#endif /* HAVE_TC_RAMCACHE */
-
+
cpu_boost(false);
tc_stat.initialized = true;
-
+
/* Don't delay bootup with the header check but do it on background. */
if (!tc_stat.ready)
{
@@ -4719,11 +4800,11 @@ static void tagcache_thread(void)
tc_stat.ready = check_all_headers();
tc_stat.readyvalid = true;
}
-
+
while (1)
{
run_command_queue(false);
-
+
queue_wait_w_tmo(&tagcache_queue, &ev, HZ);
switch (ev.id)
@@ -4731,13 +4812,13 @@ static void tagcache_thread(void)
case Q_IMPORT_CHANGELOG:
tagcache_import_changelog();
break;
-
+
case Q_REBUILD:
remove_files();
remove(TAGCACHE_FILE_TEMP);
tagcache_build();
break;
-
+
case Q_UPDATE:
tagcache_build();
#ifdef HAVE_TC_RAMCACHE
@@ -4745,13 +4826,14 @@ static void tagcache_thread(void)
#endif
check_deleted_files();
break ;
-
+
case Q_START_SCAN:
check_done = false;
+ /* fallthrough */
case SYS_TIMEOUT:
if (check_done || !tc_stat.ready)
break ;
-
+
#ifdef HAVE_TC_RAMCACHE
if (!tc_stat.ramcache && global_settings.tagcache_ram)
{
@@ -4764,24 +4846,24 @@ static void tagcache_thread(void)
if (global_settings.tagcache_autoupdate)
{
tagcache_build();
-
+
/* This will be very slow unless dircache is enabled
or target is flash based, but do it anyway for
consistency. */
check_deleted_files();
}
-
+
logf("tagcache check done");
-
+
check_done = true;
break ;
case Q_STOP_SCAN:
break ;
-
+
case SYS_POWEROFF:
break ;
-
+
case SYS_USB_CONNECTED:
logf("USB: TagCache");
usb_acknowledge(SYS_USB_CONNECTED_ACK);
@@ -4795,11 +4877,11 @@ bool tagcache_prepare_shutdown(void)
{
if (tagcache_get_commit_step() > 0)
return false;
-
+
tagcache_stop_scan();
while (read_lock || write_lock)
sleep(1);
-
+
return true;
}
@@ -4807,7 +4889,7 @@ void tagcache_shutdown(void)
{
/* Flush the command queue. */
run_command_queue(true);
-
+
#if defined(HAVE_EEPROM_SETTINGS) && defined(HAVE_TC_RAMCACHE)
if (tc_stat.ramcache)
tagcache_dumpsave();
@@ -4848,7 +4930,7 @@ struct tagcache_stat* tagcache_get_stat(void)
{
tc_stat.progress = get_progress();
tc_stat.processed_entries = processed_dir_count;
-
+
return &tc_stat;
}
@@ -4861,7 +4943,7 @@ bool tagcache_update(void)
{
if (!tc_stat.ready)
return false;
-
+
queue_post(&tagcache_queue, Q_UPDATE, 0);
return false;
}
@@ -4886,12 +4968,12 @@ void tagcache_init(void)
memset(&current_tcmh, 0, sizeof(struct master_header));
filenametag_fd = -1;
write_lock = read_lock = 0;
-
+
#ifndef __PCTOOL__
mutex_init(&command_queue_mutex);
queue_init(&tagcache_queue, true);
create_thread(tagcache_thread, tagcache_stack,
- sizeof(tagcache_stack), 0, tagcache_thread_name
+ sizeof(tagcache_stack), 0, tagcache_thread_name
IF_PRIO(, PRIORITY_BACKGROUND)
IF_COP(, CPU));
#else
diff --git a/apps/tagcache.h b/apps/tagcache.h
index e358cc26e0..b64571de40 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -31,10 +31,10 @@
tagcache.c and bump up the header version too.
*/
enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
- tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year,
- tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating,
- tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, tag_lastelapsed,
- tag_lastoffset,
+ tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year,
+ tag_discnumber, tag_tracknumber, tag_virt_canonicalartist, tag_bitrate, tag_length,
+ tag_playcount, tag_rating, tag_playtime, tag_lastplayed, tag_commitid, tag_mtime,
+ tag_lastelapsed, tag_lastoffset,
/* Real tags end here, count them. */
TAG_COUNT,
/* Virtual tags */
@@ -52,7 +52,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
#define IDX_BUF_DEPTH 64
/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */
-#define TAGCACHE_MAGIC 0x5443480f
+#define TAGCACHE_MAGIC 0x54434810
/* Dump store/restore header version 'TCSxx'. */
#define TAGCACHE_STATEFILE_MAGIC 0x54435301
@@ -109,10 +109,9 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
(1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \
(1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \
(1LU << tag_lastelapsed) | (1LU << tag_lastoffset) | \
- (1LU << tag_virt_basename) | (1LU << tag_virt_length_min) | \
- (1LU << tag_virt_length_sec) | (1LU << tag_virt_playtime_min) | \
- (1LU << tag_virt_playtime_sec) | (1LU << tag_virt_entryage) | \
- (1LU << tag_virt_autoscore))
+ (1LU << tag_virt_length_min) | (1LU << tag_virt_length_sec) | \
+ (1LU << tag_virt_playtime_min) | (1LU << tag_virt_playtime_sec) | \
+ (1LU << tag_virt_entryage) | (1LU << tag_virt_autoscore))
#define TAGCACHE_IS_NUMERIC(tag) (BIT_N(tag) & TAGCACHE_NUMERIC_TAGS)
diff --git a/apps/tagnavi.config b/apps/tagnavi.config
index 80f891dd94..254fe04092 100644
--- a/apps/tagnavi.config
+++ b/apps/tagnavi.config
@@ -12,12 +12,12 @@
%format "fmt_title" "%s - %02d:%02d" title Lm Ls
%format "fmt_alphanum_title" "%s - %02d:%02d (%s)" basename Lm Ls filename ? title == "<Untagged>"
%format "fmt_alphanum_title" "%s - %02d:%02d" title Lm Ls
-%format "fmt_mostplayed" "%2d|%3d %s (%s)" playcount autoscore title artist %sort = "inverse" %limit = "100"
-%format "fmt_lastplayed" "%06d%s - %s" lastplayed artist title %sort = "inverse" %limit = "99" %strip = "6"
-%format "fmt_forgotten" "%06d%s - %s" lastplayed artist title %limit = "99" %strip = "6"
+%format "fmt_mostplayed" "%2d|%3d %s (%s)" playcount autoscore title canonicalartist %sort = "inverse" %limit = "100"
+%format "fmt_lastplayed" "%06d%s - %s" lastplayed canonicalartist title %sort = "inverse" %limit = "99" %strip = "6"
+%format "fmt_forgotten" "%06d%s - %s" lastplayed canonicalartist title %limit = "99" %strip = "6"
%format "fmt_best_tracks" "%02d. %s (%3d)" tracknum title autoscore
-%format "fmt_score" "(%3d) %s-%s" autoscore title artist
-%format "fmt_rating" "(%2d) %s-%s" rating title artist %sort = "inverse"
+%format "fmt_score" "(%3d) %s-%s" autoscore title canonicalartist
+%format "fmt_rating" "(%2d) %s-%s" rating title canonicalartist %sort = "inverse"
# Include our custom menu
%include "/.rockbox/tagnavi_custom.config"
@@ -28,33 +28,33 @@
# Define the A to Z Artist sub menu
%menu_start "custom_artist" "Artist A to Z"
-"Numeric" -> artist ? artist < "A" -> album -> title = "fmt_title"
-"A" -> artist ? artist ^ "A" -> album -> title = "fmt_title"
-"B" -> artist ? artist ^ "B" -> album -> title = "fmt_title"
-"C" -> artist ? artist ^ "C" -> album -> title = "fmt_title"
-"D" -> artist ? artist ^ "D" -> album -> title = "fmt_title"
-"E" -> artist ? artist ^ "E" -> album -> title = "fmt_title"
-"F" -> artist ? artist ^ "F" -> album -> title = "fmt_title"
-"G" -> artist ? artist ^ "G" -> album -> title = "fmt_title"
-"H" -> artist ? artist ^ "H" -> album -> title = "fmt_title"
-"I" -> artist ? artist ^ "I" -> album -> title = "fmt_title"
-"J" -> artist ? artist ^ "J" -> album -> title = "fmt_title"
-"K" -> artist ? artist ^ "K" -> album -> title = "fmt_title"
-"L" -> artist ? artist ^ "L" -> album -> title = "fmt_title"
-"M" -> artist ? artist ^ "M" -> album -> title = "fmt_title"
-"N" -> artist ? artist ^ "N" -> album -> title = "fmt_title"
-"O" -> artist ? artist ^ "O" -> album -> title = "fmt_title"
-"P" -> artist ? artist ^ "P" -> album -> title = "fmt_title"
-"Q" -> artist ? artist ^ "Q" -> album -> title = "fmt_title"
-"R" -> artist ? artist ^ "R" -> album -> title = "fmt_title"
-"S" -> artist ? artist ^ "S" -> album -> title = "fmt_title"
-"T" -> artist ? artist ^ "T" -> album -> title = "fmt_title"
-"U" -> artist ? artist ^ "U" -> album -> title = "fmt_title"
-"V" -> artist ? artist ^ "V" -> album -> title = "fmt_title"
-"W" -> artist ? artist ^ "W" -> album -> title = "fmt_title"
-"X" -> artist ? artist ^ "X" -> album -> title = "fmt_title"
-"Y" -> artist ? artist ^ "Y" -> album -> title = "fmt_title"
-"Z" -> artist ? artist ^ "Z" -> album -> title = "fmt_title"
+"Numeric" -> canonicalartist ? canonicalartist < "A" -> album -> title = "fmt_title"
+"A" -> canonicalartist ? canonicalartist ^ "A" -> album -> title = "fmt_title"
+"B" -> canonicalartist ? canonicalartist ^ "B" -> album -> title = "fmt_title"
+"C" -> canonicalartist ? canonicalartist ^ "C" -> album -> title = "fmt_title"
+"D" -> canonicalartist ? canonicalartist ^ "D" -> album -> title = "fmt_title"
+"E" -> canonicalartist ? canonicalartist ^ "E" -> album -> title = "fmt_title"
+"F" -> canonicalartist ? canonicalartist ^ "F" -> album -> title = "fmt_title"
+"G" -> canonicalartist ? canonicalartist ^ "G" -> album -> title = "fmt_title"
+"H" -> canonicalartist ? canonicalartist ^ "H" -> album -> title = "fmt_title"
+"I" -> canonicalartist ? canonicalartist ^ "I" -> album -> title = "fmt_title"
+"J" -> canonicalartist ? canonicalartist ^ "J" -> album -> title = "fmt_title"
+"K" -> canonicalartist ? canonicalartist ^ "K" -> album -> title = "fmt_title"
+"L" -> canonicalartist ? canonicalartist ^ "L" -> album -> title = "fmt_title"
+"M" -> canonicalartist ? canonicalartist ^ "M" -> album -> title = "fmt_title"
+"N" -> canonicalartist ? canonicalartist ^ "N" -> album -> title = "fmt_title"
+"O" -> canonicalartist ? canonicalartist ^ "O" -> album -> title = "fmt_title"
+"P" -> canonicalartist ? canonicalartist ^ "P" -> album -> title = "fmt_title"
+"Q" -> canonicalartist ? canonicalartist ^ "Q" -> album -> title = "fmt_title"
+"R" -> canonicalartist ? canonicalartist ^ "R" -> album -> title = "fmt_title"
+"S" -> canonicalartist ? canonicalartist ^ "S" -> album -> title = "fmt_title"
+"T" -> canonicalartist ? canonicalartist ^ "T" -> album -> title = "fmt_title"
+"U" -> canonicalartist ? canonicalartist ^ "U" -> album -> title = "fmt_title"
+"V" -> canonicalartist ? canonicalartist ^ "V" -> album -> title = "fmt_title"
+"W" -> canonicalartist ? canonicalartist ^ "W" -> album -> title = "fmt_title"
+"X" -> canonicalartist ? canonicalartist ^ "X" -> album -> title = "fmt_title"
+"Y" -> canonicalartist ? canonicalartist ^ "Y" -> album -> title = "fmt_title"
+"Z" -> canonicalartist ? canonicalartist ^ "Z" -> album -> title = "fmt_title"
# ^ An empy line ends the menu
@@ -130,12 +130,11 @@
# Define the search sub menu
%menu_start "search" "Search by..."
-"Artist" -> artist ? artist ~ "" -> album -> title = "fmt_title"
-"Album Artist" -> albumartist ? albumartist ~ "" -> album -> title = "fmt_title"
+"Artist" -> canonicalartist ? canonicalartist ~ "" -> album -> title = "fmt_title"
"Album" -> album ? album ~ "" -> title = "fmt_title"
"Title" -> title = "fmt_title" ? title ~ ""
"Album by year" -> album ? year = "" -> title = "fmt_title"
-"Artist between years" -> artist ? year >= "" & year <= "" -> album -> title = "fmt_title"
+"Artist between years" -> canonicalartist ? year >= "" & year <= "" -> album -> title = "fmt_title"
"Album between years" -> album ? year >= "" & year <= "" -> title = "fmt_title"
"Filename" -> filename ? filename ~ ""
"Score" -> title = "fmt_score" ? autoscore > ""
@@ -146,7 +145,7 @@
%menu_start "same" "Same as current"
"Directory" -> title ? filename ^ "#directory#"
"Title" -> title = "fmt_title" ? title = "#title#"
-"Artist" -> album ? artist = "#artist#" -> title = "fmt_title"
+"Artist" -> album ? artist = "#artist#" | artist = "#albumartist#" | albumartist = "#artist#" | albumartist = "#albumartist#" -> title = "fmt_title"
"Album" -> title = "fmt_title" ? album = "#album#"
"Composer" -> title = "fmt_title" ? composer = "#composer#"
@@ -154,11 +153,11 @@
%menu_start "runtime" "Play history"
"Most played (Plays|Score)" -> title = "fmt_mostplayed" ? playcount > "0"
"Recently played tracks" -> title = "fmt_lastplayed" ? playcount > "0"
-"Never played tracks" -> artist ? playcount == "0" -> album -> title = "fmt_title"
-"Favourite artists" -> artist ? playcount > "3" & autoscore > "85" -> album -> title = "fmt_best_tracks"
+"Never played tracks" -> canonicalartist ? playcount == "0" -> album -> title = "fmt_title"
+"Favourite artists" -> canonicalartist ? playcount > "3" & autoscore > "85" -> album -> title = "fmt_best_tracks"
"Favourite albums" -> album ? playcount > "3" & autoscore > "85" -> title = "fmt_best_tracks"
"Recent favourites" -> title = "fmt_lastplayed" ? playcount > "3" & autoscore > "85"
-"New favourites" -> artist ? playcount <= "3" & autoscore > "85" -> album -> title = "fmt_best_tracks"
+"New favourites" -> canonicalartist ? playcount <= "3" & autoscore > "85" -> album -> title = "fmt_best_tracks"
"Forgotten favourites" -> title = "fmt_forgotten" ? playcount > "3" & autoscore > "85"
#
@@ -167,13 +166,12 @@
# Define the title of the main menu
%menu_start "main" "Database"
-"Artist" -> artist -> album -> title = "fmt_title"
-"Album Artist" -> albumartist -> album -> title = "fmt_title"
+"Artist" -> canonicalartist -> album -> title = "fmt_title"
"Album" -> album -> title = "fmt_title"
-"Genre" -> genre -> artist -> album -> title = "fmt_title"
+"Genre" -> genre -> canonicalartist -> album -> title = "fmt_title"
"Composer" -> composer -> album -> title = "fmt_title"
"Track" -> title = "fmt_alphanum_title"
-"Year" -> year ? year > "0" -> artist -> album -> title = "fmt_title"
+"Year" -> year ? year > "0" -> canonicalartist -> album -> title = "fmt_title"
"User Rating" -> rating -> title = "fmt_title"
"Recently Added" -> album ? entryage < "4" & commitid > "0" -> title = "fmt_title"
"A to Z..." ==> "a2z"
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 4b118f6d0d..454875ded2 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -338,6 +338,7 @@ static int get_tag(int *tag)
{"filename", tag_filename},
{"basename", tag_virt_basename},
{"tracknum", tag_tracknumber},
+ {"canonicalartist", tag_virt_canonicalartist},
{"discnum", tag_discnumber},
{"year", tag_year},
{"playcount", tag_playcount},
diff --git a/apps/talk.c b/apps/talk.c
index 73191c22c3..e440dd98b5 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -1188,17 +1188,44 @@ int talk_number(long n, bool enqueue)
talk_id(VOICE_HUNDRED, true);
}
- /* combination indexing */
- if (ones > 20)
+ struct queue_entry tens_swap;
+ if (get_clip(VOICE_NUMERIC_TENS_SWAP_SEPARATOR, &tens_swap) >= 0)
{
- int tens = ones/10 + 18;
- talk_id(VOICE_ZERO + tens, true);
- ones %= 10;
+ /* direct indexing */
+ if (ones <= 20)
+ {
+ talk_id(VOICE_ZERO + ones, true);
+ }
+ else if (ones)
+ {
+ int tmp = ones % 10;
+ if (tmp)
+ {
+ talk_id(VOICE_ZERO + tmp, true);
+ talk_id(VOICE_NUMERIC_TENS_SWAP_SEPARATOR, true);
+ }
+ }
+ /* combination indexing */
+ if (ones > 20)
+ {
+ int tens = ones/10 + 18;
+ talk_id(VOICE_ZERO + tens, true);
+ }
}
+ else
+ {
+ /* combination indexing */
+ if (ones > 20)
+ {
+ int tens = ones/10 + 18;
+ talk_id(VOICE_ZERO + tens, true);
+ ones %= 10;
+ }
- /* direct indexing */
- if (ones)
- talk_id(VOICE_ZERO + ones, true);
+ /* direct indexing */
+ if (ones)
+ talk_id(VOICE_ZERO + ones, true);
+ }
/* add billion, million, thousand */
if (mil)
@@ -1215,7 +1242,7 @@ int talk_number(long n, bool enqueue)
static int talk_year(long year, bool enqueue)
{
int rem;
- if(year < 1100 || year >=2000)
+ if(year < 1100 || (year >=2000 && year < 2100))
/* just say it as a regular number */
return talk_number(year, enqueue);
/* Say century */
@@ -1469,9 +1496,30 @@ void talk_setting(const void *global_settings_variable)
void talk_date(const struct tm *tm, bool enqueue)
{
- talk_id(LANG_MONTH_JANUARY + tm->tm_mon, enqueue);
- talk_number(tm->tm_mday, true);
- talk_number(1900 + tm->tm_year, true);
+ const char *format = str(LANG_VOICED_DATE_FORMAT);
+ const char *ptr;
+
+ if (!enqueue)
+ talk_shutup(); /* cut off all the pending stuff */
+
+ for (ptr = format ; *ptr ; ptr++) {
+ switch(*ptr) {
+ case 'Y':
+ talk_number(1900 + tm->tm_year, true);
+ break;
+ case 'A':
+ talk_id(LANG_MONTH_JANUARY + tm->tm_mon, true);
+ break;
+ case 'm':
+ talk_number(tm->tm_mon + 1, true);
+ break;
+ case 'd':
+ talk_number(tm->tm_mday, true);
+ break;
+ default:
+ break;
+ }
+ }
}
void talk_time(const struct tm *tm, bool enqueue)
diff --git a/apps/tree.c b/apps/tree.c
index 1f7102dbb9..f50d424a82 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -128,7 +128,7 @@ static const char* tree_get_filename(int selected_item, void *data,
{
return tagtree_get_entry_name(&tc, selected_item, buffer, buffer_len);
}
- else
+ else
#endif
{
struct entry *entry = tree_get_entry_at(local_tc, selected_item);
@@ -137,7 +137,7 @@ static const char* tree_get_filename(int selected_item, void *data,
name = entry->name;
attr = entry->attr;
}
-
+
if(!(attr & ATTR_DIRECTORY))
{
switch(global_settings.show_filename_ext)
@@ -363,7 +363,7 @@ static int update_dir(void)
changed = true;
}
}
- else
+ else
#endif
{
tc.sort_dir = global_settings.sort_dir;
@@ -391,7 +391,7 @@ static int update_dir(void)
{
if(
#ifdef HAVE_TAGCACHE
- !id3db &&
+ !id3db &&
#endif
tc.dirfull )
{
@@ -474,7 +474,7 @@ void resume_directory(const char *dir)
#ifdef HAVE_TAGCACHE
if (!id3db)
#endif
- *tc.dirfilter = global_settings.dirfilter;
+ *tc.dirfilter = global_settings.dirfilter;
ret = ft_load(&tc, dir);
*tc.dirfilter = dirfilter;
if (ret < 0)
@@ -534,7 +534,7 @@ char* get_current_file(char* buffer, size_t buffer_len)
return NULL;
}
-/* Allow apps to change our dirfilter directly (required for sub browsers)
+/* Allow apps to change our dirfilter directly (required for sub browsers)
if they're suddenly going to become a file browser for example */
void set_dirfilter(int l_dirfilter)
{
@@ -712,7 +712,7 @@ static int dirbrowse(void)
#endif
if (ft_exit(&tc) == 3)
exit_func = true;
-
+
restore = true;
break;
@@ -976,7 +976,7 @@ int rockbox_browse(struct browse_context *browse)
browse->root, browse->selected);
set_current_file(current);
/* set_current_file changes dirlevel, change it back */
- tc.dirlevel = 0;
+ tc.dirlevel = 0;
}
ret_val = dirbrowse();
@@ -1100,7 +1100,7 @@ bool bookmark_play(char *resume_file, int index, unsigned long elapsed,
else search for it */
peek_filename = playlist_peek(index, filename_buf,
sizeof(filename_buf));
-
+
if (peek_filename == NULL)
{
/* playlist has shrunk, search from the top */
@@ -1110,7 +1110,7 @@ bool bookmark_play(char *resume_file, int index, unsigned long elapsed,
if (peek_filename == NULL)
return false;
}
-
+
if (strcmp(strrchr(peek_filename, '/') + 1, filename))
{
for ( i=0; i < playlist_amount(); i++ )
@@ -1209,7 +1209,7 @@ void tree_flush(void)
global_status.dircache_size = info.last_size;
#ifdef HAVE_EEPROM_SETTINGS
savecache = firmware_settings.initialized;
- #endif
+ #endif
}
else
{
@@ -1231,11 +1231,11 @@ void tree_restore(void)
#ifdef HAVE_EEPROM_SETTINGS
firmware_settings.disk_clean = false;
#endif
-
+
#ifdef HAVE_TC_RAMCACHE
remove(TAGCACHE_STATEFILE);
#endif
-
+
#ifdef HAVE_DIRCACHE
if (global_settings.dircache && dircache_resume() > 0)
{
diff --git a/apps/usb_keymaps.c b/apps/usb_keymaps.c
index bd72d95be8..2781fb5532 100644
--- a/apps/usb_keymaps.c
+++ b/apps/usb_keymaps.c
@@ -181,6 +181,7 @@ int get_hid_usb_action(void)
{
case ACTION_USB_HID_MODE_SWITCH_NEXT:
step = 1;
+ /* fallthrough */
case ACTION_USB_HID_MODE_SWITCH_PREV:
/* Switch key mappings in a cyclic way */
usb_keypad_mode = clamp_value_wrap(usb_keypad_mode + step,
diff --git a/apps/voice_thread.c b/apps/voice_thread.c
index 77bdd08d44..6ce0f6a408 100644
--- a/apps/voice_thread.c
+++ b/apps/voice_thread.c
@@ -361,12 +361,11 @@ static enum voice_state voice_message(struct voice_thread_data *td)
{
case Q_VOICE_PLAY:
LOGFQUEUE("voice < Q_VOICE_PLAY");
- if (quiet_counter == 0)
- {
- /* Boost CPU now */
- trigger_cpu_boost();
- }
- else
+
+ /* Boost CPU now */
+ trigger_cpu_boost();
+
+ if (quiet_counter != 0)
{
/* Stop any clip still playing */
voice_stop_playback();
diff --git a/bootloader/SOURCES b/bootloader/SOURCES
index 86dd64d7d9..b721b12ce1 100644
--- a/bootloader/SOURCES
+++ b/bootloader/SOURCES
@@ -31,8 +31,6 @@ sansaview.c
show_logo.c
main-pp.c
#endif
-#elif defined(TATUNG_TPJ1022)
-tpj1022.c
#elif defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(IAUDIO_M3)
iaudio_coldfire.c
#elif defined(IRIVER_H100_SERIES)
diff --git a/bootloader/common.c b/bootloader/common.c
index 295ebdc51b..a79b1c4d64 100644
--- a/bootloader/common.c
+++ b/bootloader/common.c
@@ -45,7 +45,7 @@
#endif
/* TODO: Other bootloaders need to be adjusted to set this variable to true
- on a button press - currently only the ipod, H10, Vibe 500 and Sansa versions do. */
+ on a button press - currently only the ipod, H10, Vibe 500, Sansa, and xDuoo x3 versions do. */
#if defined(IPOD_ARCH) || defined(IRIVER_H10) || defined(IRIVER_H10_5GB) \
|| defined(SANSA_E200) || defined(SANSA_C200) || defined(GIGABEAT_F) \
|| (CONFIG_CPU == AS3525) || (CONFIG_CPU == AS3525v2) || defined(COWON_D2) \
@@ -156,86 +156,3 @@ int load_raw_firmware(unsigned char* buf, char* firmware, int buffer_size)
close(fd);
return len;
}
-
-/* FIXME?: unused broken code */
-#if 0
-#ifdef ROCKBOX_HAS_LOGF /* Logf display helper for the bootloader */
-
-#define LINES (LCD_HEIGHT/SYSFONT_HEIGHT)
-#define COLUMNS ((LCD_WIDTH/SYSFONT_WIDTH) > MAX_LOGF_ENTRY ? \
- MAX_LOGF_ENTRY : (LCD_WIDTH/SYSFONT_WIDTH))
-
-#ifdef ONDA_VX747
-#define LOGF_UP BUTTON_VOL_UP
-#define LOGF_DOWN BUTTON_VOL_DOWN
-#define LOGF_CLEAR BUTTON_MENU
-#else
-#warning No keymap defined for this target
-#endif
-
-void display_logf(void) /* Doesn't return! */
-{
- int i, index, button, user_index=0;
-#ifdef HAVE_TOUCHSCREEN
- int touch, prev_y=0;
-#endif
- char buffer[COLUMNS+1];
-
- while(1)
- {
- index = logfindex + user_index;
-
- lcd_clear_display();
- for(i = LINES-1; i>=0; i--)
- {
- if(--index < 0)
- {
- if(logfwrap)
- index = MAX_LOGF_LINES-1;
- else
- break; /* done */
- }
-
- memcpy(buffer, logfbuffer[index], COLUMNS);
-
- if (logfbuffer[index][MAX_LOGF_ENTRY] == LOGF_TERMINATE_CONTINUE_LINE)
- buffer[MAX_LOGF_ENTRY-1] = '>';
- else if (logfbuffer[index][MAX_LOGF_ENTRY] == LOGF_TERMINATE_MULTI_LINE)
- buffer[MAX_LOGF_ENTRY-1] = '\0';
-
- buffer[COLUMNS] = '\0';
-
- lcd_puts(0, i, buffer);
- }
-
- button = button_get(false);
- if(button == SYS_USB_CONNECTED)
- usb_acknowledge(SYS_USB_CONNECTED_ACK);
- else if(button == SYS_USB_DISCONNECTED)
- ;
- else if(button & LOGF_UP)
- user_index++;
- else if(button & LOGF_DOWN)
- user_index--;
- else if(button & LOGF_CLEAR)
- user_index = 0;
-#ifdef HAVE_TOUCHSCREEN
- else if(button & BUTTON_TOUCHSCREEN)
- {
- touch = button_get_data();
-
- if(button & BUTTON_REL)
- prev_y = 0;
-
- if(prev_y != 0)
- user_index += (prev_y - (touch & 0xFFFF)) / SYSFONT_HEIGHT;
- prev_y = touch & 0xFFFF;
- }
-#endif
-
- lcd_update();
- sleep(HZ/16);
- }
-}
-#endif
-#endif
diff --git a/bootloader/main-pp.c b/bootloader/main-pp.c
index 08b5ea3ef5..15f6ad4fb7 100644
--- a/bootloader/main-pp.c
+++ b/bootloader/main-pp.c
@@ -51,6 +51,9 @@
#if defined(SANSA_E200) || defined(SANSA_C200) || defined(PHILIPS_SA9200)
#include "usb_drv.h"
#endif
+#if defined(SANSA_E200) && defined(HAVE_BOOTLOADER_USB_MODE)
+#include "core_alloc.h"
+#endif
#if defined(SAMSUNG_YH925)
/* this function (in lcd-yh925.c) resets the screen orientation for the OF
* for use with dualbooting */
@@ -231,7 +234,18 @@ static int handle_usb(int connect_timeout)
usb = USB_HANDLED;
usb_acknowledge(SYS_USB_CONNECTED_ACK);
+#if defined(SANSA_E200) && defined(HAVE_BOOTLOADER_USB_MODE)
+ /* E200 misses unplug randomly
+ probably fine for other targets too but needs tested */
+ while (usb_wait_for_disconnect_w_tmo(&q, HZ * 5) > 0)
+ {
+ /* timeout */
+ if (!usb_plugged())
+ break;
+ }
+#else
usb_wait_for_disconnect(&q);
+#endif
break;
}
@@ -299,6 +313,9 @@ void* main(void)
int usb = USB_EXTRACTED;
system_init();
+#if defined(SANSA_E200) && defined(HAVE_BOOTLOADER_USB_MODE)
+ core_allocator_init();
+#endif
kernel_init();
#ifdef HAVE_BOOTLOADER_USB_MODE
diff --git a/bootloader/tpj1022.c b/bootloader/tpj1022.c
deleted file mode 100644
index 3590c7882d..0000000000
--- a/bootloader/tpj1022.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id$
- *
- * Copyright (C) 2006 by Dave Chapman
- *
- * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "cpu.h"
-#include "system.h"
-#include "lcd.h"
-#include "kernel.h"
-#include "thread.h"
-#include "storage.h"
-#include "file_internal.h"
-#include "disk.h"
-#include "font.h"
-#include "panic.h"
-#include "power.h"
-#include "file.h"
-#include "common.h"
-
-void* main(void)
-{
- int i;
- int rc;
- int fd;
- char buffer[80];
- unsigned char* framebuffer = (unsigned char*)0x11e00000;
-
-#if 0
- lcd_init();
- font_init();
-
- printf("Hello World!");
-#endif
-
- i=storage_init();
-
- filesystem_init();
- rc = disk_mount_all();
-
-#if 0
- /* Dump the flash */
- fd=open("/flash.bin",O_CREAT|O_RDWR, 0666);
- write(fd,(char*)0,1024*1024);
- close(fd);
-#endif
-
-#if 1
- /* Dump what may be the framebuffer */
- fd=open("/framebuffer.bin",O_CREAT|O_RDWR|O_TRUNC, 0666);
- write(fd,framebuffer,220*176*4);
- close(fd);
-#endif
-
-
- fd=open("/gpio.txt",O_CREAT|O_RDWR|O_TRUNC, 0666);
- unsigned int gpio_a = GPIOA_INPUT_VAL;
- unsigned int gpio_b = GPIOB_INPUT_VAL;
- unsigned int gpio_c = GPIOC_INPUT_VAL;
- unsigned int gpio_d = GPIOD_INPUT_VAL;
- unsigned int gpio_e = GPIOE_INPUT_VAL;
- unsigned int gpio_f = GPIOF_INPUT_VAL;
- unsigned int gpio_g = GPIOG_INPUT_VAL;
- unsigned int gpio_h = GPIOH_INPUT_VAL;
- unsigned int gpio_i = GPIOI_INPUT_VAL;
- unsigned int gpio_j = GPIOJ_INPUT_VAL;
- unsigned int gpio_k = GPIOK_INPUT_VAL;
- unsigned int gpio_l = GPIOL_INPUT_VAL;
-
- snprintf(buffer, sizeof(buffer), "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",gpio_a,gpio_b,gpio_c,gpio_d,gpio_e,gpio_f,gpio_g,gpio_h,gpio_i,gpio_j,gpio_k,gpio_l);
- write(fd,buffer,strlen(buffer)+1);
- close(fd);
-
- /* Wait for FFWD button to be pressed */
- while((GPIOA_INPUT_VAL & 0x04) != 0);
-
-
- /* Now reboot */
- DEV_RS |= 0x4;
-
- return 0;
-}
diff --git a/bootloader/xduoox3.c b/bootloader/xduoox3.c
index d38639bfd4..ff6b81aa25 100644
--- a/bootloader/xduoox3.c
+++ b/bootloader/xduoox3.c
@@ -26,7 +26,9 @@
#include "font.h"
#include "lcd.h"
#include "file.h"
+#ifdef HAVE_BOOTLOADER_USB_MODE
#include "usb.h"
+#endif
#include "system.h"
#include "button.h"
#include "common.h"
@@ -41,12 +43,33 @@
#include "xdebug.h"
+#define SHOW_LOGO
+
extern void show_logo(void);
extern void power_off(void);
+static int lcd_inited = 0;
+void init_lcd(void)
+{
+ if(lcd_inited)
+ return;
+
+ lcd_init();
+ font_init();
+ lcd_setfont(FONT_SYSFIXED);
+
+ lcd_clear_display();
+ lcd_update();
+
+ backlight_init();
+
+ lcd_inited = true;
+}
+
#ifdef HAVE_BOOTLOADER_USB_MODE
static void show_splash(int timeout, const char *msg)
{
+ init_lcd();
reset_screen();
lcd_putsxy( (LCD_WIDTH - (SYSFONT_WIDTH * strlen(msg))) / 2,
(LCD_HEIGHT - SYSFONT_HEIGHT) / 2, msg);
@@ -55,74 +78,84 @@ static void show_splash(int timeout, const char *msg)
sleep(timeout);
}
+static int usb_inited = 0;
+
static void usb_mode(void)
{
- int button;
+ int button = 0;
- /* Init USB */
- usb_init();
- usb_start_monitoring();
+ /* Init USB, but only once */
+ if (!usb_inited) {
+ usb_init();
+ usb_start_monitoring();
+ usb_inited = 1;
+ }
- /* Wait for threads to connect */
- show_splash(HZ/2, "Waiting for USB");
+ init_lcd();
+ reset_screen();
- while (1)
- {
+ /* Wait for USB */
+ show_splash(0, "Waiting for USB");
+ while(1) {
button = button_get_w_tmo(HZ/2);
-
+ if (button == BUTTON_POWER)
+ return;
if (button == SYS_USB_CONNECTED)
break; /* Hit */
}
- if (button == SYS_USB_CONNECTED)
- {
- /* Got the message - wait for disconnect */
- show_splash(0, "Bootloader USB mode");
+ /* Got the message - wait for disconnect */
+ show_splash(0, "Bootloader USB mode");
- usb_acknowledge(SYS_USB_CONNECTED_ACK);
+ usb_acknowledge(SYS_USB_CONNECTED_ACK);
- while (1)
- {
- button = button_get(true);
- if (button == SYS_USB_DISCONNECTED)
- break;
- }
+ while(1) {
+ button = button_get_w_tmo(HZ/2);
+ if (button == SYS_USB_DISCONNECTED)
+ break;
}
+
+ show_splash(HZ*2, "USB disconnected");
}
#endif
+/* Jump to loaded binary */
+void exec(void* addr) __attribute__((noinline, noreturn, section(".icode")));
+
+void exec(void* addr)
+{
+ commit_discard_idcache();
+ typedef void(*entry_fn)(void) __attribute__((noreturn));
+ entry_fn fn = (entry_fn)addr;
+ fn();
+}
+
static int boot_rockbox(void)
{
int rc;
- void (*kernel_entry)(void);
- printf("Mounting disk...\n");
+ printf("Mounting disk...");
- while((rc = disk_mount_all()) <= 0)
- {
+ while((rc = disk_mount_all()) <= 0) {
verbose = true;
#ifdef HAVE_BOOTLOADER_USB_MODE
error(EDISK, rc, false);
- usb_start_monitoring();
usb_mode();
#else
error(EDISK, rc, true);
#endif
}
- printf("Loading firmware...\n");
+ printf("Loading firmware...");
rc = load_firmware((unsigned char *)CONFIG_SDRAM_START, BOOTFILE, 0x400000);
- if(rc <= EFILE_EMPTY)
+ if(rc <= EFILE_EMPTY) {
+ printf("!! " BOOTFILE);
return rc;
- else
- {
- printf("Starting Rockbox...\n");
+ } else {
+ printf("Starting Rockbox...");
adc_close(); /* Disable SADC, seems to fix the re-init Rockbox does */
-
disable_interrupt();
- kernel_entry = (void*) CONFIG_SDRAM_START;
- kernel_entry();
-
+ exec((void*) CONFIG_SDRAM_START);
return 0; /* Shouldn't happen */
}
}
@@ -152,18 +185,24 @@ int main(void)
serial_puts("\n\nSPL Stage 2\n\n");
+ system_init();
kernel_init();
- lcd_init();
- font_init();
- lcd_setfont(FONT_SYSFIXED);
- button_init();
- backlight_init();
+ init_lcd();
+#ifdef SHOW_LOGO
show_logo();
+#endif
+
+ button_init();
+ enable_irq();
+
+ int btn = button_read_device();
+ if(btn & BUTTON_POWER) {
+ verbose = true;
+ }
rc = storage_init();
- if(rc)
- {
+ if(rc) {
verbose = true;
error(EATA, rc, true);
}
@@ -171,38 +210,28 @@ int main(void)
filesystem_init();
#ifdef HAVE_BOOTLOADER_USB_MODE
- button_init_device();
- int btn = button_read_device();
-
- usb_init();
-
- /* Enter USB mode if USB is plugged and PLAY button is pressed */
- if(btn & BUTTON_PLAY) {
- usb_start_monitoring();
- if(usb_detect() == USB_INSERTED)
- usb_mode();
+ /* Enter USB mode if USB is plugged and POWER button is pressed */
+ if (btn & BUTTON_POWER) {
+ usb_mode();
+ reset_screen();
}
#endif /* HAVE_BOOTLOADER_USB_MODE */
- /* Don't mount the disks yet, there could be file system/partition errors
- which are fixable in USB mode */
-
- reset_screen();
-
- printf(MODEL_NAME" Rockbox Bootloader\n");
- printf("Version %s\n", rbversion);
+#ifndef SHOW_LOGO
+ printf(MODEL_NAME" Rockbox Bootloader");
+ printf("Version %s", rbversion);
+#endif
rc = boot_rockbox();
- if(rc <= EFILE_EMPTY)
- {
+ if(rc <= EFILE_EMPTY) {
verbose = true;
printf("Error: %s", loader_strerror(rc));
}
- /* Halt */
- while (1)
- core_idle();
+ /* Power off */
+ sleep(5*HZ);
+ power_off();
return 0;
}
diff --git a/docs/CREDITS b/docs/CREDITS
index 613aa1f660..d6b2a315f8 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -707,6 +707,7 @@ Spencer Brennessel
Dana Conrad
Albert Song
Marc Aarts
+Fabrice Bellard
The libmad team
The wavpack team
diff --git a/docs/usb-api.md b/docs/usb-api.md
new file mode 100644
index 0000000000..a21d6fd703
--- /dev/null
+++ b/docs/usb-api.md
@@ -0,0 +1,144 @@
+Handling USB control requests
+=============================
+
+API overview
+------------
+
+ enum usb_control_response {
+ USB_CONTROL_ACK,
+ USB_CONTROL_STALL,
+ USB_CONTROL_RECEIVE,
+ };
+
+ void usb_core_control_request(struct usb_ctrlrequest* req, void* reqdata);
+ void usb_core_control_complete(int status);
+ void usb_drv_control_response(enum usb_control_response resp,
+ void* data, int length);
+
+The two `usb_core` functions are common to all targets with a USB stack and
+are implemented in `usb_core.c`. The USB driver calls them to inform the core
+when a control request arrives or is completed.
+
+Each USB driver implements `usb_drv_control_response()`. The core calls this
+to let the driver know how to respond to each control request.
+
+### Legacy API
+
+ void usb_core_legacy_control_request(struct usb_ctrlrequest* req);
+
+The old control request API is available through this function. Drivers which
+don't yet implement the new API can use the legacy API instead. To support
+legacy drivers, the USB core implements all functions in the new API and
+emulates the old control request handling behavior, bugs included.
+
+This is intended as a stopgap measure so that old drivers keep working as-is.
+The core can start using the new API right away, and drivers can be ported
+one-by-one as time allows. Once all drivers are ported to the new API, all
+legacy driver support can be removed.
+
+Request handling process
+------------------------
+
+The driver submits control requests to the USB core one at a time. Once a
+request is submitted, it must be completed before the next request can be
+submitted. This mirrors normal USB operation.
+
+When the USB driver receives a setup packet from the host, it submits it
+to the core to begin handling the control transfer. The driver calls
+`usb_core_control_request(req, NULL)`, passing the setup packet in `req`.
+The second argument, `reqdata`, is not used at this time and is passed
+as `NULL`.
+
+The core processes the setup packet and calls `usb_drv_control_response()`
+when it's done. The allowed responses depend on the type of control transfer
+being processed.
+
+### Non-data transfers
+
+- `USB_CONTROL_ACK`, to indicate the request was processed successfully.
+- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
+
+### Control read transfers
+
+- `USB_CONTROL_ACK`, to indicate the request was processed successfully.
+ The core must provide a valid `data` buffer with `length` not exceeding
+ the `wLength` field in the setup packet; otherwise, driver behavior is
+ undefined. The driver will transfer this data to the host during the
+ data phase of the control transfer, and then acknowledge the host's OUT
+ packet to complete the transfer successfully.
+- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
+
+### Control write transfers
+
+The driver calls `usb_core_control_request()` twice to handle control writes.
+The first call allows the core to handle the setup packet, and if the core
+decides to accept the data phase, the second call is made when the data has
+been received without error.
+
+#### Setup phase
+
+The first call is made at the end of the setup phase, after receiving the
+setup packet. The driver passes `reqdata = NULL` to indicate this.
+
+The core can decide whether it wants to receive the data phase:
+
+- `USB_CONTROL_RECEIVE`, if the core wishes to continue to the data phase.
+ The core must provide a valid `data` buffer with `length` greater than or
+ equal to the `wLength` specified in the setup packet; otherwise, driver
+ behavior is undefined. The driver will proceed to the data phase and store
+ received data into the provided buffer.
+- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
+
+If the core accepts the data phase, the driver will re-submit the request
+when the data phase is completed correctly. If any error occurs during the
+data phase, the driver will not re-submit the request; instead, it will
+call `usb_core_control_complete()` with a non-zero status code.
+
+#### Status phase
+
+The second call to `usb_core_control_request()` is made at the end of the data
+phase. The `reqdata` passed by the driver is the same one that the core passed
+in its `USB_CONTROL_RECEIVE` response.
+
+The core's allowed responses are:
+
+- `USB_CONTROL_ACK`, to indicate the request was processed successfully.
+- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
+
+### Request completion
+
+The driver will notify the core when a request has completed by calling
+`usb_core_control_complete()`. A status code of zero means the request was
+completed successfully; a non-zero code means it failed. Note that failure
+can occur even if the request was successful from the core's perspective.
+
+If the core response is `USB_CONTROL_STALL` at any point, the request is
+considered complete. In this case, the driver won't deliver a completion
+notification because it would be redundant.
+
+The driver may only complete a request after the core has provided a response
+to any pending `usb_core_control_request()` call. Specifically, if the core
+has not yet responded to a request, the driver needs to defer the completion
+notification until it sees the core's response. If the core's response is a
+stall, then the notification should be silently dropped.
+
+### Notes
+
+- Driver behavior is undefined if the core makes an inappropriate response
+ to a request, for example, responding with `USB_CONTROL_ACK` in the setup
+ phase of a control write or `USB_CONTROL_RECEIVE` to a non-data request.
+ The only permissible responses are the documented ones.
+
+- If a response requires a buffer, then `data` must be non-NULL unless the
+ `length` is also zero. If a buffer is not required, the core must pass
+ `data = NULL` and `length = 0`. Otherwise, driver behavior is undefined.
+ There are two responses which require a buffer:
+ + `USB_CONTROL_ACK` to a control read
+ + `USB_CONTROL_RECEIVE` to the setup phase of a control write
+
+- Drivers must be prepared to accept a setup packet at any time, including
+ in the middle of a control request. In such a case, devices are required
+ to abort the ongoing request and start handling the new request. (This is
+ intended as an error recovery mechanism and should not be abused by hosts
+ in normal operation.) The driver must take care to notify the core of the
+ current request's failure, and then submit the new request.
diff --git a/firmware/SOURCES b/firmware/SOURCES
index fc194fe640..87db67d8fd 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -269,6 +269,8 @@ common/timefuncs.c
common/unicode.c
common/vuprintf.c
common/zip.c
+common/adler32.c
+common/inflate.c
/* Display */
scroll_engine.c
@@ -1299,14 +1301,6 @@ target/arm/olympus/mrobe-100/power-mr100.c
target/arm/olympus/mrobe-100/powermgmt-mr100.c
#endif /* MROBE_100 */
-#ifdef TATUNG_TPJ1022
-target/arm/tatung/tpj1022/backlight-tpj1022.c
-target/arm/tatung/tpj1022/button-tpj1022.c
-target/arm/tatung/tpj1022/lcd-tpj1022.c
-target/arm/tatung/tpj1022/power-tpj1022.c
-target/arm/tatung/tpj1022/powermgmt-tpj1022.c
-#endif /* TATUNG_TPJ1022 */
-
#ifdef IPOD_4G
target/arm/ipod/backlight-4g_color.c
target/arm/ipod/button-clickwheel.c
@@ -1448,17 +1442,6 @@ target/arm/imx233/sansa-fuzeplus/debug-fuzeplus.c
target/arm/imx233/sansa-fuzeplus/powermgmt-fuzeplus.c
#endif
-#ifdef SAMSUNG_YPZ5
-target/arm/imx233/samsung-ypz5/backlight-ypz5.c
-target/arm/imx233/samsung-ypz5/lcd-ypz5.c
-target/arm/imx233/samsung-ypz5/button-ypz5.c
-target/arm/imx233/samsung-ypz5/debug-ypz5.c
-target/arm/imx233/samsung-ypz5/powermgmt-ypz5.c
-#ifndef BOOTLOADER
-target/arm/imx233/fmradio-imx233.c
-#endif
-#endif
-
#ifdef SANSA_CLIPZIP
target/arm/as3525/sansa-clipzip/lcd-clipzip.c
target/arm/as3525/sansa-clipzip/button-clipzip.c
diff --git a/firmware/common/adler32.c b/firmware/common/adler32.c
new file mode 100644
index 0000000000..419eb02e44
--- /dev/null
+++ b/firmware/common/adler32.c
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2021 James Buren (adaptations from tinf/zlib)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/* Copyright (c) 2003-2019 Joergen Ibsen
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ * not claim that you wrote the original software. If you use this
+ * software in a product, an acknowledgment in the product
+ * documentation would be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must
+ * not be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ */
+
+#include "adler32.h"
+#include "system.h"
+
+/* adler_32 (derived from tinf adler32 which was taken from zlib)
+ * Adler-32 algorithm taken from the zlib source, which is
+ * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+ */
+uint32_t adler_32(const void *src, uint32_t len, uint32_t adler32)
+{
+ const unsigned char *buf = (const unsigned char *)src;
+ uint32_t s1 = (adler32 & 0xffff);
+ uint32_t s2 = (adler32 >> 16);
+
+ enum {
+ A32_BASE = 65521,
+ A32_NMAX = 5552,
+ };
+
+ while (len > 0) {
+ uint32_t k = MIN(len, A32_NMAX);
+ uint32_t i;
+
+ for (i = k / 16; i; --i, buf += 16) {
+ s2 += s1 += buf[0];
+ s2 += s1 += buf[1];
+ s2 += s1 += buf[2];
+ s2 += s1 += buf[3];
+ s2 += s1 += buf[4];
+ s2 += s1 += buf[5];
+ s2 += s1 += buf[6];
+ s2 += s1 += buf[7];
+ s2 += s1 += buf[8];
+ s2 += s1 += buf[9];
+ s2 += s1 += buf[10];
+ s2 += s1 += buf[11];
+ s2 += s1 += buf[12];
+ s2 += s1 += buf[13];
+ s2 += s1 += buf[14];
+ s2 += s1 += buf[15];
+ }
+
+ for (i = k % 16; i; --i) {
+ s1 += *buf++;
+ s2 += s1;
+ }
+
+ s1 %= A32_BASE;
+ s2 %= A32_BASE;
+
+ len -= k;
+ }
+
+ return (s1 | (s2 << 16));
+}
diff --git a/firmware/common/crc32.c b/firmware/common/crc32.c
index d4c7cfb795..c8ed8f5350 100644
--- a/firmware/common/crc32.c
+++ b/firmware/common/crc32.c
@@ -19,6 +19,28 @@
*
****************************************************************************/
+/* Copyright (c) 2003-2019 Joergen Ibsen
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ * not claim that you wrote the original software. If you use this
+ * software in a product, an acknowledgment in the product
+ * documentation would be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must
+ * not be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ */
+
#include "crc32.h"
#include "config.h"
diff --git a/firmware/common/disk.c b/firmware/common/disk.c
index 51d033b678..c096878e86 100644
--- a/firmware/common/disk.c
+++ b/firmware/common/disk.c
@@ -174,6 +174,13 @@ int disk_mount(int drive)
int volume = get_free_volume();
+ if (volume < 0)
+ {
+ DEBUGF("No Free Volumes\n");
+ disk_writer_unlock();
+ return 0;
+ }
+
if (!disk_init(IF_MD(drive)))
{
disk_writer_unlock();
diff --git a/firmware/common/file_internal.c b/firmware/common/file_internal.c
index fe18f90056..b92c4ea115 100644
--- a/firmware/common/file_internal.c
+++ b/firmware/common/file_internal.c
@@ -75,13 +75,15 @@ void file_cache_alloc(struct filestr_cache *cachep)
/* free resources attached to the cache */
void file_cache_free(struct filestr_cache *cachep)
{
- if (cachep && cachep->buffer)
+ if (cachep)
{
- dc_release_buffer(cachep->buffer);
- cachep->buffer = NULL;
+ if(cachep->buffer)
+ {
+ dc_release_buffer(cachep->buffer);
+ cachep->buffer = NULL;
+ }
+ file_cache_reset(cachep);
}
-
- file_cache_reset(cachep);
}
@@ -647,6 +649,7 @@ int open_stream_internal(const char *path, unsigned int callflags,
{
case WALK_RC_FOUND_ROOT:
IF_MV( rc = rootrc; )
+ /* fallthrough */
case WALK_RC_NOT_FOUND:
case WALK_RC_FOUND:
/* FF_PROBE leaves nothing for caller to clean up */
diff --git a/firmware/common/inflate.c b/firmware/common/inflate.c
new file mode 100644
index 0000000000..26fd191690
--- /dev/null
+++ b/firmware/common/inflate.c
@@ -0,0 +1,759 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2021 by James Buren (libflate adaptations for RockBox)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/* Copyright 2021 Plan 9 Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "inflate.h"
+#include <stdbool.h>
+#include "adler32.h"
+#include "crc32.h"
+#include "system.h"
+
+enum {
+ INFLATE_BUFFER_SIZE = 32768,
+ INFLATE_SYMBOL_MAX = 288,
+ INFLATE_OFFSET_MAX = 32,
+ INFLATE_CODELEN_MAX = 19,
+ INFLATE_HUFF_BITS = 17,
+ INFLATE_FLAT_BITS = 7,
+ INFLATE_SYMBOL_BITS = 7,
+ INFLATE_OFFSET_BITS = 6,
+ INFLATE_CODELEN_BITS = 6,
+};
+
+struct inflate_huff {
+ uint32_t max_bits;
+ uint32_t min_bits;
+ uint32_t flat_mask;
+ uint32_t flat[1 << INFLATE_FLAT_BITS];
+ uint32_t max_code[INFLATE_HUFF_BITS];
+ uint32_t last[INFLATE_HUFF_BITS];
+ uint32_t decode[INFLATE_SYMBOL_MAX];
+};
+
+struct inflate {
+ uint8_t in[INFLATE_BUFFER_SIZE];
+ uint8_t out[INFLATE_BUFFER_SIZE];
+ union {
+ struct {
+ uint8_t len[INFLATE_SYMBOL_MAX];
+ uint8_t off[INFLATE_OFFSET_MAX];
+ };
+ uint8_t combo[INFLATE_SYMBOL_MAX + INFLATE_OFFSET_MAX];
+ };
+ uint8_t clen[INFLATE_CODELEN_MAX];
+ struct inflate_huff lentab;
+ struct inflate_huff offtab;
+ struct inflate_huff clentab;
+ uint32_t bits[INFLATE_HUFF_BITS];
+ uint32_t codes[INFLATE_HUFF_BITS];
+};
+
+#define INFLATE_FILL(E) do { \
+ const uint32_t _size = read(is, sizeof(it->in), rctx); \
+ if (_size == 0) { \
+ rv = (E); \
+ goto bail; \
+ } \
+ ip = is; \
+ ie = is + _size; \
+} while (0)
+
+#define INFLATE_FLUSH(E) do { \
+ const uint32_t _size = (op - os); \
+ if (write(os, _size, wctx) != _size) { \
+ rv = (E); \
+ goto bail; \
+ } \
+ flushed = true; \
+ if (st == INFLATE_ZLIB) \
+ chksum = adler_32(os, _size, chksum); \
+ else if (st == INFLATE_GZIP) \
+ chksum = crc_32r(os, _size, chksum); \
+ op = os; \
+} while (0)
+
+#define INFLATE_GET_BYTE(E,C) do { \
+ if (ip == ie) \
+ INFLATE_FILL(E); \
+ (C) = ip[0]; \
+ ++ip; \
+} while (0)
+
+#define INFLATE_PUT_BYTE(E,B) do { \
+ if (op == oe) \
+ INFLATE_FLUSH(E); \
+ op[0] = (B); \
+ ++op; \
+} while (0)
+
+#define INFLATE_FILL_BITS(E,N) do { \
+ while ((N) > nbits) { \
+ uint8_t _byte; \
+ INFLATE_GET_BYTE(E, _byte); \
+ sreg |= (_byte << nbits); \
+ nbits += 8; \
+ } \
+} while (0)
+
+#define INFLATE_CONSUME_BITS(N) do { \
+ sreg >>= (N); \
+ nbits -= (N); \
+} while (0)
+
+#define INFLATE_EXTRACT_BITS(N,B) do { \
+ (B) = (sreg & ((1 << (N)) - 1)); \
+ INFLATE_CONSUME_BITS(N); \
+} while (0)
+
+#define INFLATE_CHECK_LENGTH(E,N) do { \
+ if ((N) > (ie - ip)) { \
+ rv = (E); \
+ goto bail; \
+ } \
+} while (0)
+
+#define INFLATE_REVERSE(C,B) ({ \
+ uint32_t _c = (C); \
+ _c <<= (16 - (B)); \
+ ((revtab[_c >> 8]) | (revtab[_c & 0xff] << 8)); \
+})
+
+#define INFLATE_DECODE(E,H) ({ \
+ __label__ _found; \
+ uint32_t _c = (H)->flat[sreg & (H)->flat_mask]; \
+ uint32_t _b = (_c & 0xff); \
+ uint32_t _code; \
+ if (_b == 0xff) { \
+ for (_b = (_c >> 8); _b <= (H)->max_bits; _b++) { \
+ _c = (revtab[sreg & 0xff] << 8); \
+ _c |= (revtab[(sreg >> 8) & 0xff]); \
+ _c >>= (16 - _b); \
+ if (_c <= (H)->max_code[_b]) { \
+ _code = (H)->decode[(H)->last[_b] - _c]; \
+ goto _found; \
+ } \
+ } \
+ rv = (E); \
+ goto bail; \
+ } \
+ _code = (_c >> 8); \
+_found: \
+ INFLATE_CONSUME_BITS(_b); \
+ _code; \
+})
+
+static int inflate_blocks(struct inflate* it, int st, inflate_reader read, void* rctx, inflate_writer write, void* wctx) {
+ int rv = 0;
+ uint8_t* is = it->in;
+ uint8_t* ip;
+ uint8_t* ie;
+ uint8_t* os = it->out;
+ uint8_t* op = os;
+ uint8_t* oe = os + sizeof(it->out);
+ bool flushed = false;
+ uint32_t chksum;
+ uint32_t nbits = 0;
+ uint32_t sreg = 0;
+ uint32_t i;
+ uint32_t j;
+ bool final;
+ uint8_t type;
+
+ INFLATE_FILL(-1);
+
+ if (st == INFLATE_ZLIB) {
+ uint16_t header;
+
+ INFLATE_CHECK_LENGTH(-2, 2);
+
+ header = (ip[0] << 8 | ip[1]);
+ ip += 2;
+
+ if ((header % 31) != 0) {
+ rv = -3;
+ goto bail;
+ }
+
+ if (((header & 0xf000) >> 12) > 7) {
+ rv = -4;
+ goto bail;
+ }
+
+ if (((header & 0x0f00) >> 8) != 8) {
+ rv = -5;
+ goto bail;
+ }
+
+ if (((header & 0x0020) >> 5) != 0) {
+ rv = -6;
+ goto bail;
+ }
+
+ chksum = 1;
+ } else if (st == INFLATE_GZIP) {
+ uint8_t flg;
+
+ INFLATE_CHECK_LENGTH(-7, 10);
+
+ if (ip[0] != 0x1f || ip[1] != 0x8b) {
+ rv = -8;
+ goto bail;
+ }
+
+ if (ip[2] != 8) {
+ rv = -9;
+ goto bail;
+ }
+
+ flg = ip[3];
+
+ if ((flg & 0xe0) != 0) {
+ rv = -10;
+ goto bail;
+ }
+
+ ip += 10;
+ chksum = 0xffffffff;
+
+ if ((flg & 0x04) != 0) {
+ uint16_t xlen;
+
+ INFLATE_CHECK_LENGTH(-11, 2);
+
+ xlen = (ip[0] | ip[1] << 8);
+ ip += 2;
+
+ while (xlen >= (ie - ip)) {
+ xlen -= (ie - ip);
+
+ if ((flg & 0x02) != 0)
+ chksum = crc_32r(is, ie - is, chksum);
+
+ INFLATE_FILL(-12);
+ }
+
+ ip += xlen;
+ }
+
+ if ((flg & 0x08) != 0) {
+ while (ip++[0] != '\0') {
+ if (ip == ie) {
+ if ((flg & 0x02) != 0)
+ chksum = crc_32r(is, ie - is, chksum);
+
+ INFLATE_FILL(-13);
+ }
+ }
+ }
+
+ if ((flg & 0x10) != 0) {
+ while (ip++[0] != '\0') {
+ if (ip == ie) {
+ if ((flg & 0x02) != 0)
+ chksum = crc_32r(is, ie - is, chksum);
+
+ INFLATE_FILL(-14);
+ }
+ }
+ }
+
+ if ((flg & 0x02) != 0) {
+ uint16_t crc16;
+
+ INFLATE_CHECK_LENGTH(-15, 2);
+
+ crc16 = (ip[0] | ip[1] << 8);
+ chksum = crc_32r(is, ip - is, chksum);
+ chksum &= 0xffff;
+ chksum ^= 0xffff;
+
+ if (crc16 != chksum) {
+ rv = -16;
+ goto bail;
+ }
+
+ ip += 2;
+ }
+
+ chksum = 0xffffffff;
+ } else {
+ chksum = 0;
+ }
+
+ do {
+ INFLATE_FILL_BITS(-17, 3);
+ final = (sreg & 0x01);
+ type = ((sreg & 0x06) >> 1);
+ INFLATE_CONSUME_BITS(3);
+
+ if (type == 0) {
+ uint8_t header[4];
+ uint32_t len;
+ uint32_t clen;
+
+ INFLATE_CONSUME_BITS(nbits & 0x07);
+
+ for (i = 0; i < 4; i++) {
+ if (nbits != 0)
+ INFLATE_EXTRACT_BITS(8, header[i]);
+ else
+ INFLATE_GET_BYTE(-18, header[i]);
+ }
+
+ len = (header[0] | (header[1] << 8));
+ clen = (header[2] | (header[3] << 8)) ^ 0xffff;
+
+ if (len != clen) {
+ rv = -19;
+ goto bail;
+ }
+
+ while (len != 0) {
+ if (ip == ie)
+ INFLATE_FILL(-20);
+
+ if (op == oe)
+ INFLATE_FLUSH(-21);
+
+ j = MIN(len, MIN((uint32_t) (ie - ip), (uint32_t) (oe - op)));
+ for (i = 0; i < j; i++)
+ op[i] = ip[i];
+
+ len -= j;
+ ip += j;
+ op += j;
+ }
+ } else if (type == 3) {
+ rv = -22;
+ goto bail;
+ } else {
+ static const uint8_t revtab[256] =
+ {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+ };
+ uint8_t* tab[3];
+ uint32_t tab_lens[3];
+ uint32_t tab_bits[3];
+ struct inflate_huff* tab_huffs[3] = { &it->lentab, &it->offtab, &it->clentab, };
+ uint32_t c;
+ uint32_t k;
+
+ if (type == 2) {
+ static const uint32_t min_tab_sizes[3] = { 257, 1, 4, };
+ static const uint32_t min_tab_bits[3] = { 5, 5, 4, };
+ static const uint32_t clen_order[INFLATE_CODELEN_MAX] = {
+ 16, 17, 18, 0, 8,
+ 7, 9, 6, 10, 5,
+ 11, 4, 12, 3, 13,
+ 2, 14, 1, 15,
+ };
+
+ INFLATE_FILL_BITS(-23, 14);
+ for (i = 0; i < 3; i++) {
+ INFLATE_EXTRACT_BITS(min_tab_bits[i], tab_lens[i]);
+ tab_lens[i] += min_tab_sizes[i];
+ }
+
+ tab[2] = it->clen;
+ for (i = 0; i < INFLATE_CODELEN_MAX; i++)
+ tab[2][i] = 0;
+ for (i = 0; i < tab_lens[2]; i++) {
+ INFLATE_FILL_BITS(-24, 3);
+ INFLATE_EXTRACT_BITS(3, tab[2][clen_order[i]]);
+ }
+
+ tab[0] = it->combo;
+ tab_bits[0] = INFLATE_SYMBOL_BITS;
+
+ tab[1] = tab[0] + tab_lens[0];
+ tab_bits[1] = INFLATE_OFFSET_BITS;
+
+ tab_lens[2] = INFLATE_CODELEN_MAX;
+ tab_bits[2] = INFLATE_CODELEN_BITS;
+ } else {
+ tab[0] = it->len;
+ for (i = 0; i < 144; i++)
+ tab[0][i] = 8;
+ for (; i < 256; i++)
+ tab[0][i] = 9;
+ for (; i < 280; i++)
+ tab[0][i] = 7;
+ for (; i < INFLATE_SYMBOL_MAX; i++)
+ tab[0][i] = 8;
+ tab_lens[0] = INFLATE_SYMBOL_MAX;
+ tab_bits[0] = INFLATE_FLAT_BITS;
+
+ tab[1] = it->off;
+ for (i = 0; i < INFLATE_OFFSET_MAX; i++)
+ tab[1][i] = 5;
+ tab_lens[1] = INFLATE_OFFSET_MAX;
+ tab_bits[1] = INFLATE_FLAT_BITS;
+ }
+
+ for(; type != 0xff; --type) {
+ const uint8_t* hb = tab[type];
+ uint32_t hb_len = tab_lens[type];
+ uint32_t flat_bits = tab_bits[type];
+ struct inflate_huff* h = tab_huffs[type];
+ uint32_t* bits = it->bits;
+ uint32_t* codes = it->codes;
+ uint32_t max_bits = 0;
+ uint32_t min_bits = INFLATE_HUFF_BITS + 1;
+ uint32_t min_code;
+ uint32_t b;
+ uint32_t code;
+ uint32_t fc;
+ uint32_t ec;
+
+ for (i = 0; i < INFLATE_HUFF_BITS; i++)
+ bits[i] = 0;
+
+ for (i = 0; i < hb_len; i++) {
+ b = hb[i];
+
+ if (b != 0) {
+ bits[b]++;
+
+ if (b < min_bits)
+ min_bits = b;
+
+ if (b > max_bits)
+ max_bits = b;
+ }
+ }
+
+ if (max_bits == 0) {
+ h->flat_mask = h->min_bits = h->max_bits = 0;
+ goto table_done;
+ }
+
+ h->max_bits = max_bits;
+
+ for (b = c = code = 0; b <= max_bits; b++) {
+ h->last[b] = c;
+ c += bits[b];
+
+ min_code = (code << 1);
+ codes[b] = min_code;
+ code = (min_code + bits[b]);
+
+ if (code > (1U << b)) {
+ rv = -25;
+ goto bail;
+ }
+
+ h->max_code[b] = (code - 1);
+ h->last[b] += (code - 1);
+ }
+
+ if (flat_bits > max_bits)
+ flat_bits = max_bits;
+
+ h->flat_mask = ((1 << flat_bits) - 1);
+
+ if (min_bits > flat_bits)
+ min_bits = flat_bits;
+
+ h->min_bits = min_bits;
+
+ for (i = 0, b = (1 << flat_bits); i < b; i++)
+ h->flat[i] = 0xffffffff;
+
+ for (b = max_bits; b > flat_bits; b--) {
+ code = h->max_code[b];
+
+ if (code == 0xffffffff)
+ break;
+
+ min_code = ((code + 1) - bits[b]);
+ min_code >>= (b - flat_bits);
+ code >>= (b - flat_bits);
+
+ for (; min_code <= code; min_code++)
+ h->flat[INFLATE_REVERSE(min_code, flat_bits)] = ((b << 8) | 0xff);
+ }
+
+ for (i = 0; i < hb_len; i++) {
+ b = hb[i];
+
+ if (b == 0)
+ continue;
+
+ c = codes[b]++;
+
+ if (b <= flat_bits) {
+ code = ((i << 8) | b);
+ ec = ((c + 1) << (flat_bits - b));
+
+ if (ec > (1U << flat_bits)) {
+ rv = -26;
+ goto bail;
+ }
+
+ for (fc = (c << (flat_bits - b)); fc < ec; fc++)
+ h->flat[INFLATE_REVERSE(fc, flat_bits)] = code;
+ }
+
+ if (b > min_bits) {
+ c = h->last[b] - c;
+
+ if (c >= hb_len) {
+ rv = -27;
+ goto bail;
+ }
+
+ h->decode[c] = i;
+ }
+ }
+
+ table_done:
+
+ if (type == 2) {
+ static const uint32_t bits[3] = { 2, 3, 7, };
+ static const uint32_t bases[3] = { 3, 3, 11, };
+
+ for (i = 0, j = tab_lens[0] + tab_lens[1]; i < j; ) {
+ uint32_t len;
+ uint8_t byte;
+
+ INFLATE_FILL_BITS(-28, h->max_bits);
+
+ c = INFLATE_DECODE(-29, h);
+
+ if (c < 16) {
+ tab[0][i++] = c;
+ continue;
+ }
+
+ c -= 16;
+
+ if (c == 0 && i == 0) {
+ rv = -30;
+ goto bail;
+ }
+
+ INFLATE_FILL_BITS(-31, bits[c]);
+ INFLATE_EXTRACT_BITS(bits[c], len);
+ len += bases[c];
+
+ if ((i + len) > j) {
+ rv = -32;
+ goto bail;
+ }
+
+ byte = ((c == 0) ? tab[0][i - 1] : 0);
+ for (k = 0; k < len; k++)
+ tab[0][i + k] = byte;
+
+ i += len;
+ }
+ }
+ }
+
+ while (1) {
+ static const uint32_t lenbase[INFLATE_SYMBOL_MAX - 257] = {
+ 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115,
+ 131, 163, 195, 227, 258, 0, 0,
+ };
+ static const uint32_t lenextra[INFLATE_SYMBOL_MAX - 257] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4,
+ 5, 5, 5, 5, 0, 0, 0,
+ };
+ static const uint32_t offbase[INFLATE_OFFSET_MAX] = {
+ 1, 2, 3, 4, 5, 7, 9, 13,
+ 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073,
+ 4097, 6145, 8193, 12289, 16385, 24577, 0, 0,
+ };
+ static const uint32_t offextra[INFLATE_OFFSET_MAX] = {
+ 0, 0, 0, 0, 1, 1, 2, 2,
+ 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10,
+ 11, 11, 12, 12, 13, 13, 0, 0,
+ };
+ uint32_t len;
+ uint32_t off;
+ uint8_t* cp;
+
+ INFLATE_FILL_BITS(-33, tab_huffs[0]->max_bits);
+ c = INFLATE_DECODE(-34, tab_huffs[0]);
+
+ if (c < 256) {
+ INFLATE_PUT_BYTE(-35, c);
+ continue;
+ }
+
+ if (c == 256)
+ break;
+
+ if (c > 285) {
+ rv = -36;
+ goto bail;
+ }
+
+ c -= 257;
+ INFLATE_FILL_BITS(-37, lenextra[c]);
+ INFLATE_EXTRACT_BITS(lenextra[c], len);
+ len += lenbase[c];
+
+ INFLATE_FILL_BITS(-38, tab_huffs[1]->max_bits);
+ c = INFLATE_DECODE(-39, tab_huffs[1]);
+
+ if (c > 29) {
+ rv = -40;
+ goto bail;
+ }
+
+ INFLATE_FILL_BITS(-41, offextra[c]);
+ INFLATE_EXTRACT_BITS(offextra[c], off);
+ off += offbase[c];
+
+ cp = op - off;
+ if (cp < os) {
+ if (!flushed) {
+ rv = -42;
+ goto bail;
+ }
+
+ cp += sizeof(it->out);
+ }
+
+ while (len != 0) {
+ if (op == oe)
+ INFLATE_FLUSH(-43);
+
+ if (cp == oe)
+ cp = os;
+
+ j = MIN(len, MIN((uint32_t) (oe - op), (uint32_t) (oe - cp)));
+
+ for (i = 0; i < j; i++)
+ op[i] = cp[i];
+
+ op += j;
+ cp += j;
+ len -= j;
+ }
+ }
+ }
+ } while (!final);
+
+ INFLATE_FLUSH(-44);
+
+ if (st != INFLATE_RAW) {
+ uint8_t header[4];
+ uint32_t chksum2;
+
+ INFLATE_CONSUME_BITS(nbits & 0x07);
+
+ for (i = 0; i < 4; i++) {
+ if (nbits != 0)
+ INFLATE_EXTRACT_BITS(8, header[i]);
+ else
+ INFLATE_GET_BYTE(-45, header[i]);
+ }
+
+ if (st == INFLATE_ZLIB) {
+ chksum2 = ((header[0] << 24) | (header[1] << 16) | (header[2] << 8) | (header[3] << 0));
+
+ if (chksum != chksum2) {
+ rv = -46;
+ goto bail;
+ }
+ } else if (st == INFLATE_GZIP) {
+ chksum2 = ((header[3] << 24) | (header[2] << 16) | (header[1] << 8) | (header[0] << 0));
+
+ if (~chksum != chksum2) {
+ rv = -47;
+ goto bail;
+ }
+ }
+ }
+
+bail:
+ return rv;
+}
+
+const uint32_t inflate_size = sizeof(struct inflate);
+const uint32_t inflate_align = _Alignof(struct inflate);
+
+int inflate(struct inflate* it, int st, inflate_reader read, void* rctx, inflate_writer write, void* wctx) {
+ if (it == NULL || read == NULL || write == NULL || st < 0 || st > 2 || (((uintptr_t) it) & (_Alignof(struct inflate) - 1)) != 0)
+ return -48;
+
+ return inflate_blocks(it, st, read, rctx, write, wctx);
+}
diff --git a/firmware/common/pathfuncs.c b/firmware/common/pathfuncs.c
index 1c48a54972..2b4e6a8eb0 100644
--- a/firmware/common/pathfuncs.c
+++ b/firmware/common/pathfuncs.c
@@ -340,6 +340,57 @@ void path_correct_separators(char *dstpath, const char *path)
strcpy(dstp, p);
}
+/* Remove dot segments from the path
+ *
+ * 'path' and 'dstpath' may either be the same buffer or non-overlapping
+ */
+void path_remove_dot_segments (char *dstpath, const char *path)
+{
+ char *dstp = dstpath;
+ char *odstp = dstpath;
+ const char *p = path;
+
+ while (*p)
+ {
+ if (p[0] == '.' && p[1] == PATH_SEPCH)
+ p += 2;
+ else if (p[0] == '.' && p[1] == '.' && p[2] == PATH_SEPCH)
+ p += 3;
+ else if (p[0] == PATH_SEPCH && p[1] == '.' && p[2] == PATH_SEPCH)
+ p += 2;
+ else if (p[0] == PATH_SEPCH && p[1] == '.' && !p[2])
+ {
+ *dstp++ = PATH_SEPCH;
+ break;
+ }
+ else if (p[0] == PATH_SEPCH && p[1] == '.' &&
+ p[2] == '.' && p[3] == PATH_SEPCH)
+ {
+ dstp = odstp;
+ p += 3;
+ }
+ else if (p[0] == PATH_SEPCH && p[1] == '.' && p[2] == '.' && !p[3])
+ {
+ dstp = odstp;
+ *dstp++ = PATH_SEPCH;
+ break;
+ }
+ else if (p[0] == '.' && !p[1])
+ break;
+ else if (p[0] == '.' && p[1] == '.' && !p[2])
+ break;
+ else
+ {
+ odstp = dstp;
+ if (p[0] == PATH_SEPCH)
+ *dstp++ = *p++;
+ while (p[0] && p[0] != PATH_SEPCH)
+ *dstp++ = *p++;
+ }
+ }
+ *dstp = 0;
+}
+
/* Appends one path to another, adding separators between components if needed.
* Return value and behavior is otherwise as strlcpy so that truncation may be
* detected.
diff --git a/firmware/common/vuprintf.c b/firmware/common/vuprintf.c
index 6a3b29388b..0566e3e37e 100644
--- a/firmware/common/vuprintf.c
+++ b/firmware/common/vuprintf.c
@@ -753,6 +753,7 @@ static int format_double_radix(double f,
if (prec_rem) {
prec_rem--;
}
+ /* fallthrough */
case 1: /* %e, %E */
explen = 2;
break;
diff --git a/firmware/core_alloc.c b/firmware/core_alloc.c
index df1b4d3213..bf2f8e8298 100644
--- a/firmware/core_alloc.c
+++ b/firmware/core_alloc.c
@@ -8,16 +8,27 @@
/* not static so it can be discovered by core_get_data() */
struct buflib_context core_ctx;
-/* defined in linker script */
#if (CONFIG_PLATFORM & PLATFORM_NATIVE) && !defined(__PCTOOL__)
+
#if defined(IPOD_VIDEO) && !defined(BOOTLOADER)
+/* defined in linker script */
+extern unsigned char audiobuffer[];
extern unsigned char *audiobufend_lds[];
+/* pointer to end of audio buffer filled at runtime allocator_init */
unsigned char *audiobufend;
-#else /* !IPOD_VIDEO */
-extern unsigned char audiobufend[];
-#endif
+#elif defined(SANSA_E200) && defined(HAVE_BOOTLOADER_USB_MODE)
+/* defined in linker script */
+extern unsigned char freebuffer[];
+extern unsigned char freebufferend[];
+/* map linker symbol to the audiobuffer in order to use core_alloc */
+unsigned char *audiobuffer = (unsigned char *)freebuffer;
+unsigned char *audiobufend = (unsigned char *)freebufferend;
+#else /* !IPOD_VIDEO, !SANSA_E200&&BOOTLOADERUSB */
/* defined in linker script */
extern unsigned char audiobuffer[];
+extern unsigned char audiobufend[];
+#endif
+
#else /* PLATFORM_HOSTED */
static unsigned char audiobuffer[((MEMORYSIZE)*1024-768)*1024];
unsigned char *audiobufend = audiobuffer + sizeof(audiobuffer);
diff --git a/firmware/drivers/audio/ak4376.c b/firmware/drivers/audio/ak4376.c
index 11714b210d..8206bcf7e0 100644
--- a/firmware/drivers/audio/ak4376.c
+++ b/firmware/drivers/audio/ak4376.c
@@ -83,11 +83,11 @@ void ak4376_open(void)
ak4376_set_pdn_pin(1);
mdelay(1);
- static const int init_config[] = {
+ static const uint8_t init_config[] = {
/* Ensure HPRHZ, HPLHZ are 0 */
AK4376_REG_OUTPUT_MODE, 0x00,
/* Mute all volume controls */
- AK4376_REG_MIXER, 0x00,
+ AK4376_REG_MIXER, AK4376_MIX_LCH | (AK4376_MIX_RCH << 4),
AK4376_REG_LCH_VOLUME, 0x80,
AK4376_REG_RCH_VOLUME, 0x00,
AK4376_REG_AMP_VOLUME, 0x00,
@@ -150,14 +150,9 @@ static int round_step_up(int x, int step)
return x - rem;
}
-static void calc_volumes(int vol, int* mix, int* dig, int* sw)
+static void calc_volumes(int vol, int* dig, int* sw)
{
- /* Mixer can divide by 2, which gives an extra -6 dB adjustment */
- if(vol < AK4376_DIG_VOLUME_MIN) {
- *mix |= AK4376_MIX_HALF;
- vol += 60;
- }
-
+ /* Apply digital volume */
*dig = round_step_up(vol, AK4376_DIG_VOLUME_STEP);
*dig = MIN(*dig, AK4376_DIG_VOLUME_MAX);
*dig = MAX(*dig, AK4376_DIG_VOLUME_MIN);
@@ -186,8 +181,8 @@ static int amp_vol_to_hw(int vol)
void ak4376_set_volume(int vol_l, int vol_r)
{
int amp;
- int mix_l = AK4376_MIX_LCH, dig_l, sw_l;
- int mix_r = AK4376_MIX_RCH, dig_r, sw_r;
+ int dig_l, sw_l;
+ int dig_r, sw_r;
if(vol_l <= AK4376_MIN_VOLUME && vol_r <= AK4376_MIN_VOLUME) {
/* Special case for full mute */
@@ -202,11 +197,10 @@ void ak4376_set_volume(int vol_l, int vol_r)
amp = MAX(amp, AK4376_AMP_VOLUME_MIN);
/* Other controls are stereo */
- calc_volumes(vol_l - amp, &mix_l, &dig_l, &sw_l);
- calc_volumes(vol_r - amp, &mix_r, &dig_r, &sw_r);
+ calc_volumes(vol_l - amp, &dig_l, &sw_l);
+ calc_volumes(vol_r - amp, &dig_r, &sw_r);
}
- ak4376_write(AK4376_REG_MIXER, (mix_l & 0xf) | ((mix_r & 0xf) << 4));
ak4376_write(AK4376_REG_LCH_VOLUME, dig_vol_to_hw(dig_l) | (1 << 7));
ak4376_write(AK4376_REG_RCH_VOLUME, dig_vol_to_hw(dig_r));
ak4376_write(AK4376_REG_AMP_VOLUME, amp_vol_to_hw(amp));
diff --git a/firmware/drivers/audio/eros_qn_codec.c b/firmware/drivers/audio/eros_qn_codec.c
index 21347f5fca..da50d62fe5 100644
--- a/firmware/drivers/audio/eros_qn_codec.c
+++ b/firmware/drivers/audio/eros_qn_codec.c
@@ -26,10 +26,14 @@
#include "audiohw.h"
#include "settings.h"
#include "pcm_sw_volume.h"
+#include "gpio-x1000.h"
static long int vol_l_hw = 0;
static long int vol_r_hw = 0;
+/* internal: mute the headphone amp. 0 - unmuted, 1 - muted */
+void audiohw_mute_hp(int mute);
+
void pcm5102_set_outputs(void)
{
audiohw_set_volume(vol_l_hw, vol_r_hw);
@@ -53,13 +57,33 @@ void audiohw_set_volume(int vol_l, int vol_r)
if (lineout_inserted() && !headphones_inserted())
{
l = r = global_settings.volume_limit * 10;
+
+ /* mute the headphone amp if not plugged in */
+ audiohw_mute_hp(1);
}
else
{
+ /* unmute the headphone amp when plugged in */
+ audiohw_mute_hp(0);
l = vol_l;
r = vol_r;
}
#endif
+ l = l <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : (l / 20);
+ r = r <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : (r / 20);
+
pcm_set_master_volume(l, r);
}
+
+void audiohw_mute_hp(int mute)
+{
+ if (mute == 0)
+ {
+ gpio_set_level(GPIO_MAX97220_SHDN, 1);
+ }
+ else
+ {
+ gpio_set_level(GPIO_MAX97220_SHDN, 0);
+ }
+}
diff --git a/firmware/drivers/isp1583.c b/firmware/drivers/isp1583.c
index c028d2fa01..e60339d9fc 100644
--- a/firmware/drivers/isp1583.c
+++ b/firmware/drivers/isp1583.c
@@ -341,7 +341,7 @@ static void usb_handle_setup_rx(void)
if (len == 8)
{
ISP1583_DFLOW_CTRLFUN |= DFLOW_CTRLFUN_STATUS; /* Acknowledge packet */
- usb_core_control_request((struct usb_ctrlrequest*)setup_pkt_buf);
+ usb_core_legacy_control_request((struct usb_ctrlrequest*)setup_pkt_buf);
}
else
{
@@ -531,9 +531,9 @@ static void in_callback(int ep, unsigned char *buf, int len)
usb_core_transfer_complete(ep, false, 0, len);
}
-int usb_drv_recv(int ep, void* ptr, int length)
+int usb_drv_recv_nonblocking(int ep, void* ptr, int length)
{
- logf("usb_drv_recv(%d, 0x%x, %d)", ep, (int)ptr, length);
+ logf("usb_drv_recv_nonblocking(%d, 0x%x, %d)", ep, (int)ptr, length);
if(ep == EP_CONTROL && length == 0 && ptr == NULL)
{
usb_status_ack(ep, DIR_TX);
diff --git a/firmware/drivers/lcd-16bit-common.c b/firmware/drivers/lcd-16bit-common.c
index dbfea50dd7..25e3b89dc3 100644
--- a/firmware/drivers/lcd-16bit-common.c
+++ b/firmware/drivers/lcd-16bit-common.c
@@ -330,6 +330,15 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
src_x -= x;
x = 0;
}
+
+ /* 'Bugfix' mono_bitmap_part reads ahead in the buffer,
+ * if the height is <= char bit pixels other memory gets read
+ * the other option is to check in the hot code path but this appears
+ * sufficient
+ */
+ if (height <= CHAR_BIT)
+ stride = 0;
+
if (y < 0)
{
height += y;
@@ -346,14 +355,6 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
src_end = src + width;
dst_col = FBADDR(x, y);
- /* 'Bugfix' mono_bitmap_part reads ahead in the buffer,
- * if the height is <= char bit pixels other memory gets read
- * the other option is to check in the hot code path but this appears
- * sufficient
- */
- if (height <= CHAR_BIT)
- stride = 0;
-
if (drmode & DRMODE_INVERSEVID)
{
dmask = 0x1ff; /* bit 8 == sentinel */
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c
index 170ad374ea..9a5f865f2a 100644
--- a/firmware/drivers/lcd-bitmap-common.c
+++ b/firmware/drivers/lcd-bitmap-common.c
@@ -511,9 +511,10 @@ static bool LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string,
x = x * (linebased ? cwidth : 1);
width = vp->width - x;
- if (y >= vp->height || (height + y) > (vp->height))
+ if (y >= vp->height)
return false;
-
+ if ((height + y) > (vp->height))
+ height = vp->height - y;
s = find_scrolling_line(x, y);
restart = !s;
diff --git a/firmware/drivers/m66591.c b/firmware/drivers/m66591.c
index d09b269f33..822585d882 100644
--- a/firmware/drivers/m66591.c
+++ b/firmware/drivers/m66591.c
@@ -208,7 +208,7 @@ static void control_received(void) {
/* acknowledge packet recieved (clear valid) */
M66591_INTSTAT_MAIN &= ~(1<<3);
- usb_core_control_request(&temp);
+ usb_core_legacy_control_request(&temp);
}
/* This is a helper function, it is used to notife the stack that a transfer is
@@ -869,7 +869,7 @@ int usb_drv_send(int endpoint, void* ptr, int length)
/* This function begins a receive (on an OUT endpoint), it should not block
* so the actual receive is done in the interrupt handler.
*/
-int usb_drv_recv(int endpoint, void* ptr, int length)
+int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length)
{
return mxx_queue(endpoint, ptr, length, false, false);
}
diff --git a/firmware/drivers/usb-designware.c b/firmware/drivers/usb-designware.c
index 375fd8be74..37e96aa557 100644
--- a/firmware/drivers/usb-designware.c
+++ b/firmware/drivers/usb-designware.c
@@ -53,13 +53,31 @@
#define COMMIT_DCACHE_RANGE(b,s) commit_dcache_range(b,s)
#endif
-/* On some platforms, virtual addresses must be mangled to
- * get a physical address for DMA
+/* USB_DW_PHYSADDR(x) converts the address of buffer x to one usable with DMA.
+ * For example, converting a virtual address to a physical address.
+ *
+ * USB_DW_UNCACHEDADDR(x) is used to get an uncached pointer to a buffer.
+ * If the platform doesn't support this, define NO_UNCACHED_ADDR instead.
+ *
+ * Define POST_DMA_FLUSH if the driver should discard DMA RX buffers after a
+ * transfer completes. Needed if the CPU can speculatively fetch cache lines
+ * in any way, eg. due to speculative execution / prefetching.
*/
#if CONFIG_CPU == X1000
-# define DMA_ADDR2PHYS(x) PHYSADDR(x)
-#else
-# define DMA_ADDR2PHYS(x) x
+# define USB_DW_PHYSADDR(x) PHYSADDR(x)
+# define USB_DW_UNCACHEDADDR(x) ((typeof(x))UNCACHEDADDR(x))
+# define POST_DMA_FLUSH
+#elif CONFIG_CPU == AS3525v2
+# define USB_DW_PHYSADDR(x) AS3525_PHYSICAL_ADDR(x)
+# define USB_DW_UNCACHEDADDR(x) AS3525_UNCACHED_ADDR(x)
+#elif CONFIG_CPU == S5L8701
+# define USB_DW_PHYSADDR(x) x
+# define NO_UNCACHED_ADDR /* Not known how to form uncached addresses */
+#elif CONFIG_CPU == S5L8702
+# define USB_DW_PHYSADDR(x) S5L8702_PHYSICAL_ADDR(x)
+# define USB_DW_UNCACHEDADDR(x) S5L8702_UNCACHED_ADDR(x)
+#elif !defined(USB_DW_ARCH_SLAVE)
+# error "Must define USB_DW_PHYSADDR / USB_DW_UNCACHEDADDR!"
#endif
#ifndef USB_DW_TOUTCAL
@@ -77,19 +95,33 @@ enum usb_dw_epdir
USB_DW_EPDIR_OUT = 1,
};
-union usb_ep0_buffer
+enum usb_dw_ep0_state
{
- struct usb_ctrlrequest setup;
- uint8_t raw[64];
-};
+ /* Waiting for a setup packet to arrive. This is the default state. */
+ EP0_SETUP,
+
+ /* Request wait states -- after submitting a request, we enter EP0_REQ
+ * (or EP0_REQ_CTRLWRITE for control writes). EP0_REQ is also used for
+ * the 2nd phase of a control write. */
+ EP0_REQ,
+ EP0_REQ_CTRLWRITE,
+
+ /* Waiting for a data phase to complete. */
+ EP0_DATA_IN, EP0_FIRST_CNAK_STATE = EP0_DATA_IN,
+ EP0_DATA_OUT,
-static union usb_ep0_buffer ep0_buffer USB_DEVBSS_ATTR;
+ /* Waiting for the status phase */
+ EP0_STATUS_IN,
+ EP0_STATUS_OUT,
+
+ EP0_NUM_STATES
+};
/* Internal EP state/info */
struct usb_dw_ep
{
struct semaphore complete;
- uint32_t* req_addr;
+ void* req_addr;
uint32_t req_size;
uint32_t* addr;
uint32_t sizeleft;
@@ -99,7 +131,42 @@ struct usb_dw_ep
uint8_t busy;
};
+/* Additional state for EP0 */
+struct usb_dw_ep0
+{
+ enum usb_dw_ep0_state state;
+ struct usb_ctrlrequest active_req;
+ struct usb_ctrlrequest pending_req;
+};
+
+static const char* const dw_dir_str[USB_DW_NUM_DIRS] =
+{
+ [USB_DW_EPDIR_IN] = "IN",
+ [USB_DW_EPDIR_OUT] = "OUT",
+};
+
+static const char* const dw_state_str[EP0_NUM_STATES] =
+{
+ [EP0_SETUP] = "setup",
+ [EP0_REQ] = "req",
+ [EP0_REQ_CTRLWRITE] = "req_cw",
+ [EP0_DATA_IN] = "dat_in",
+ [EP0_DATA_OUT] = "dat_out",
+ [EP0_STATUS_IN] = "sts_in",
+ [EP0_STATUS_OUT] = "sts_out",
+};
+
+static const char* const dw_resp_str[3] =
+{
+ [USB_CONTROL_ACK] = "ACK",
+ [USB_CONTROL_RECEIVE] = "RECV",
+ [USB_CONTROL_STALL] = "STALL",
+};
+
static struct usb_dw_ep usb_dw_ep_list[USB_NUM_ENDPOINTS][USB_DW_NUM_DIRS];
+static struct usb_dw_ep0 ep0;
+uint8_t _ep0_buffer[64] USB_DEVBSS_ATTR __attribute__((aligned(32)));
+uint8_t* ep0_buffer; /* Uncached, unless NO_UNCACHED_ADDR is defined */
static uint32_t usb_endpoints; /* available EPs mask */
@@ -117,35 +184,30 @@ static uint32_t epmis_msk;
static uint32_t ep_periodic_msk;
#endif
-static const char *dw_dir_str[USB_DW_NUM_DIRS] =
-{
- [USB_DW_EPDIR_IN] = "IN",
- [USB_DW_EPDIR_OUT] = "OUT",
-};
-
-
static struct usb_dw_ep *usb_dw_get_ep(int epnum, enum usb_dw_epdir epdir)
{
return &usb_dw_ep_list[epnum][epdir];
}
-static int usb_dw_maxpktsize(int epnum, enum usb_dw_epdir epdir)
+static uint32_t usb_dw_maxpktsize(int epnum, enum usb_dw_epdir epdir)
{
return epnum ? DWC_EPCTL(epnum, epdir) & 0x3ff : 64;
}
-static int usb_dw_maxxfersize(int epnum, enum usb_dw_epdir epdir)
+static uint32_t usb_dw_maxxfersize(int epnum, enum usb_dw_epdir epdir)
{
- return epnum ? ALIGN_DOWN_P2(MIN(hw_maxbytes,
- hw_maxpackets*usb_dw_maxpktsize(epnum, epdir)), CACHEALIGN_BITS) : 64;
+ /* EP0 can only transfer one packet at a time. */
+ if(epnum == 0)
+ return 64;
+
+ uint32_t maxpktsize = usb_dw_maxpktsize(epnum, epdir);
+ return CACHEALIGN_DOWN(MIN(hw_maxbytes, hw_maxpackets * maxpktsize));
}
/* Calculate number of packets (if size == 0 an empty packet will be sent) */
-static int usb_dw_calc_packets(uint32_t size, uint32_t maxpktsize)
+static uint32_t usb_dw_calc_packets(uint32_t size, uint32_t maxpktsize)
{
- int packets = (size + maxpktsize - 1) / maxpktsize;
- if (!packets) packets = 1;
- return packets;
+ return MAX(1, (size + maxpktsize - 1) / maxpktsize);
}
static int usb_dw_get_stall(int epnum, enum usb_dw_epdir epdir)
@@ -184,8 +246,8 @@ static unsigned usb_dw_bytes_in_txfifo(int epnum, uint32_t *sentbytes)
uint32_t dieptsiz = DWC_DIEPTSIZ(epnum);
uint32_t packetsleft = (dieptsiz >> 19) & 0x3ff;
if (!packetsleft) return 0;
- int maxpktsize = usb_dw_maxpktsize(epnum, USB_DW_EPDIR_IN);
- int packets = usb_dw_calc_packets(size, maxpktsize);
+ uint32_t maxpktsize = usb_dw_maxpktsize(epnum, USB_DW_EPDIR_IN);
+ uint32_t packets = usb_dw_calc_packets(size, maxpktsize);
uint32_t bytesleft = dieptsiz & 0x7ffff;
uint32_t bytespushed = size - bytesleft;
uint32_t bytespulled = (packets - packetsleft) * maxpktsize;
@@ -200,7 +262,7 @@ static unsigned usb_dw_bytes_in_txfifo(int epnum, uint32_t *sentbytes)
static void usb_dw_handle_rxfifo(void)
{
uint32_t rxsts = DWC_GRXSTSP;
- int pktsts = (rxsts >> 17) & 0xf;
+ uint32_t pktsts = (rxsts >> 17) & 0xf;
switch (pktsts)
{
@@ -208,19 +270,31 @@ static void usb_dw_handle_rxfifo(void)
case PKTSTS_SETUPRX:
{
int ep = rxsts & 0xf;
- int words = (((rxsts >> 4) & 0x7ff) + 3) >> 2;
- struct usb_dw_ep* dw_ep = usb_dw_get_ep(ep, USB_DW_EPDIR_OUT);
- if (dw_ep->busy)
+ uint32_t words = (((rxsts >> 4) & 0x7ff) + 3) >> 2;
+
+ /* Annoyingly, we need to special-case EP0. */
+ if(ep == 0)
{
+ uint32_t* addr = (uint32_t*)ep0_buffer;
while (words--)
- *dw_ep->addr++ = DWC_DFIFO(0);
+ *addr++ = DWC_DFIFO(0);
}
else
{
- /* Discard data */
- while (words--)
- (void) DWC_DFIFO(0);
+ struct usb_dw_ep* dw_ep = usb_dw_get_ep(ep, USB_DW_EPDIR_OUT);
+ if (dw_ep->busy)
+ {
+ while (words--)
+ *dw_ep->addr++ = DWC_DFIFO(0);
+ }
+ else
+ {
+ /* Discard data */
+ while (words--)
+ (void) DWC_DFIFO(0);
+ }
}
+
break;
}
case PKTSTS_OUTDONE:
@@ -292,7 +366,7 @@ static void usb_dw_handle_dtxfifo(int epnum)
{
/* We push whole packets to read consistent info on DIEPTSIZ
(i.e. when FIFO size is not maxpktsize multiplo). */
- int maxpktwords = usb_dw_maxpktsize(epnum, USB_DW_EPDIR_IN) >> 2;
+ uint32_t maxpktwords = usb_dw_maxpktsize(epnum, USB_DW_EPDIR_IN) >> 2;
words = (fifospace / maxpktwords) * maxpktwords;
}
@@ -458,7 +532,7 @@ static void usb_dw_nptx_unqueue(int epnum)
dw_ep->addr -= (bytesinfifo + 3) >> 2;
#else
(void) bytesinfifo;
- DWC_DIEPDMA(ep) = DMA_ADDR2PHYS((uint32_t)(dw_ep->addr) + sentbytes);
+ DWC_DIEPDMA(ep) = USB_DW_PHYSADDR((uint32_t)(dw_ep->addr) + sentbytes);
#endif
DWC_DIEPTSIZ(ep) = PKTCNT(packetsleft) | (dw_ep->size - sentbytes);
@@ -664,57 +738,72 @@ static void usb_dw_reset_endpoints(void)
#endif
}
-static void usb_dw_start_xfer(int epnum,
- enum usb_dw_epdir epdir, const void* buf, int size)
+static void usb_dw_epstart(int epnum, enum usb_dw_epdir epdir,
+ void* buf, uint32_t size)
{
if ((uint32_t)buf & ((epdir == USB_DW_EPDIR_IN) ? 3 : CACHEALIGN_SIZE-1))
logf("%s: %s%d %p unaligned", __func__, dw_dir_str[epdir], epnum, buf);
struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, epdir);
+ uint32_t xfersize = MIN(size, usb_dw_maxxfersize(epnum, epdir));
- dw_ep->busy = true;
- dw_ep->status = -1;
+ dw_ep->addr = (uint32_t*)buf;
+ dw_ep->size = xfersize;
dw_ep->sizeleft = size;
- size = MIN(size, usb_dw_maxxfersize(epnum, epdir));
- dw_ep->size = size;
+ dw_ep->status = -1;
+ dw_ep->busy = true;
- int packets = usb_dw_calc_packets(size, usb_dw_maxpktsize(epnum, epdir));
- uint32_t eptsiz = PKTCNT(packets) | size;
- uint32_t nak;
+ if (epnum == 0 && epdir == USB_DW_EPDIR_OUT)
+ {
+ /* FIXME: there's an extremely rare race condition here.
+ *
+ * 1. Host sends a control write.
+ * 2. We process the request.
+ * 3. (time passes)
+ * 4. This function is called via USB_CONTROL_RECEIVE response.
+ * 5. Right before we set CNAK, host sends another control write.
+ *
+ * So we may unintentionally receive data from the second request.
+ * It's possible to detect this when we see a setup packet because
+ * EP0 OUT will be busy. In principle it should even be possible to
+ * handle the 2nd request correctly. Currently we don't attempt to
+ * detect or recover from this error.
+ */
+ DWC_DOEPCTL(0) |= CNAK;
+ return;
+ }
- /* Set up data source */
- dw_ep->addr = (uint32_t*)buf;
-#ifndef USB_DW_ARCH_SLAVE
- DWC_EPDMA(epnum, epdir) = DMA_ADDR2PHYS((uint32_t)buf);
-#endif
+ uint32_t maxpktsize = usb_dw_maxpktsize(epnum, epdir);
+ uint32_t packets = usb_dw_calc_packets(xfersize, maxpktsize);
+ uint32_t eptsiz = PKTCNT(packets) | xfersize;
+ uint32_t nak = CNAK;
if (epdir == USB_DW_EPDIR_IN)
{
#ifndef USB_DW_ARCH_SLAVE
- COMMIT_DCACHE_RANGE(buf, size);
+ COMMIT_DCACHE_RANGE(buf, xfersize);
#endif
#ifdef USB_DW_SHARED_FIFO
eptsiz |= MCCNT((ep_periodic_msk >> epnum) & 1);
#endif
- nak = CNAK;
+
}
else
{
#ifndef USB_DW_ARCH_SLAVE
- DISCARD_DCACHE_RANGE(buf, size);
+ DISCARD_DCACHE_RANGE(buf, xfersize);
#endif
- eptsiz |= STUPCNT(!epnum);
- nak = epnum ? CNAK : SNAK;
}
+#ifndef USB_DW_ARCH_SLAVE
+ DWC_EPDMA(epnum, epdir) = USB_DW_PHYSADDR((uint32_t)buf);
+#endif
DWC_EPTSIZ(epnum, epdir) = eptsiz;
-
- /* Enable the endpoint */
DWC_EPCTL(epnum, epdir) |= EPENA | nak;
#ifdef USB_DW_ARCH_SLAVE
/* Enable interrupts to start pushing data into the FIFO */
- if ((epdir == USB_DW_EPDIR_IN) && size)
+ if ((epdir == USB_DW_EPDIR_IN) && dw_ep->size > 0)
#ifdef USB_DW_SHARED_FIFO
DWC_GINTMSK |= ((ep_periodic_msk & (1 << epnum)) ? PTXFE : NPTXFE);
#else
@@ -723,25 +812,31 @@ static void usb_dw_start_xfer(int epnum,
#endif
}
-static void usb_dw_ep0_wait_setup(void)
+static void usb_dw_transfer(int epnum, enum usb_dw_epdir epdir,
+ void* buf, uint32_t size)
{
- usb_dw_start_xfer(0, USB_DW_EPDIR_OUT, ep0_buffer.raw, 64);
-}
-
-static void usb_dw_handle_setup_received(void)
-{
- static struct usb_ctrlrequest usb_ctrlsetup;
-
- usb_dw_flush_endpoint(0, USB_DW_EPDIR_IN);
+ struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, epdir);
- memcpy(&usb_ctrlsetup, ep0_buffer.raw, sizeof(usb_ctrlsetup));
+ if (!dw_ep->active)
+ logf("%s: %s%d inactive", __func__, dw_dir_str[epdir], epnum);
+ if (dw_ep->busy)
+ logf("%s: %s%d busy", __func__, dw_dir_str[epdir], epnum);
- if (((usb_ctrlsetup.bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE)
- && ((usb_ctrlsetup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
- && (usb_ctrlsetup.bRequest == USB_REQ_SET_ADDRESS))
- usb_dw_set_address(usb_ctrlsetup.wValue);
+ dw_ep->req_addr = buf;
+ dw_ep->req_size = size;
+ usb_dw_epstart(epnum, epdir, buf, size);
+}
- usb_core_control_request(&usb_ctrlsetup);
+static void usb_dw_ep0_recv(void)
+{
+#ifndef USB_DW_ARCH_SLAVE
+#ifdef NO_UNCACHED_ADDR
+ DISCARD_DCACHE_RANGE(&_ep0_buffer[0], 64);
+#endif
+ DWC_DOEPDMA(0) = USB_DW_PHYSADDR((uint32_t)&_ep0_buffer[0]);
+#endif
+ DWC_DOEPTSIZ(0) = STUPCNT(1) | PKTCNT(1) | 64;
+ DWC_DOEPCTL(0) |= EPENA | SNAK;
}
static void usb_dw_abort_endpoint(int epnum, enum usb_dw_epdir epdir)
@@ -755,60 +850,223 @@ static void usb_dw_abort_endpoint(int epnum, enum usb_dw_epdir epdir)
}
}
+static void usb_dw_control_received(struct usb_ctrlrequest* req)
+{
+ logf("%s(%p) state=%s", __func__, req, dw_state_str[ep0.state]);
+ logf(" bRequestType=%02x bRequest=%02x", req->bRequestType, req->bRequest);
+ logf(" wValue=%04x wIndex=%u wLength=%u", req->wValue, req->wIndex, req->wLength);
+
+ /* FIXME: This will implode if we receive a setup packet while waiting
+ * for a response from the USB stack to a previous packet.
+ */
+
+ switch(ep0.state) {
+ case EP0_DATA_IN:
+ case EP0_STATUS_IN:
+ case EP0_DATA_OUT:
+ case EP0_STATUS_OUT:
+ usb_core_control_complete(-1);
+ /* fallthrough */
+
+ case EP0_SETUP:
+ /* Save the request */
+ memcpy(&ep0.active_req, req, sizeof(*req));
+ req = &ep0.active_req;
+
+ /* Check for a SET ADDRESS request, which we must handle here */
+ if ((req->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE &&
+ (req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD &&
+ (req->bRequest == USB_REQ_SET_ADDRESS))
+ usb_dw_set_address(req->wValue);
+
+ /* Check for control writes */
+ if (req->wLength > 0 && !(req->bRequestType & USB_DIR_IN))
+ ep0.state = EP0_REQ_CTRLWRITE;
+ else
+ ep0.state = EP0_REQ;
+
+ usb_dw_flush_endpoint(0, USB_DW_EPDIR_IN);
+ usb_core_control_request(req, NULL);
+ break;
+
+ default:
+ panicf("%s: bad state=%s", __func__, dw_state_str[ep0.state]);
+ }
+}
+
+static void usb_dw_control_response(enum usb_control_response resp,
+ void* data, int length)
+{
+ struct usb_ctrlrequest* req = &ep0.active_req;
+
+ switch(ep0.state) {
+ case EP0_REQ:
+ case EP0_REQ_CTRLWRITE:
+ switch(resp) {
+ case USB_CONTROL_ACK:
+ if(req->wLength > 0 && (req->bRequestType & USB_DIR_IN))
+ ep0.state = EP0_DATA_IN; /* control read */
+ else
+ ep0.state = EP0_STATUS_IN; /* non-data or write */
+
+ usb_dw_transfer(0, USB_DW_EPDIR_IN, data, length);
+ break;
+
+ case USB_CONTROL_RECEIVE:
+ if(ep0.state != EP0_REQ_CTRLWRITE)
+ panicf("%s: bad response", __func__);
+
+ ep0.state = EP0_DATA_OUT;
+ usb_dw_transfer(0, USB_DW_EPDIR_OUT, data, length);
+ break;
+
+ case USB_CONTROL_STALL:
+ if(ep0.state == EP0_REQ_CTRLWRITE)
+ usb_dw_set_stall(0, USB_DW_EPDIR_OUT, 1);
+ else
+ usb_dw_set_stall(0, USB_DW_EPDIR_IN, 1);
+
+ ep0.state = EP0_SETUP;
+ break;
+ }
+ break;
+
+ default:
+ panicf("%s: bad state=%s", __func__, dw_state_str[ep0.state]);
+ }
+}
+
+static void usb_dw_ep0_xfer_complete(enum usb_dw_epdir epdir,
+ int status, int transferred)
+{
+ struct usb_dw_ep* dw_ep = usb_dw_get_ep(0, epdir);
+
+ switch((ep0.state << 1) | epdir)
+ {
+ case (EP0_DATA_IN << 1) | USB_DW_EPDIR_IN:
+ ep0.state = EP0_STATUS_OUT;
+ usb_dw_transfer(0, USB_DW_EPDIR_OUT, NULL, 0);
+ break;
+
+ case (EP0_DATA_OUT << 1) | USB_DW_EPDIR_OUT:
+ ep0.state = EP0_REQ;
+ usb_core_control_request(&ep0.active_req, dw_ep->req_addr);
+ break;
+
+ case (EP0_STATUS_IN << 1) | USB_DW_EPDIR_IN:
+ case (EP0_STATUS_OUT << 1) | USB_DW_EPDIR_OUT:
+ if(status != 0 || transferred != 0)
+ usb_core_control_complete(-2);
+ else
+ usb_core_control_complete(0);
+
+ ep0.state = EP0_SETUP;
+ break;
+
+ default:
+ panicf("%s: state=%s dir=%s", __func__,
+ dw_state_str[ep0.state], dw_dir_str[epdir]);
+ }
+}
+
static void usb_dw_handle_xfer_complete(int epnum, enum usb_dw_epdir epdir)
{
struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, epdir);
+ bool is_ep0out = (epnum == 0 && epdir == USB_DW_EPDIR_OUT);
if (!dw_ep->busy)
+ {
+ if(is_ep0out)
+ usb_dw_ep0_recv();
return;
+ }
- uint32_t bytesleft = DWC_EPTSIZ(epnum, epdir) & 0x7ffff;
+ uint32_t bytes_left = DWC_EPTSIZ(epnum, epdir) & 0x7ffff;
+ uint32_t transferred = (is_ep0out ? 64 : dw_ep->size) - bytes_left;
- if (!epnum && (epdir == USB_DW_EPDIR_OUT)) /* OUT0 */
+ if(transferred > dw_ep->sizeleft)
{
- int recvbytes = 64 - bytesleft;
- dw_ep->sizeleft = dw_ep->req_size - recvbytes;
- if (dw_ep->req_addr)
- memcpy(dw_ep->req_addr, ep0_buffer.raw, dw_ep->req_size);
+ /* Host sent more data than expected.
+ * Shouldn't happen for IN endpoints. */
+ dw_ep->status = -2;
+ goto complete;
}
- else
+
+ if(is_ep0out)
+ {
+#if defined(NO_UNCACHED_ADDR) && defined(POST_DMA_FLUSH)
+ DISCARD_DCACHE_RANGE(ep0_buffer, 64);
+#endif
+ memcpy(dw_ep->addr, ep0_buffer, transferred);
+ usb_dw_ep0_recv();
+ }
+
+ dw_ep->sizeleft -= transferred;
+
+ /* Start a new transfer if there is still more to go */
+ if(bytes_left == 0 && dw_ep->sizeleft > 0)
{
- dw_ep->sizeleft -= (dw_ep->size - bytesleft);
- if (!bytesleft && dw_ep->sizeleft)
- {
#ifndef USB_DW_ARCH_SLAVE
- dw_ep->addr += (dw_ep->size >> 2); /* words */
+ dw_ep->addr += (dw_ep->size >> 2); /* offset in words */
#endif
- usb_dw_start_xfer(epnum, epdir, dw_ep->addr, dw_ep->sizeleft);
- return;
- }
+ usb_dw_epstart(epnum, epdir, dw_ep->addr, dw_ep->sizeleft);
+ return;
+ }
- if (epdir == USB_DW_EPDIR_IN)
- {
- /* SNAK the disabled EP, otherwise IN tokens for this
- EP could raise unwanted EPMIS interrupts. Useful for
- usbserial when there is no data to send. */
- DWC_DIEPCTL(epnum) |= SNAK;
+ if(epdir == USB_DW_EPDIR_IN)
+ {
+ /* SNAK the disabled EP, otherwise IN tokens for this
+ EP could raise unwanted EPMIS interrupts. Useful for
+ usbserial when there is no data to send. */
+ DWC_DIEPCTL(epnum) |= SNAK;
#ifdef USB_DW_SHARED_FIFO
- /* See usb-s5l8701.c */
- if (usb_dw_config.use_ptxfifo_as_plain_buffer)
- {
- int dtxfnum = GET_DTXFNUM(epnum);
- if (dtxfnum)
- usb_dw_flush_fifo(TXFFLSH, dtxfnum);
- }
-#endif
+ /* See usb-s5l8701.c */
+ if (usb_dw_config.use_ptxfifo_as_plain_buffer)
+ {
+ int dtxfnum = GET_DTXFNUM(epnum);
+ if (dtxfnum)
+ usb_dw_flush_fifo(TXFFLSH, dtxfnum);
}
+#endif
+ }
+ else
+ {
+#if !defined(USB_DW_ARCH_SLAVE) && defined(POST_DMA_FLUSH)
+ /* On EP0 OUT we do not DMA into the request buffer,
+ * so do not discard the cache in this case. */
+ if(!is_ep0out)
+ DISCARD_DCACHE_RANGE(dw_ep->req_addr, dw_ep->req_size);
+#endif
}
- dw_ep->busy = false;
dw_ep->status = 0;
+
+ complete:
+ dw_ep->busy = false;
semaphore_release(&dw_ep->complete);
- int transfered = dw_ep->req_size - dw_ep->sizeleft;
- usb_core_transfer_complete(epnum, (epdir == USB_DW_EPDIR_OUT) ?
- USB_DIR_OUT : USB_DIR_IN, dw_ep->status, transfered);
+ int total_bytes = dw_ep->req_size - dw_ep->sizeleft;
+ if (epnum == 0)
+ {
+ usb_dw_ep0_xfer_complete(epdir, dw_ep->status, total_bytes);
+ }
+ else
+ {
+ usb_core_transfer_complete(epnum, (epdir == USB_DW_EPDIR_OUT) ?
+ USB_DIR_OUT : USB_DIR_IN, dw_ep->status, total_bytes);
+ }
+}
+
+static void usb_dw_handle_setup_received(void)
+{
+#if defined(NO_UNCACHED_ADDR) && defined(POST_DMA_FLUSH)
+ DISCARD_DCACHE_RANGE(ep0_buffer, 64);
+#endif
+ memcpy(&ep0.pending_req, ep0_buffer, sizeof(struct usb_ctrlrequest));
+ usb_dw_ep0_recv();
+
+ usb_dw_control_received(&ep0.pending_req);
}
#ifdef USB_DW_SHARED_FIFO
@@ -822,7 +1080,7 @@ static int usb_dw_get_epmis(void)
/* Get the EP on the top of the queue, 0 < idx < number of available
IN endpoints */
- int idx = (gnptxsts >> 27) & 0xf;
+ uint32_t idx = (gnptxsts >> 27) & 0xf;
for (epmis = 0; epmis < USB_NUM_ENDPOINTS; epmis++)
if ((usb_endpoints & (1 << epmis)) && !idx--)
break;
@@ -960,6 +1218,7 @@ static void usb_dw_irq(void)
if (daint & (1 << (ep + 16)))
{
uint32_t epints = DWC_DOEPINT(ep);
+ DWC_DOEPINT(ep) = epints;
if (!ep)
{
@@ -967,17 +1226,31 @@ static void usb_dw_irq(void)
{
usb_dw_handle_setup_received();
}
- else if (epints & XFRC)
+
+ if (epints & XFRC)
{
- usb_dw_handle_xfer_complete(0, USB_DW_EPDIR_OUT);
+ if(epints & STATUSRECVD)
+ {
+ /* At the end of a control write's data phase, the
+ * controller writes a spurious OUTDONE token to the
+ * FIFO and raises StatusRecvd | XferCompl.
+ *
+ * We do not need or want this -- we've already handled
+ * the data phase by this point -- but EP0 is stoppped
+ * as a side effect of XferCompl, so we need to restart
+ * it to keep receiving packets. */
+ usb_dw_ep0_recv();
+ }
+ else if(!(epints & SETUPRECVD))
+ {
+ /* Only call this for normal data packets. Setup
+ * packets use the STUP interrupt handler instead. */
+ usb_dw_handle_xfer_complete(0, USB_DW_EPDIR_OUT);
+ }
}
- usb_dw_ep0_wait_setup();
- /* Clear interrupt after the current EP0 packet is handled */
- DWC_DOEPINT(0) = epints;
}
else
{
- DWC_DOEPINT(ep) = epints;
if (epints & XFRC)
{
usb_dw_handle_xfer_complete(ep, USB_DW_EPDIR_OUT);
@@ -991,14 +1264,14 @@ static void usb_dw_irq(void)
DWC_GINTSTS = USBRST;
usb_dw_set_address(0);
usb_dw_reset_endpoints();
- usb_dw_ep0_wait_setup();
usb_core_bus_reset();
}
if (DWC_GINTSTS & ENUMDNE)
{
DWC_GINTSTS = ENUMDNE;
- /* Nothing to do? */
+ ep0.state = EP0_SETUP;
+ usb_dw_ep0_recv();
}
}
@@ -1083,9 +1356,17 @@ static void usb_dw_init(void)
if (!initialized)
{
+#if !defined(USB_DW_ARCH_SLAVE) && !defined(NO_UNCACHED_ADDR)
+ ep0_buffer = USB_DW_UNCACHEDADDR(&_ep0_buffer[0]);
+#else
+ /* DMA is not used so we can operate on cached addresses */
+ ep0_buffer = &_ep0_buffer[0];
+#endif
+
for (int ep = 0; ep < USB_NUM_ENDPOINTS; ep++)
for (int dir = 0; dir < USB_DW_NUM_DIRS; dir++)
semaphore_init(&usb_dw_get_ep(ep, dir)->complete, 1, 0);
+
initialized = true;
}
@@ -1333,39 +1614,18 @@ void usb_drv_release_endpoint(int endpoint)
usb_dw_target_enable_irq();
}
-int usb_drv_recv(int endpoint, void* ptr, int length)
+int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length)
{
- int epnum = EP_NUM(endpoint);
- struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, USB_DW_EPDIR_OUT);
-
usb_dw_target_disable_irq();
- if (dw_ep->active)
- {
- dw_ep->req_addr = ptr;
- dw_ep->req_size = length;
- /* OUT0 is always launched waiting for SETUP packet,
- it is CNAKed to receive app data */
- if (epnum == 0)
- DWC_DOEPCTL(0) |= CNAK;
- else
- usb_dw_start_xfer(epnum, USB_DW_EPDIR_OUT, ptr, length);
- }
+ usb_dw_transfer(EP_NUM(endpoint), USB_DW_EPDIR_OUT, ptr, length);
usb_dw_target_enable_irq();
return 0;
}
int usb_drv_send_nonblocking(int endpoint, void *ptr, int length)
{
- int epnum = EP_NUM(endpoint);
- struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, USB_DW_EPDIR_IN);
-
usb_dw_target_disable_irq();
- if (dw_ep->active)
- {
- dw_ep->req_addr = ptr;
- dw_ep->req_size = length;
- usb_dw_start_xfer(epnum, USB_DW_EPDIR_IN, ptr, length);
- }
+ usb_dw_transfer(EP_NUM(endpoint), USB_DW_EPDIR_IN, ptr, length);
usb_dw_target_enable_irq();
return 0;
}
@@ -1388,3 +1648,11 @@ int usb_drv_send(int endpoint, void *ptr, int length)
return dw_ep->status;
}
+
+void usb_drv_control_response(enum usb_control_response resp,
+ void* data, int length)
+{
+ usb_dw_target_disable_irq();
+ usb_dw_control_response(resp, data, length);
+ usb_dw_target_enable_irq();
+}
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h
index 5a706da3b8..3f1bcb6feb 100644
--- a/firmware/export/audiohw.h
+++ b/firmware/export/audiohw.h
@@ -692,4 +692,9 @@ AUDIOHW_SETTING(BALANCE, "%", 0, 1, -100, 100, 0)
AUDIOHW_SETTING(CHANNELS, "", 0, 1, 0, 5, 0)
AUDIOHW_SETTING(STEREO_WIDTH, "%", 0, 5, 0, 250, 100)
+/* if not otherwise defined, set to 16 */
+#if !defined(PCM_NATIVE_BITDEPTH)
+# define PCM_NATIVE_BITDEPTH 16
+#endif
+
#endif /* _AUDIOHW_H_ */
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 702b821856..e887796acc 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -105,7 +105,6 @@
#define IRIVER_H10_PAD 12
#define SANSA_E200_PAD 13
#define SANSA_C200_PAD 14
-#define TATUNG_TPJ1022_PAD 15
#define MROBE100_PAD 17
#define MROBE500_PAD 18
#define GIGABEAT_S_PAD 19
@@ -145,7 +144,6 @@
#define MA_PAD 56
#define SONY_NWZ_PAD 57
#define CREATIVE_ZEN_PAD 58
-#define SAMSUNG_YPZ5_PAD 59
#define IHIFI_PAD 60
#define SAMSUNG_YPR1_PAD 61
#define SAMSUNG_YH92X_PAD 62
@@ -225,7 +223,6 @@
#define LCD_GIGABEAT 12
#define LCD_H10_20GB 13 /* as used by iriver H10 20Gb */
#define LCD_H10_5GB 14 /* as used by iriver H10 5Gb */
-#define LCD_TPJ1022 15 /* as used by Tatung Elio TPJ-1022 */
#define LCD_C200 17 /* as used by Sandisk Sansa c200 */
#define LCD_MROBE500 18 /* as used by Olympus M:Robe 500i */
#define LCD_MROBE100 19 /* as used by Olympus M:Robe 100 */
@@ -264,7 +261,6 @@
#define LCD_CREATIVEZENMOZAIC 56 /* as used by the Creative ZEN Mozaic (FGD0801) */
#define LCD_ILI9342C 57 /* another type of lcd used by HiFi E.T MA9/MA8 */
#define LCD_CREATIVEZENV 58 /* as used by the Creative Zen V (Plus) */
-#define LCD_SAMSUNGYPZ5 59 /* as used by Samsung YP-Z5 */
#define LCD_IHIFI 60 /* as used by IHIFI 760/960 */
#define LCD_CREATIVEZENXFISTYLE 61 /* as used by Creative Zen X-Fi Style */
#define LCD_SAMSUNGYPR1 62 /* as used by Samsung YP-R1 */
@@ -427,8 +423,6 @@ Lyre prototype 1 */
#include "config/sansae200.h"
#elif defined(SANSA_C200)
#include "config/sansac200.h"
-#elif defined(TATUNG_TPJ1022)
-#include "config/tatungtpj1022.h"
#elif defined(MROBE_100)
#include "config/mrobe100.h"
#elif defined(MROBE_500)
@@ -543,8 +537,6 @@ Lyre prototype 1 */
#include "config/sonynwze370.h"
#elif defined(SONY_NWZE360)
#include "config/sonynwze360.h"
-#elif defined(SAMSUNG_YPZ5)
-#include "config/samsungypz5.h"
#elif defined(IHIFI760)
#include "config/ihifi760.h"
#elif defined(IHIFI770)
@@ -1180,7 +1172,11 @@ Lyre prototype 1 */
/* Define the implemented USB transport classes */
#if CONFIG_USBOTG == USBOTG_ISP1583
#define USB_HAS_BULK
-#elif (CONFIG_USBOTG == USBOTG_ARC) || \
+#define USB_LEGACY_CONTROL_API
+#elif (CONFIG_USBOTG == USBOTG_DESIGNWARE)
+#define USB_HAS_BULK
+#define USB_HAS_INTERRUPT
+#elif (CONFIG_USBOTG == USBOTG_ARC) || \
(CONFIG_USBOTG == USBOTG_JZ4740) || \
(CONFIG_USBOTG == USBOTG_JZ4760) || \
(CONFIG_USBOTG == USBOTG_M66591) || \
@@ -1190,10 +1186,13 @@ Lyre prototype 1 */
(CONFIG_USBOTG == USBOTG_TNETV105)
#define USB_HAS_BULK
#define USB_HAS_INTERRUPT
+#define USB_LEGACY_CONTROL_API
#elif defined(CPU_TCC780X)
#define USB_HAS_BULK
+#define USB_LEGACY_CONTROL_API
#elif CONFIG_USBOTG == USBOTG_S3C6400X
#define USB_HAS_BULK
+#define USB_LEGACY_CONTROL_API
//#define USB_HAS_INTERRUPT -- seems to be broken
#endif /* CONFIG_USBOTG */
diff --git a/firmware/export/config/android.h b/firmware/export/config/android.h
index 7d3355ef9d..ac0e2141a1 100644
--- a/firmware/export/config/android.h
+++ b/firmware/export/config/android.h
@@ -51,9 +51,6 @@
#define HAVE_TOUCHSCREEN
#define HAVE_BUTTON_DATA
-/* define this if you have RTC RAM available for settings */
-//#define HAVE_RTC_RAM
-
/* define this if you have a real-time clock */
#define CONFIG_RTC APPLICATION
diff --git a/firmware/export/config/cowond2.h b/firmware/export/config/cowond2.h
index 81a2a85018..51b5495680 100644
--- a/firmware/export/config/cowond2.h
+++ b/firmware/export/config/cowond2.h
@@ -90,9 +90,6 @@
/* The D2 has either a PCF50606 or PCF50635, RTC_D2 handles both */
#define CONFIG_RTC RTC_D2
-/* define this if you have RTC RAM available for settings */
-//#define HAVE_RTC_RAM
-
/* Define this if you have a software controlled poweroff */
#define HAVE_SW_POWEROFF
diff --git a/firmware/export/config/erosqnative.h b/firmware/export/config/erosqnative.h
index 1b37b6042a..f68830e211 100644
--- a/firmware/export/config/erosqnative.h
+++ b/firmware/export/config/erosqnative.h
@@ -64,6 +64,9 @@
#define HAVE_SW_TONE_CONTROLS
#define HAVE_SW_VOLUME_CONTROL
+/* use high-bitdepth volume scaling */
+#define PCM_NATIVE_BITDEPTH 24
+
/* Button defines */
#define CONFIG_KEYPAD EROSQ_PAD
#define HAVE_SCROLLWHEEL
@@ -103,7 +106,6 @@
/* USB support */
#ifndef SIMULATOR
#define CONFIG_USBOTG USBOTG_DESIGNWARE
-#define USB_DW_ARCH_SLAVE
#define USB_DW_TURNAROUND 5
#define HAVE_USBSTACK
#define USB_VENDOR_ID 0xc502
@@ -111,7 +113,13 @@
#define USB_DEVBSS_ATTR __attribute__((aligned(32)))
#define HAVE_USB_POWER
#define HAVE_USB_CHARGING_ENABLE
+#define HAVE_USB_CHARGING_IN_THREAD
+#define TARGET_USB_CHARGING_DEFAULT USB_CHARGING_FORCE
#define HAVE_BOOTLOADER_USB_MODE
+/* This appears to improve transfer performance (the default is 64 KiB).
+ * Going any higher doesn't help but we're still slower than the OF. */
+#define USB_READ_BUFFER_SIZE (128 * 1024)
+#define USB_WRITE_BUFFER_SIZE (128 * 1024)
#endif
/* Rockbox capabilities */
diff --git a/firmware/export/config/fiiom3k.h b/firmware/export/config/fiiom3k.h
index 849aa9c0a6..29395bd433 100644
--- a/firmware/export/config/fiiom3k.h
+++ b/firmware/export/config/fiiom3k.h
@@ -106,7 +106,6 @@
/* USB support */
#ifndef SIMULATOR
#define CONFIG_USBOTG USBOTG_DESIGNWARE
-#define USB_DW_ARCH_SLAVE
#define USB_DW_TURNAROUND 5
#define HAVE_USBSTACK
#define USB_VENDOR_ID 0x2972
@@ -114,7 +113,13 @@
#define USB_DEVBSS_ATTR __attribute__((aligned(32)))
#define HAVE_USB_POWER
#define HAVE_USB_CHARGING_ENABLE
+#define HAVE_USB_CHARGING_IN_THREAD
+#define TARGET_USB_CHARGING_DEFAULT USB_CHARGING_FORCE
#define HAVE_BOOTLOADER_USB_MODE
+/* This appears to improve transfer performance (the default is 64 KiB).
+ * Going any higher doesn't help but we're still slower than the OF. */
+#define USB_READ_BUFFER_SIZE (128 * 1024)
+#define USB_WRITE_BUFFER_SIZE (128 * 1024)
#endif
/* Rockbox capabilities */
diff --git a/firmware/export/config/nokian8xx.h b/firmware/export/config/nokian8xx.h
index 550ee112d1..5cdf42a11f 100644
--- a/firmware/export/config/nokian8xx.h
+++ b/firmware/export/config/nokian8xx.h
@@ -43,9 +43,6 @@
#define HAVE_TOUCHSCREEN
#define HAVE_BUTTON_DATA
-/* define this if you have RTC RAM available for settings */
-//#define HAVE_RTC_RAM
-
/* define this if you have a real-time clock */
#define CONFIG_RTC APPLICATION
diff --git a/firmware/export/config/nokian900.h b/firmware/export/config/nokian900.h
index ebbe5e2cc8..e7084f9acb 100644
--- a/firmware/export/config/nokian900.h
+++ b/firmware/export/config/nokian900.h
@@ -42,9 +42,6 @@
#define HAVE_TOUCHSCREEN
#define HAVE_BUTTON_DATA
-/* define this if you have RTC RAM available for settings */
-//#define HAVE_RTC_RAM
-
/* define this if you have a real-time clock */
#define CONFIG_RTC APPLICATION
diff --git a/firmware/export/config/pandora.h b/firmware/export/config/pandora.h
index 3b26ad9b7b..41b2b44dad 100644
--- a/firmware/export/config/pandora.h
+++ b/firmware/export/config/pandora.h
@@ -43,9 +43,6 @@
#define HAVE_TOUCHSCREEN
#define HAVE_BUTTON_DATA
-/* define this if you have RTC RAM available for settings */
-//#define HAVE_RTC_RAM
-
/* define this if you have a real-time clock */
#define CONFIG_RTC APPLICATION
diff --git a/firmware/export/config/samsungypr0.h b/firmware/export/config/samsungypr0.h
index ba5f02ad74..e29ea6a974 100644
--- a/firmware/export/config/samsungypr0.h
+++ b/firmware/export/config/samsungypr0.h
@@ -68,10 +68,6 @@
/* TODO: ASCODEC has an auto dim feature, so disabling the supply to leds should do the trick. But for now I tested SW fading only */
#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING
-/* define this if you have RTC RAM available for settings */
-/* TODO: in theory we could use that, ascodec offers us such a ram. we have also a small device, part of the nand of 1 MB size, that Samsung uses to store region code etc and it's almost unused space */
-//#define HAVE_RTC_RAM
-
/* define this if you have a real-time clock */
#define CONFIG_RTC RTC_AS3514
#define HAVE_RTC_ALARM
diff --git a/firmware/export/config/samsungypz5.h b/firmware/export/config/samsungypz5.h
deleted file mode 100644
index 2af62c1cbe..0000000000
--- a/firmware/export/config/samsungypz5.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * This config file is for the Samsung YP-Z5
- */
-#define IMX233_SUBTARGET 3600
-#define IMX233_PACKAGE IMX233_BGA169
-#define IMX233_PARTITIONS IMX233_FREESCALE
-
-/* For Rolo and boot loader */
-#define MODEL_NUMBER 84
-#define MODEL_NAME "Samsung YP-Z5"
-/* Define if boot data from bootloader has been enabled for the target */
-#define HAVE_BOOTDATA
-
-#define HW_SAMPR_CAPS SAMPR_CAP_ALL_48
-
-/* define this if you have recording possibility */
-#define HAVE_RECORDING
-
-#define REC_SAMPR_CAPS SAMPR_CAP_ALL_48
-
-/* Default recording levels */
-#define DEFAULT_REC_MIC_GAIN 23
-#define DEFAULT_REC_LEFT_GAIN 23
-#define DEFAULT_REC_RIGHT_GAIN 23
-
-/* Define bitmask of input sources - recordable bitmask can be defined
- explicitly if different */
-#define HAVE_FMRADIO_IN
-#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO)
-
-
-
-/* define this if you have a colour LCD */
-#define HAVE_LCD_COLOR
-
-#ifndef BOOTLOADER
-#define HAVE_ALBUMART
-
-/* define this to enable bitmap scaling */
-#define HAVE_BMP_SCALING
-
-/* define this to enable JPEG decoding */
-#define HAVE_JPEG
-
-/* Define this if a programmable hotkey is mapped */
-#define HAVE_HOTKEY
-
-/* define this if you have access to the quickscreen */
-#define HAVE_QUICKSCREEN
-
-/* define this if you would like tagcache to build on this target */
-#define HAVE_TAGCACHE
-
-/* define this if the target has volume keys which can be used in the lists */
-#define HAVE_VOLUME_IN_LIST
-
-/* define this if you have LCD enable function */
-//#define HAVE_LCD_ENABLE
-
-/* Define this if your LCD can be put to sleep. HAVE_LCD_ENABLE
- should be defined as well.
-#define HAVE_LCD_SLEEP
-#define HAVE_LCD_SLEEP_SETTING
-*/
-
-/* define this if you can flip your LCD
-#define HAVE_LCD_FLIP
-*/
-
-/* define this if you can invert the colours on your LCD
-#define HAVE_LCD_INVERT
-*/
-
-/* define this if you have a real-time clock */
-#define CONFIG_RTC RTC_IMX233
-
-/* define this if you have a real-time clock with alarm facilities */
-#define HAVE_RTC_ALARM
-
-#endif /* !BOOTLOADER */
-
-/* define this if you have an i.MX23 codec */
-#define HAVE_IMX233_CODEC
-
-#define CONFIG_TUNER TEA5767
-#define CONFIG_TUNER_XTAL 32768
-
-/* There is no hardware tone control */
-#define HAVE_SW_TONE_CONTROLS
-
-#define CONFIG_KEYPAD SAMSUNG_YPZ5_PAD
-#define HAVE_TOUCHPAD_IMX233
-
-/* Define this to enable morse code input */
-#define HAVE_MORSE_INPUT
-
-
-
-
-/* LCD dimensions */
-#define LCD_WIDTH 128
-#define LCD_HEIGHT 160
-/* sqrt(128^2 + 160^2) / 1.8 = 113.8 */
-#define LCD_DPI 114
-#define LCD_DEPTH 16 /* 65536 colours */
-#define LCD_PIXELFORMAT RGB565 /* rgb565 */
-
-/* Define this if you have a software controlled poweroff */
-#define HAVE_SW_POWEROFF
-
-/* Some devices seem to be FAT16 formatted */
-#define HAVE_FAT16SUPPORT
-
-/* The number of bytes reserved for loadable codecs */
-#define CODEC_SIZE 0x100000
-
-/* The number of bytes reserved for loadable plugins */
-#define PLUGIN_BUFFER_SIZE 0x80000
-
-#define AB_REPEAT_ENABLE
-
-/* Define this for LCD backlight available */
-#define HAVE_BACKLIGHT
-#define HAVE_BACKLIGHT_BRIGHTNESS
-
-/* Main LCD backlight brightness range and defaults */
-#define MIN_BRIGHTNESS_SETTING 1
-#define MAX_BRIGHTNESS_SETTING 18
-#define DEFAULT_BRIGHTNESS_SETTING 5
-
-/* Which backlight fading type? */
-#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING
-
-/* define this if you have a flash memory storage */
-//#define HAVE_FLASH_STORAGE
-
-#define CONFIG_STORAGE (STORAGE_RAMDISK)
-//#define CONFIG_NAND NAND_IMX233
-//#define NUM_DRIVES 0
-
-/* Extra threads: touchpad and rds */
-//#define TARGET_EXTRA_THREADS 2
-
-/* todo */
-#define BATTERY_CAPACITY_DEFAULT 550 /* default battery capacity */
-#define BATTERY_CAPACITY_MIN 550 /* min. capacity selectable */
-#define BATTERY_CAPACITY_MAX 550 /* max. capacity selectable */
-#define BATTERY_CAPACITY_INC 0 /* capacity increment */
-#define BATTERY_TYPES_COUNT 1 /* only one type */
-
-#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE
-
-/* Charging implemented in a target-specific algorithm */
-#define CONFIG_CHARGING CHARGING_TARGET
-
-/* define this if the unit can be powered or charged via USB */
-#define HAVE_USB_POWER
-
-/* Define this if you have an IMX233*/
-#define CONFIG_CPU IMX233
-
-/* Define this if you want to use the IMX233 i2c interface */
-#define CONFIG_I2C I2C_IMX233
-
-/* define current usage levels (based on battery bench) */
-#define CURRENT_NORMAL 35
-#define CURRENT_BACKLIGHT 30
-#define CURRENT_RECORD CURRENT_NORMAL
-
-/* maximum charging current */
-#define CURRENT_MAX_CHG 200
-
-/* Define this to the CPU frequency */
-#define CPU_FREQ 454000000
-
-/* Type of LCD */
-#define CONFIG_LCD LCD_SAMSUNGYPZ5
-
-/* Offset ( in the firmware file's header ) to the file CRC and data. These are
- only used when loading the old format rockbox.e200 file */
-#define FIRMWARE_OFFSET_FILE_CRC 0x0
-#define FIRMWARE_OFFSET_FILE_DATA 0x8
-
-/* USB On-the-go */
-#define CONFIG_USBOTG USBOTG_ARC
-
-/* enable these for the experimental usb stack */
-#define HAVE_USBSTACK
-#define USB_VENDOR_ID 0x04e8
-#define USB_PRODUCT_ID 0x5041
-#define HAVE_USB_HID_MOUSE
-#define HAVE_BOOTLOADER_USB_MODE
-
-/* Define this if you have adjustable CPU frequency */
-//#define HAVE_ADJUSTABLE_CPU_FREQ
-
-/* Virtual LED (icon) */
-#define CONFIG_LED LED_VIRTUAL
-
-#define BOOTFILE_EXT "samsung"
-#define BOOTFILE "rockbox." BOOTFILE_EXT
-#define BOOTDIR "/.rockbox"
-
-#define INCLUDE_TIMEOUT_API
diff --git a/firmware/export/config/sansam200v4.h b/firmware/export/config/sansam200v4.h
index 97462dc6e2..37f0931079 100644
--- a/firmware/export/config/sansam200v4.h
+++ b/firmware/export/config/sansam200v4.h
@@ -75,9 +75,6 @@
#define CONFIG_RTC RTC_AS3514
#endif
-/* define this if you have RTC RAM available for settings */
-//#define HAVE_RTC_RAM
-
/* Define this if you have a software controlled poweroff */
#define HAVE_SW_POWEROFF
diff --git a/firmware/export/config/sdlapp.h b/firmware/export/config/sdlapp.h
index d8c1266f51..3286e377ce 100644
--- a/firmware/export/config/sdlapp.h
+++ b/firmware/export/config/sdlapp.h
@@ -52,9 +52,6 @@
#define HAVE_TOUCHSCREEN
#define HAVE_BUTTON_DATA
-/* define this if you have RTC RAM available for settings */
-//#define HAVE_RTC_RAM
-
/* define this if you have a real-time clock */
#define CONFIG_RTC APPLICATION
diff --git a/firmware/export/config/shanlingq1.h b/firmware/export/config/shanlingq1.h
index 88175b9160..1f1ee79ca7 100644
--- a/firmware/export/config/shanlingq1.h
+++ b/firmware/export/config/shanlingq1.h
@@ -96,7 +96,6 @@
/* USB support */
#ifndef SIMULATOR
#define CONFIG_USBOTG USBOTG_DESIGNWARE
-#define USB_DW_ARCH_SLAVE
#define USB_DW_TURNAROUND 5
#define HAVE_USBSTACK
#define USB_VENDOR_ID 0x0525 /* Same as the xDuuo X3, for some reason. */
@@ -104,7 +103,13 @@
#define USB_DEVBSS_ATTR __attribute__((aligned(32)))
#define HAVE_USB_POWER
#define HAVE_USB_CHARGING_ENABLE
+#define HAVE_USB_CHARGING_IN_THREAD
+#define TARGET_USB_CHARGING_DEFAULT USB_CHARGING_FORCE
#define HAVE_BOOTLOADER_USB_MODE
+/* This appears to improve transfer performance (the default is 64 KiB).
+ * Going any higher doesn't help but we're still slower than the OF. */
+#define USB_READ_BUFFER_SIZE (128 * 1024)
+#define USB_WRITE_BUFFER_SIZE (128 * 1024)
#endif
/* Rockbox capabilities */
diff --git a/firmware/export/config/tatungtpj1022.h b/firmware/export/config/tatungtpj1022.h
deleted file mode 100644
index 3865e8f87f..0000000000
--- a/firmware/export/config/tatungtpj1022.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * This config file is for the Tatung Elio TPJ-1022
- */
-
-#define MODEL_NAME "Tatung Elio TPJ-1022"
-
-/* For Rolo and boot loader */
-#define MODEL_NUMBER 15
-
-/* define this if you use an ATA controller */
-#define CONFIG_STORAGE STORAGE_ATA
-
-/*define this if the ATA controller and method of USB access support LBA48 */
-#define HAVE_LBA48
-
-/* define this if you have recording possibility */
-/*#define HAVE_RECORDING*/ /* TODO: add support for this */
-
-/* define the bitmask of hardware sample rates */
-#define HW_SAMPR_CAPS (SAMPR_CAP_96 | SAMPR_CAP_88 | SAMPR_CAP_48 | \
- SAMPR_CAP_44 | SAMPR_CAP_32 | SAMPR_CAP_8)
-
-/* define the bitmask of recording sample rates
-#define REC_SAMPR_CAPS (SAMPR_CAP_96 | SAMPR_CAP_88 | SAMPR_CAP_48 | \
- SAMPR_CAP_44 | SAMPR_CAP_32 | SAMPR_CAP_8) */
-
-
-
-
-/* define this if you have a colour LCD */
-#define HAVE_LCD_COLOR
-
-/* define this if you have access to the quickscreen */
-#define HAVE_QUICKSCREEN
-
-/* LCD dimensions */
-#define LCD_WIDTH 220
-#define LCD_HEIGHT 176
-/* sqrt(220^2 + 176^2) / 2.2 = 128.1 */
-#define LCD_DPI 128
-#define LCD_DEPTH 16 /* 65536 colours */
-#define LCD_PIXELFORMAT RGB565
-
-/* #define IRAM_LCDFRAMEBUFFER IDATA_ATTR *//* put the lcd frame buffer in IRAM */
-
-#define CONFIG_KEYPAD TATUNG_TPJ1022_PAD
-
-
-
-
-/* define this if you have a real-time clock */
-#ifndef BOOTLOADER
-//#define CONFIG_RTC RTC_E8564
-#endif
-
-/* Define this if you have a software controlled poweroff */
-#define HAVE_SW_POWEROFF
-
-/* The number of bytes reserved for loadable codecs */
-#define CODEC_SIZE 0x100000
-
-/* The number of bytes reserved for loadable plugins */
-#define PLUGIN_BUFFER_SIZE 0x80000
-
-/* Define this if you have the WM8731 audio codec */
-#define HAVE_WM8731
-
-#define AB_REPEAT_ENABLE
-
-/* define this if you have a disk storage, i.e. something
- that needs spinups and can cause skips when shaked */
-#define HAVE_DISK_STORAGE
-
-/* Define this for LCD backlight available */
-#define HAVE_BACKLIGHT
-
-#define BATTERY_CAPACITY_DEFAULT 1550 /* default battery capacity
- TODO: check this, probably different
- for different models too */
-#define BATTERY_CAPACITY_MIN 1500 /* min. capacity selectable */
-#define BATTERY_CAPACITY_MAX 1600 /* max. capacity selectable */
-#define BATTERY_CAPACITY_INC 10 /* capacity increment */
-#define BATTERY_TYPES_COUNT 1 /* only one type */
-
-#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE
-
-/* Hardware controlled charging? FIXME */
-#define CONFIG_CHARGING CHARGING_SIMPLE
-
-/* define this if the unit can be powered or charged via USB */
-/*#define HAVE_USB_POWER*/
-
-/* Define this if you have a PortalPlayer PP5020 */
-#define CONFIG_CPU PP5020
-
-/* Define this if you want to use the PP5020 i2c interface */
-#define CONFIG_I2C I2C_PP5020
-
-/* define this if the hardware can be powered off while charging */
-/* TODO: should this be set for the H10? */
-//#define HAVE_POWEROFF_WHILE_CHARGING
-
-/* The start address index for ROM builds */
-#define ROM_START 0x00000000
-
-/* Define this to the CPU frequency */
-/* TODO: this is probably wrong */
-#define CPU_FREQ 11289600
-
-/* Type of LCD */
-#define CONFIG_LCD LCD_TPJ1022
-
-#define DEFAULT_CONTRAST_SETTING 19
-
-/* Offset ( in the firmware file's header ) to the file length */
-#define FIRMWARE_OFFSET_FILE_LENGTH 0
-
-/* Offset ( in the firmware file's header ) to the file CRC */
-#define FIRMWARE_OFFSET_FILE_CRC 0
-
-/* Offset ( in the firmware file's header ) to the real data */
-#define FIRMWARE_OFFSET_FILE_DATA 8
-
-/* USB On-the-go */
-#define CONFIG_USBOTG USBOTG_ARC
-
-/* define this if the unit can be powered or charged via USB */
-#define HAVE_USB_POWER
-
-/* enable these for the experimental usb stack ROOLKU */
-#define HAVE_USBSTACK
-#define USB_VENDOR_ID 0x07B4
-#define USB_PRODUCT_ID 0x0280
-
-/* Define this if you have adjustable CPU frequency */
-#define HAVE_ADJUSTABLE_CPU_FREQ
-
-#define BOOTFILE_EXT "elio"
-#define BOOTFILE "rockbox." BOOTFILE_EXT
-#define BOOTDIR "/.rockbox"
-
-
-/* DMA is used only for reading on PP502x because although reads are ~8x faster
- * writes appear to be ~25% slower.
- */
-#ifndef BOOTLOADER
-#define HAVE_ATA_DMA
-#endif
-
-/* Define this if a programmable hotkey is mapped */
-//#define HAVE_HOTKEY
diff --git a/firmware/export/config/xduoox3.h b/firmware/export/config/xduoox3.h
index 6cc1aa2e57..ea86e60d59 100644
--- a/firmware/export/config/xduoox3.h
+++ b/firmware/export/config/xduoox3.h
@@ -185,7 +185,7 @@
/* enable these for the experimental usb stack */
#define HAVE_USBSTACK
-#define HAVE_BOOTLOADER_USB_MODE
+//#define HAVE_BOOTLOADER_USB_MODE
/* Connect by events, not by tick polling */
#define USB_STATUS_BY_EVENT
diff --git a/firmware/export/eros_qn_codec.h b/firmware/export/eros_qn_codec.h
index 15c745c04b..851ab63362 100644
--- a/firmware/export/eros_qn_codec.h
+++ b/firmware/export/eros_qn_codec.h
@@ -23,10 +23,19 @@
#ifndef _EROS_QN_CODEC_H
#define _EROS_QN_CODEC_H
+/*
+ * Note: Maximum volume is set one step below unity in order to
+ * avoid overflowing pcm samples due to our DC Offset.
+ *
+ * The DAC's output is hot enough this should not be an issue.
+ */
#define PCM5102A_VOLUME_MIN -740
-#define PCM5102A_VOLUME_MAX 0
+#define PCM5102A_VOLUME_MAX -20
+
+/* a small DC offset prevents play/pause clicking due to the DAC auto-muting */
+#define PCM_DC_OFFSET_VALUE -1
-AUDIOHW_SETTING(VOLUME, "dB", 0, 1, PCM5102A_VOLUME_MIN/10, PCM5102A_VOLUME_MAX/10, 0)
+AUDIOHW_SETTING(VOLUME, "dB", 0, 2, PCM5102A_VOLUME_MIN/10, PCM5102A_VOLUME_MAX/10, 0)
/* this just calls audiohw_set_volume() with the last (locally) known volume,
* used for switching to/from fixed line out volume. */
diff --git a/firmware/export/erosqlinux_codec.h b/firmware/export/erosqlinux_codec.h
index b6ab58fa74..ecc10be924 100644
--- a/firmware/export/erosqlinux_codec.h
+++ b/firmware/export/erosqlinux_codec.h
@@ -3,7 +3,16 @@
#define AUDIOHW_CAPS (LINEOUT_CAP)
-AUDIOHW_SETTING(VOLUME, "dB", 0, 2, -74, 0, -40)
+/* a small DC offset prevents play/pause clicking due to the DAC auto-muting */
+#define PCM_DC_OFFSET_VALUE -1
+
+/*
+ * Note: Maximum volume is set one step below unity in order to
+ * avoid overflowing pcm samples due to our DC Offset.
+ *
+ * The DAC's output is hot enough this should not be an issue.
+ */
+AUDIOHW_SETTING(VOLUME, "dB", 0, 2, -74, -2, -40)
//#define AUDIOHW_NEEDS_INITIAL_UNMUTE
diff --git a/firmware/export/logf.h b/firmware/export/logf.h
index c8aaad06b4..7fbe5976a4 100644
--- a/firmware/export/logf.h
+++ b/firmware/export/logf.h
@@ -31,7 +31,7 @@
#define MAX_LOGF_SIZE 16384
-extern unsigned char logfbuffer[MAX_LOGF_SIZE];
+extern unsigned char logfbuffer[MAX_LOGF_SIZE + 1];
extern int logfindex;
extern bool logfwrap;