summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/action.c121
-rw-r--r--apps/action.h6
-rw-r--r--apps/core_keymap.c134
-rw-r--r--apps/core_keymap.h7
-rw-r--r--apps/lang/english.lang10
-rw-r--r--apps/lang/italiano.lang196
-rw-r--r--apps/lang/polski.lang20
-rw-r--r--apps/menus/main_menu.c2
-rw-r--r--apps/onplay.c12
-rw-r--r--apps/onplay.h8
-rw-r--r--apps/playlist.c1
-rw-r--r--apps/playlist_catalog.c4
-rw-r--r--apps/playlist_viewer.c302
-rw-r--r--apps/plugins/brickmania.c15
-rw-r--r--apps/plugins/doom/d_deh.c3
-rw-r--r--apps/plugins/doom/i_video.c3
-rw-r--r--apps/plugins/pictureflow/pictureflow.c5
-rw-r--r--apps/plugins/properties.c3
-rw-r--r--apps/plugins/spacerocks.c4
-rw-r--r--apps/plugins/xworld/engine.c2
-rw-r--r--apps/settings_list.c23
-rw-r--r--apps/tagcache.c2
-rw-r--r--apps/tagtree.c7
-rw-r--r--bootloader/x1000/recovery.c1
-rw-r--r--bootloader/x1000/utils.c105
-rw-r--r--bootloader/x1000/x1000bootloader.h1
-rw-r--r--docs/CREDITS2
-rw-r--r--firmware/buflib.c671
-rw-r--r--firmware/core_alloc.c15
-rw-r--r--firmware/drivers/lcd-16bit-common.c103
-rw-r--r--firmware/drivers/lcd-16bit-vert.c80
-rw-r--r--firmware/drivers/lcd-16bit.c80
-rw-r--r--firmware/drivers/lcd-1bit-vert.c86
-rw-r--r--firmware/drivers/lcd-24bit.c180
-rw-r--r--firmware/drivers/lcd-2bit-horz.c112
-rw-r--r--firmware/drivers/lcd-2bit-vert.c111
-rw-r--r--firmware/drivers/lcd-2bit-vi.c113
-rw-r--r--firmware/drivers/lcd-bitmap-common.c4
-rw-r--r--firmware/drivers/lcd-color-common.c8
-rw-r--r--firmware/export/config.h20
-rw-r--r--firmware/export/config/ipod6g.h8
-rw-r--r--firmware/export/config/mrobe500.h3
-rw-r--r--firmware/export/config/sansaconnect.h3
-rw-r--r--firmware/include/buflib.h44
-rw-r--r--firmware/include/core_alloc.h7
-rw-r--r--firmware/include/rbendian.h237
-rw-r--r--firmware/target/mips/ingenic_x1000/boot-x1000.c17
-rw-r--r--firmware/target/mips/ingenic_x1000/boot-x1000.h4
-rw-r--r--firmware/target/mips/ingenic_x1000/installer-x1000.c4
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.c234
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.h109
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-nand-x1000.c4
-rw-r--r--firmware/usb.c44
-rw-r--r--lib/rbcodec/codecs/libgme/blip_buffer.c2
-rw-r--r--lib/skin_parser/skin_parser.h15
-rw-r--r--manual/appendix/config_file_options.tex6
-rw-r--r--manual/rockbox_interface/hotkeys.tex11
-rwxr-xr-xtools/rockboxdev.sh2
-rw-r--r--utils/rbutilqt/CMakeLists.txt66
-rw-r--r--utils/rbutilqt/base/ziputil.cpp6
-rw-r--r--utils/rbutilqt/base/ziputil.h6
-rw-r--r--wps/WPSLIST2
-rw-r--r--wps/cabbiev2.112x64x1.wps2
-rw-r--r--wps/cabbiev2.128x128x16.wps4
-rw-r--r--wps/cabbiev2.128x128x2.wps4
-rw-r--r--wps/cabbiev2.128x160x16.wps2
-rw-r--r--wps/cabbiev2.128x64x1.wps2
-rw-r--r--wps/cabbiev2.128x96x16.wps4
-rw-r--r--wps/cabbiev2.128x96x2.wps2
-rw-r--r--wps/cabbiev2.132x80x16.wps4
-rw-r--r--wps/cabbiev2.138x110x2.wps4
-rw-r--r--wps/cabbiev2.160x128x1.wps2
-rw-r--r--wps/cabbiev2.160x128x16.wps4
-rw-r--r--wps/cabbiev2.160x128x2.wps4
-rw-r--r--wps/cabbiev2.176x132x16.wps4
-rw-r--r--wps/cabbiev2.176x220x16.wps4
-rw-r--r--wps/cabbiev2.220x176x16.wps4
-rw-r--r--wps/cabbiev2.240x320x16.mini2440.wps4
-rw-r--r--wps/cabbiev2.240x320x16.wps16
-rw-r--r--wps/cabbiev2.240x400x16.wps4
-rw-r--r--wps/cabbiev2.320x240x16.mrobe500.wps2
-rw-r--r--wps/cabbiev2.320x240x16.wps4
-rw-r--r--wps/cabbiev2.320x480x16.wps4
-rw-r--r--wps/cabbiev2.360x400x16.wps8
-rw-r--r--wps/cabbiev2.400x240x16.wps4
-rw-r--r--wps/cabbiev2.480x800x16.wps4
-rw-r--r--wps/cabbiev2.800x480x16.wps4
-rw-r--r--wps/cabbiev2.96x96x16.wps4
88 files changed, 1819 insertions, 1705 deletions
diff --git a/apps/action.c b/apps/action.c
index 9ef10936f2..da08e29dbb 100644
--- a/apps/action.c
+++ b/apps/action.c
@@ -34,6 +34,7 @@
#include "button.h"
#include "action.h"
#include "kernel.h"
+#include "core_alloc.h"
#include "splash.h"
#include "settings.h"
@@ -70,7 +71,7 @@ static action_last_t action_last =
.wait_for_release = false,
#ifndef DISABLE_ACTION_REMAP
- .core_keymap = NULL,
+ .key_remap = 0,
#endif
#ifdef HAVE_TOUCHSCREEN
@@ -601,9 +602,8 @@ static inline void action_code_lookup(action_last_t *last, action_cur_t *cur)
#endif
#ifndef DISABLE_ACTION_REMAP
- bool check_remap = (last->core_keymap != NULL);
/* attempt to look up the button in user supplied remap */
- if(check_remap && (context & CONTEXT_PLUGIN) == 0)
+ if(last->key_remap && (context & CONTEXT_PLUGIN) == 0)
{
#if 0 /*Disable the REMOTE context for remap for now (BUTTON_REMOTE != 0)*/
if ((cur->button & BUTTON_REMOTE) != 0)
@@ -611,7 +611,7 @@ static inline void action_code_lookup(action_last_t *last, action_cur_t *cur)
context |= CONTEXT_REMOTE;
}
#endif
- cur->items = last->core_keymap;
+ cur->items = core_get_data(last->key_remap);
i = 0;
action = ACTION_UNKNOWN;
/* check the lut at the beginning for the desired context */
@@ -1193,66 +1193,89 @@ int get_action(int context, int timeout)
int action_set_keymap(struct button_mapping* core_keymap, int count)
{
+#ifdef DISABLE_ACTION_REMAP
+ (void)core_keymap;
+ (void)count;
+ return -1;
+#else
+ if (count <= 0 || core_keymap == NULL)
+ return action_set_keymap_handle(0, 0);
+
+ size_t keyremap_buf_size = count * sizeof(struct button_mapping);
+ int handle = core_alloc("keyremap", keyremap_buf_size);
+ if (handle < 0)
+ return -6;
+ memcpy(core_get_data(handle), core_keymap, keyremap_buf_size);
+ return action_set_keymap_handle(handle, count);
+#endif
+}
+
+int action_set_keymap_handle(int handle, int count)
+{
#ifdef DISABLE_ACTION_REMAP
- count = -1;
+ (void)core_keymap;
+ (void)count;
+ return -1;
#else
- if (count > 0 && core_keymap != NULL) /* saf-tey checks :) */
+ /* free an existing remap */
+ if (action_last.key_remap > 0)
+ action_last.key_remap = core_free(action_last.key_remap);
+
+ /* if clearing the remap, we're done */
+ if (count <= 0 || handle <= 0)
+ return 0;
+
+ /* validate the keymap */
+ struct button_mapping* core_keymap = core_get_data(handle);
+ struct button_mapping* entry = &core_keymap[count - 1];
+ if (entry->action_code != (int) CONTEXT_STOPSEARCHING ||
+ entry->button_code != BUTTON_NONE) /* check for sentinel at end*/
{
- int i = 0;
- struct button_mapping* entry = &core_keymap[count - 1];
- if (entry->action_code != (int) CONTEXT_STOPSEARCHING ||
- entry->button_code != BUTTON_NONE) /* check for sentinel at end*/
- {
- count = -1;
- }
+ /* missing sentinel entry */
+ return -1;
+ }
- while (count > 0 && /* check the lut at the beginning for invalid offsets */
- (entry = &core_keymap[i])->action_code != (int) CONTEXT_STOPSEARCHING)
- {
-
- if ((entry->action_code & CONTEXT_REMAPPED) == CONTEXT_REMAPPED)
- {
- int firstbtn = entry->button_code;
- int endpos = firstbtn + entry->pre_button_code;
- if (firstbtn > count || firstbtn < i || endpos > count)
- {
- /* offset out of bounds */
- count = -2;
- break;
- }
+ /* check the lut at the beginning for invalid offsets */
+ for (int i = 0; i < count; ++i)
+ {
+ entry = &core_keymap[i];
+ if (entry->action_code == (int)CONTEXT_STOPSEARCHING)
+ break;
- if (core_keymap[endpos].button_code != BUTTON_NONE)
- {
- /* stop sentinel is not at end of action lut*/
- count = -3;
- }
- }
- else /* something other than a context remap in the lut */
+ if ((entry->action_code & CONTEXT_REMAPPED) == CONTEXT_REMAPPED)
+ {
+ int firstbtn = entry->button_code;
+ int endpos = firstbtn + entry->pre_button_code;
+ if (firstbtn > count || firstbtn < i || endpos > count)
{
- count = -4;
- break;
+ /* offset out of bounds */
+ return -2;
}
- i++;
-
- if (i >= count) /* no sentinel in the lut */
+ if (core_keymap[endpos].button_code != BUTTON_NONE)
{
- count = -5;
- break;
+ /* stop sentinel is not at end of action lut */
+ return -3;
}
}
+ else
+ {
+ /* something other than a context remap in the lut */
+ return -4;
+ }
- if (count <= 0)
- core_keymap = NULL;
- }
- else
-#endif
- {
- core_keymap = NULL;
+ if (i+1 >= count)
+ {
+ /* no sentinel in the lut */
+ return -5;
+ }
}
- action_last.core_keymap = core_keymap;
+
+ /* success */
+ action_last.key_remap = handle;
return count;
+#endif
}
int get_custom_action(int context,int timeout,
diff --git a/apps/action.h b/apps/action.h
index 35f08a3dbd..444437edf8 100644
--- a/apps/action.h
+++ b/apps/action.h
@@ -419,7 +419,7 @@ typedef struct
bool wait_for_release;
#ifndef DISABLE_ACTION_REMAP
- struct button_mapping* core_keymap;
+ int key_remap;
#endif
#ifdef HAVE_TOUCHSCREEN
@@ -449,7 +449,9 @@ bool action_userabort(int timeout);
const struct button_mapping* get_context_mapping(int context);
/* load a key map to allow buttons for actions to be remapped see: core_keymap */
-int action_set_keymap(struct button_mapping* core_button_map, int count);
+int action_set_keymap(struct button_mapping* core_keymap, int count);
+/* load keymap in a handle: takes ownership of the handle on success */
+int action_set_keymap_handle(int handle, int count);
/* returns the status code variable from action.c for the button just pressed
If button != NULL it will be set to the actual button code */
diff --git a/apps/core_keymap.c b/apps/core_keymap.c
index dbe7ae0072..9d54fcffac 100644
--- a/apps/core_keymap.c
+++ b/apps/core_keymap.c
@@ -27,119 +27,67 @@
#include "logf.h"
#if !defined(__PCTOOL__) || defined(CHECKWPS)
-static int keymap_handle = -1;
-
-static int core_alloc_keymap(size_t bufsz)
+int core_set_keyremap(struct button_mapping* core_keymap, int count)
{
- keymap_handle = core_alloc_ex("key remap", bufsz, &buflib_ops_locked);
- return keymap_handle;
+ return action_set_keymap(core_keymap, count);
}
-static void core_free_keymap(void)
+static int open_key_remap(const char *filename, int *countp)
{
- action_set_keymap(NULL, -1);
- if (keymap_handle > 0) /* free old buffer */
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ size_t fsize = filesize(fd);
+ int count = fsize / sizeof(struct button_mapping);
+ if (count == 0 || (size_t)(count * sizeof(struct button_mapping)) != fsize)
{
- keymap_handle = core_free(keymap_handle);
+ logf("core_keyremap: bad filesize %d / %lu", count, (unsigned long)fsize);
+ goto error;
}
-}
-
-/* Allocates buffer from core and copies keymap into it */
-int core_set_keyremap(struct button_mapping* core_keymap, int count)
-{
- core_free_keymap();
- if (count > 0)
+ struct button_mapping header;
+ if(read(fd, &header, sizeof(header)) != (ssize_t)sizeof(header))
{
- size_t bufsize = count * sizeof(struct button_mapping);
- if (core_keymap != NULL && core_alloc_keymap(bufsize) > 0)
- {
- char *buf = core_get_data(keymap_handle);
- memcpy(buf, core_keymap, bufsize);
- count = action_set_keymap((struct button_mapping *) buf, count);
- }
- else
- count = -1;
+ logf("core_keyremap: read error");
+ goto error;
}
- return count;
-}
-
-int core_load_key_remap(const char *filename)
-{
- char *buf;
- int fd = -1;
- int count = 0;
- size_t fsize = 0;
- core_free_keymap();
- if (filename != NULL)
- count = open_key_remap(filename, &fd, &fsize);
- while (count > 0)
+ if (header.action_code != KEYREMAP_VERSION ||
+ header.button_code != KEYREMAP_HEADERID ||
+ header.pre_button_code != count)
{
- if (core_alloc_keymap(fsize) <= 0)
- {
- count = -30;
- logf("core_keymap: %d Failed to allocate buffer", count);
- break;
- }
- buf = core_get_data(keymap_handle);
- if (read(fd, buf, fsize) == (ssize_t) fsize)
- {
- count = action_set_keymap((struct button_mapping *) buf, count);
- }
- else
- {
- count = -40;
- logf("core_keymap: %d Failed to read", count);
- }
- break;
+ logf("core_keyremap: bad header %d", count);
+ goto error;
}
+
+ *countp = count - 1;
+ return fd;
+
+ error:
close(fd);
- return count;
+ return -1;
}
-int open_key_remap(const char *filename, int *fd, size_t *fsize)
+int core_load_key_remap(const char *filename)
{
- int count = 0;
+ int count = 0; /* gcc falsely believes this may be used uninitialized */
+ int fd = open_key_remap(filename, &count);
+ if (fd < 0)
+ return -1;
- while (filename && fd && fsize)
+ size_t bufsize = count * sizeof(struct button_mapping);
+ int handle = core_alloc("keyremap", bufsize);
+ if (handle > 0)
{
- *fsize = 0;
- *fd = open(filename, O_RDONLY);
- if (*fd)
- {
- *fsize = filesize(*fd);
-
- count = *fsize / sizeof(struct button_mapping);
-
- if (count * sizeof(struct button_mapping) != *fsize)
- {
- count = -10;
- logf("core_keymap: %d Size mismatch", count);
- break;
- }
+ core_pin(handle);
+ if (read(fd, core_get_data(handle), bufsize) == (ssize_t)bufsize)
+ count = action_set_keymap_handle(handle, count);
- if (count > 1)
- {
- struct button_mapping header = {0};
- read(*fd, &header, sizeof(struct button_mapping));
- if (KEYREMAP_VERSION == header.action_code &&
- KEYREMAP_HEADERID == header.button_code &&
- header.pre_button_code == count)
- {
- count--;
- *fsize -= sizeof(struct button_mapping);
- }
- else /* Header mismatch */
- {
- count = -20;
- logf("core_keymap: %d Header mismatch", count);
- break;
- }
- }
- }
- break;
+ core_unpin(handle);
}
+
+ close(fd);
return count;
}
diff --git a/apps/core_keymap.h b/apps/core_keymap.h
index dad9875364..2077daa685 100644
--- a/apps/core_keymap.h
+++ b/apps/core_keymap.h
@@ -34,13 +34,6 @@
/* Allocates core buffer, copies keymap to allow buttons for actions to be remapped*/
int core_set_keyremap(struct button_mapping* core_keymap, int count);
-/* open_key_remap(filename , *fd (you must close file_descriptor), *fsize)
- * checks/strips header and returns remaining count
- * fd is opened and set to first record
- * filesize contains the size of the remaining records
-*/
-int open_key_remap(const char *filename, int *fd, size_t *filesize);
-
/* load a remap file to allow buttons for actions to be remapped */
int core_load_key_remap(const char *filename);
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 75849714e6..e8d646b258 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -16374,21 +16374,17 @@
user: core
<source>
*: none
- ipod3g: none
- ipod*: "Clear settings when hold switch is on during startup"
+ ipodcolor,ipodnano1g,ipodvideo,ipod4g,ipodmini1g,ipodmini2g: "Clear settings when hold switch is on during startup"
clear_settings_on_hold, iriverh10: "Clear settings when reset button is held during startup"
</source>
<dest>
*: none
- ipod3g: none
- ipod*: "Clear settings when hold switch is on during startup"
+ ipodcolor,ipodnano1g,ipodvideo,ipod4g,ipodmini1g,ipodmini2g: "Clear settings when hold switch is on during startup"
clear_settings_on_hold, iriverh10: "Clear settings when reset button is held during startup"
</dest>
<voice>
*: none
- ipod3g: none
- ipod*: "Clear settings when hold switch is on during startup"
+ ipodcolor,ipodnano1g,ipodvideo,ipod4g,ipodmini1g,ipodmini2g: "Clear settings when hold switch is on during startup"
clear_settings_on_hold, iriverh10: "Clear settings when reset button is held during startup"
</voice>
</phrase>
-
diff --git a/apps/lang/italiano.lang b/apps/lang/italiano.lang
index 0688ca7846..1dc3319e85 100644
--- a/apps/lang/italiano.lang
+++ b/apps/lang/italiano.lang
@@ -13069,16 +13069,16 @@
</phrase>
<phrase>
id: LANG_PROPERTIES_ALBUM
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Album]"
+ *: ""
</source>
<dest>
- *: "[Album]"
+ *: ""
</dest>
<voice>
- *: "Album"
+ *: ""
</voice>
</phrase>
<phrase>
@@ -13198,16 +13198,16 @@
</phrase>
<phrase>
id: LANG_PROPERTIES_ARTIST
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Artist]"
+ *: ""
</source>
<dest>
- *: "[Artista]"
+ *: ""
</dest>
<voice>
- *: "Artista"
+ *: ""
</voice>
</phrase>
<phrase>
@@ -13257,16 +13257,16 @@
</phrase>
<phrase>
id: LANG_PROPERTIES_TITLE
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Title]"
+ *: ""
</source>
<dest>
- *: "[Titolo]"
+ *: ""
</dest>
<voice>
- *: "Titolo"
+ *: ""
</voice>
</phrase>
<phrase>
@@ -13532,16 +13532,16 @@
</phrase>
<phrase>
id: LANG_PROPERTIES_DURATION
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Duration]"
+ *: ""
</source>
<dest>
- *: "[Durata]"
+ *: ""
</dest>
<voice>
- *: "Durata"
+ *: ""
</voice>
</phrase>
<phrase>
@@ -15507,16 +15507,16 @@
</phrase>
<phrase>
id: LANG_CLEAR_LIST_AND_PLAY_NEXT
- desc: in onplay menu. Replace current playlist with selected tracks
+ desc: deprecated
user: core
<source>
- *: "Clear List & Play Next"
+ *: ""
</source>
<dest>
- *: "Cancella Lista e Riproduci Successivo"
+ *: ""
</dest>
<voice>
- *: "Cancella Lista e Riproduci Successivo"
+ *: ""
</voice>
</phrase>
<phrase>
@@ -15637,16 +15637,16 @@
</phrase>
<phrase>
id: LANG_CLEAR_LIST_AND_PLAY_SHUFFLED
- desc: in onplay menu. Replace current playlist with selected tracks in random order.
+ desc: deprecated
user: core
<source>
- *: "Clear List & Play Shuffled"
+ *: ""
</source>
<dest>
- *: "Cancella Lista e Riproduci in Ordine Casuale"
+ *: ""
</dest>
<voice>
- *: "Cancella Lista e Riproduci in Ordine Casuale"
+ *: ""
</voice>
</phrase>
<phrase>
@@ -15874,128 +15874,128 @@
</phrase>
<phrase>
id: LANG_PROPERTIES_ALBUMARTIST
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Album Artist]"
+ *: ""
</source>
<dest>
- *: "[Artista Album]"
+ *: ""
</dest>
<voice>
- *: "Artista Album"
+ *: ""
</voice>
</phrase>
<phrase>
id: LANG_PROPERTIES_GENRE
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Genre]"
+ *: ""
</source>
<dest>
- *: "[Genere]"
+ *: ""
</dest>
<voice>
- *: "Genere"
+ *: ""
</voice>
</phrase>
<phrase>
id: LANG_PROPERTIES_COMMENT
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Comment]"
+ *: ""
</source>
<dest>
- *: "[Commento]"
+ *: ""
</dest>
<voice>
- *: "Commento"
+ *: ""
</voice>
</phrase>
<phrase>
id: LANG_PROPERTIES_COMPOSER
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Composer]"
+ *: ""
</source>
<dest>
- *: "[Compositore]"
+ *: ""
</dest>
<voice>
- *: "Compositore"
+ *: ""
</voice>
</phrase>
<phrase>
id: LANG_PROPERTIES_YEAR
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Year]"
+ *: ""
</source>
<dest>
- *: "[Anno]"
+ *: ""
</dest>
<voice>
- *: "Anno"
+ *: ""
</voice>
</phrase>
<phrase>
id: LANG_PROPERTIES_TRACKNUM
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Tracknum]"
+ *: ""
</source>
<dest>
- *: "[Numtraccia]"
+ *: ""
</dest>
<voice>
- *: "Numero traccia"
+ *: ""
</voice>
</phrase>
<phrase>
id: LANG_PROPERTIES_DISCNUM
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Discnum]"
+ *: ""
</source>
<dest>
- *: "[Numdisco]"
+ *: ""
</dest>
<voice>
- *: "Numero disco"
+ *: ""
</voice>
</phrase>
<phrase>
id: LANG_PROPERTIES_FREQUENCY
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Frequency]"
+ *: ""
</source>
<dest>
- *: "[Frequenza]"
+ *: ""
</dest>
<voice>
- *: "Frequenza"
+ *: ""
</voice>
</phrase>
<phrase>
id: LANG_PROPERTIES_BITRATE
- desc: in properties plugin
+ desc: deprecated
user: core
<source>
- *: "[Bitrate]"
+ *: ""
</source>
<dest>
- *: "[Bitrate]"
+ *: ""
</dest>
<voice>
- *: "Bitrate"
+ *: ""
</voice>
</phrase>
<phrase>
@@ -16239,3 +16239,79 @@
*: "La cache deve prima completare l'aggiornamento!"
</voice>
</phrase>
+<phrase>
+ id: LANG_TRACK_INFO
+ desc: Track Info Title
+ user: core
+ <source>
+ *: "Track Info"
+ </source>
+ <dest>
+ *: "Info Traccia"
+ </dest>
+ <voice>
+ *: "Info Traccia"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PLAY
+ desc: play selected file/directory, in playlist context menu
+ user: core
+ <source>
+ *: "Play"
+ </source>
+ <dest>
+ *: "Riproduci"
+ </dest>
+ <voice>
+ *: "Riproduci"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_PLAY_SHUFFLED
+ desc: play selected files in shuffled order, in playlist context menu
+ user: core
+ <source>
+ *: "Play Shuffled"
+ </source>
+ <dest>
+ *: "Riproduci Casualmente"
+ </dest>
+ <voice>
+ *: "Riproduci Casualmente"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_KEEP_CURRENT_TRACK_ON_REPLACE
+ desc: used in the playlist settings menu
+ user: core
+ <source>
+ *: "Keep Current Track When Replacing Playlist"
+ </source>
+ <dest>
+ *: "Mantieni La Traccia Corrente Quando Sostituisci La Playlist"
+ </dest>
+ <voice>
+ *: "Mantieni La Traccia Corrente Quando Sostituisci La Playlist"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_CLEAR_SETTINGS_ON_HOLD
+ desc: in the system sub menu
+ user: core
+ <source>
+ *: none
+ clear_settings_on_hold,iriverh10: "Clear settings when reset button is held during startup"
+ ipod4g,ipodcolor,ipodmini1g,ipodmini2g,ipodnano1g,ipodvideo: "Clear settings when hold switch is on during startup"
+ </source>
+ <dest>
+ *: none
+ clear_settings_on_hold,iriverh10: "Cancella le impostazioni quando si tiene premuto il pulsante reset durante l'avvio"
+ ipod4g,ipodcolor,ipodmini1g,ipodmini2g,ipodnano1g,ipodvideo: "Cancella le impostazioni quando l'interruttore di blocco è attivo durante l'avvio"
+ </dest>
+ <voice>
+ *: none
+ clear_settings_on_hold,iriverh10: "Cancella le impostazioni quando si tiene premuto il pulsante reset durante l'avvio"
+ ipod4g,ipodcolor,ipodmini1g,ipodmini2g,ipodnano1g,ipodvideo: "Cancella le impostazioni quando l'interruttore di blocco è attivo durante l'avvio"
+ </voice>
+</phrase>
diff --git a/apps/lang/polski.lang b/apps/lang/polski.lang
index 4cef4ba59a..f9650475db 100644
--- a/apps/lang/polski.lang
+++ b/apps/lang/polski.lang
@@ -16301,3 +16301,23 @@
*: "Zachowaj bieżący utwór podczas zastępowania listy odtwarzania"
</voice>
</phrase>
+<phrase>
+ id: LANG_CLEAR_SETTINGS_ON_HOLD
+ desc: in the system sub menu
+ user: core
+ <source>
+ *: none
+ clear_settings_on_hold,iriverh10: "Clear settings when reset button is held during startup"
+ ipod4g,ipodcolor,ipodmini1g,ipodmini2g,ipodnano1g,ipodvideo: "Clear settings when hold switch is on during startup"
+ </source>
+ <dest>
+ *: none
+ clear_settings_on_hold,iriverh10: "Wyczyść ustawienia, gdy przycisk resetowania będzie przytrzymany podczas uruchamiania"
+ ipod4g,ipodcolor,ipodmini1g,ipodmini2g,ipodnano1g,ipodvideo: "Wyczyść ustawienia, gdy przełącznik blokady będzie włączony podczas uruchamiania"
+ </dest>
+ <voice>
+ *: none
+ clear_settings_on_hold,iriverh10: "Wyczyść ustawienia, gdy przycisk resetowania będzie przytrzymany podczas uruchamiania"
+ ipod4g,ipodcolor,ipodmini1g,ipodmini2g,ipodnano1g,ipodvideo: "Wyczyść ustawienia, gdy przełącznik blokady będzie włączony podczas uruchamiania"
+ </voice>
+</phrase>
diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c
index 5e9b935937..321f2cdec4 100644
--- a/apps/menus/main_menu.c
+++ b/apps/menus/main_menu.c
@@ -338,7 +338,7 @@ static int info_speak_item(int selected_item, void * data)
#ifdef HAVE_RECORDING
case INFO_REC_DIR:
talk_id(LANG_REC_DIR, false);
- if (global_settings.rec_directory && global_settings.rec_directory[0])
+ if (global_settings.rec_directory[0])
{
long *pathsep = NULL;
char rec_directory[MAX_PATHNAME+1];
diff --git a/apps/onplay.c b/apps/onplay.c
index c52bd6101c..e44e81ee5d 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -1860,12 +1860,20 @@ static struct hotkey_assignment hotkey_items[] = {
{ HOTKEY_INSERT_SHUFFLED, LANG_INSERT_SHUFFLED,
HOTKEY_FUNC(playlist_insert_shuffled, NULL),
ONPLAY_RELOAD_DIR },
- { HOTKEY_PLUGIN, LANG_OPEN_PLUGIN,
+ { HOTKEY_PLUGIN, LANG_OPEN_PLUGIN,
HOTKEY_FUNC(hotkey_run_plugin, NULL),
ONPLAY_OK },
- { HOTKEY_BOOKMARK, LANG_BOOKMARK_MENU_CREATE,
+ { HOTKEY_BOOKMARK, LANG_BOOKMARK_MENU_CREATE,
HOTKEY_FUNC(bookmark_create_menu, NULL),
ONPLAY_OK },
+ { HOTKEY_PROPERTIES, LANG_PROPERTIES,
+ HOTKEY_FUNC(onplay_load_plugin, (void *)"properties"),
+ ONPLAY_RELOAD_DIR },
+#ifdef HAVE_TAGCACHE
+ { HOTKEY_PICTUREFLOW, LANG_ONPLAY_PICTUREFLOW,
+ HOTKEY_FUNC(onplay_load_plugin, (void *)"pictureflow"),
+ ONPLAY_RELOAD_DIR },
+#endif
};
/* Return the language ID for this action */
diff --git a/apps/onplay.h b/apps/onplay.h
index 3a259d68e6..3121c918ac 100644
--- a/apps/onplay.h
+++ b/apps/onplay.h
@@ -39,14 +39,18 @@ int get_hotkey_lang_id(int action);
enum hotkey_action {
HOTKEY_OFF = 0,
HOTKEY_VIEW_PLAYLIST,
+ HOTKEY_PROPERTIES,
+#ifdef HAVE_TAGCACHE
+ HOTKEY_PICTUREFLOW,
+#endif
HOTKEY_SHOW_TRACK_INFO,
HOTKEY_PITCHSCREEN,
HOTKEY_OPEN_WITH,
HOTKEY_DELETE,
+ HOTKEY_BOOKMARK,
+ HOTKEY_PLUGIN,
HOTKEY_INSERT,
HOTKEY_INSERT_SHUFFLED,
- HOTKEY_PLUGIN,
- HOTKEY_BOOKMARK,
};
#endif
diff --git a/apps/playlist.c b/apps/playlist.c
index b1d5d5a4be..70a1a0823e 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -2154,6 +2154,7 @@ int playlist_resume(void)
}
buffer = core_get_data(handle);
+ playlist_shutdown(); /* flush any cached control commands to disk */
empty_playlist(playlist, true);
playlist->control_fd = open(playlist->control_filename, O_RDWR);
diff --git a/apps/playlist_catalog.c b/apps/playlist_catalog.c
index ba12ff6d98..98a2bb4cdb 100644
--- a/apps/playlist_catalog.c
+++ b/apps/playlist_catalog.c
@@ -233,8 +233,10 @@ static int add_to_playlist(const char* playlist, bool new_playlist,
fd = open(playlist, O_CREAT|O_WRONLY|O_APPEND, 0666);
if(fd < 0)
+ {
+ splash(HZ*2, ID2P(LANG_FAILED));
return result;
-
+ }
/* In case we're in the playlist directory */
reload_directory();
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c
index a94e07643e..2f23d87c2b 100644
--- a/apps/playlist_viewer.c
+++ b/apps/playlist_viewer.c
@@ -73,6 +73,15 @@ enum direction
BACKWARD
};
+enum pv_onplay_result {
+ PV_ONPLAY_USB,
+ PV_ONPLAY_USB_CLOSED,
+ PV_ONPLAY_CLOSED,
+ PV_ONPLAY_ITEM_REMOVED,
+ PV_ONPLAY_CHANGED,
+ PV_ONPLAY_UNCHANGED,
+};
+
struct playlist_buffer
{
char *name_buffer; /* Buffer used to store track names */
@@ -108,6 +117,8 @@ static struct playlist_viewer viewer;
/* Used when viewing playlists on disk */
static struct playlist_info temp_playlist;
+static bool dirty = false;
+
static void playlist_buffer_init(struct playlist_buffer *pb, char *names_buffer,
int names_buffer_size);
static void playlist_buffer_load_entries(struct playlist_buffer * pb, int index,
@@ -126,7 +137,9 @@ static void format_line(const struct playlist_entry* track, char* str,
int len);
static bool update_playlist(bool force);
-static int onplay_menu(int index);
+static enum pv_onplay_result onplay_menu(int index);
+
+static void close_playlist_viewer(void);
static void playlist_buffer_init(struct playlist_buffer *pb, char *names_buffer,
int names_buffer_size)
@@ -479,7 +492,7 @@ static bool update_playlist(bool force)
return true;
}
-static int show_track_info(struct playlist_entry *current_track)
+static enum pv_onplay_result show_track_info(const struct playlist_entry *current_track)
{
struct mp3entry id3;
bool id3_retrieval_successful = false;
@@ -494,15 +507,63 @@ static int show_track_info(struct playlist_entry *current_track)
return id3_retrieval_successful &&
browse_id3(&id3, current_track->index + 1,
- viewer.num_tracks) ? -1 : 0;
+ viewer.num_tracks) ? PV_ONPLAY_USB : PV_ONPLAY_UNCHANGED;
+}
+
+
+#ifdef HAVE_HOTKEY
+static enum pv_onplay_result open_with(const struct playlist_entry *current_track)
+{
+ char selected_track[MAX_PATH];
+ close_playlist_viewer();
+ snprintf(selected_track, sizeof(selected_track), "%s", current_track->name);
+
+ return (filetype_list_viewers(selected_track) ==
+ PLUGIN_USB_CONNECTED ? PV_ONPLAY_USB_CLOSED : PV_ONPLAY_CLOSED);
+}
+#endif /* HAVE_HOTKEY */
+
+#ifdef HAVE_TAGCACHE
+static enum pv_onplay_result open_pictureflow(const struct playlist_entry *current_track)
+{
+ char selected_track[MAX_PATH];
+ close_playlist_viewer();
+ snprintf(selected_track, sizeof(selected_track), "%s", current_track->name);
+
+ return (filetype_load_plugin((void *)"pictureflow", selected_track) ==
+ PLUGIN_USB_CONNECTED ? PV_ONPLAY_USB_CLOSED : PV_ONPLAY_CLOSED);
+}
+#endif
+
+static enum pv_onplay_result delete_track(int current_track_index,
+ int index, bool current_was_playing)
+{
+ playlist_delete(viewer.playlist, current_track_index);
+ if (current_was_playing)
+ {
+ if (playlist_amount_ex(viewer.playlist) <= 0)
+ audio_stop();
+ else
+ {
+ /* Start playing new track except if it's the lasttrack
+ track in the playlist and repeat mode is disabled */
+ struct playlist_entry *current_track =
+ playlist_buffer_get_track(&viewer.buffer, index);
+ if (current_track->display_index != viewer.num_tracks ||
+ global_settings.repeat_mode == REPEAT_ALL)
+ {
+ audio_play(0, 0);
+ viewer.current_playing_track = -1;
+ }
+ }
+ }
+ return PV_ONPLAY_ITEM_REMOVED;
}
-/* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen.
- Returns -1 if USB attached, 0 if no playlist change, 1 if playlist
- changed, 2 if a track was removed from the playlist */
-static int onplay_menu(int index)
+/* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen. */
+static enum pv_onplay_result onplay_menu(int index)
{
- int result, ret = 0;
+ int result, ret = PV_ONPLAY_UNCHANGED;
struct playlist_entry * current_track =
playlist_buffer_get_track(&viewer.buffer, index);
MENUITEM_STRINGLIST(menu_items, ID2P(LANG_PLAYLIST), NULL,
@@ -510,13 +571,18 @@ static int onplay_menu(int index)
ID2P(LANG_REMOVE), ID2P(LANG_MOVE), ID2P(LANG_MENU_SHOW_ID3_INFO),
ID2P(LANG_SHUFFLE),
ID2P(LANG_SAVE),
- ID2P(LANG_PLAYLISTVIEWER_SETTINGS));
- bool current = (current_track->index == viewer.current_playing_track);
+ ID2P(LANG_PLAYLISTVIEWER_SETTINGS)
+#ifdef HAVE_TAGCACHE
+ ,ID2P(LANG_ONPLAY_PICTUREFLOW)
+#endif
+ );
+
+ bool current_was_playing = (current_track->index == viewer.current_playing_track);
result = do_menu(&menu_items, NULL, NULL, false);
if (result == MENU_ATTACHED_USB)
{
- ret = -1;
+ ret = PV_ONPLAY_USB;
}
else if (result >= 0)
{
@@ -529,41 +595,21 @@ static int onplay_menu(int index)
case 0:
/* playlist */
onplay_show_playlist_menu(current_track->name, NULL);
- ret = 0;
+ ret = PV_ONPLAY_UNCHANGED;
break;
case 1:
/* add to catalog */
onplay_show_playlist_cat_menu(current_track->name);
- ret = 0;
+ ret = PV_ONPLAY_UNCHANGED;
break;
case 2:
- /* delete track */
- playlist_delete(viewer.playlist, current_track->index);
- if (current)
- {
- if (playlist_amount_ex(viewer.playlist) <= 0)
- audio_stop();
- else
- {
- /* Start playing new track except if it's the lasttrack
- track in the playlist and repeat mode is disabled */
- current_track =
- playlist_buffer_get_track(&viewer.buffer, index);
- if (current_track->display_index!=viewer.num_tracks ||
- global_settings.repeat_mode == REPEAT_ALL)
- {
- audio_play(0, 0);
- viewer.current_playing_track = -1;
- }
- }
- }
- ret = 2;
+ ret = delete_track(current_track->index, index, current_was_playing);
break;
case 3:
/* move track */
viewer.moving_track = index;
viewer.moving_playlist_index = current_track->index;
- ret = 0;
+ ret = PV_ONPLAY_UNCHANGED;
break;
case 4:
ret = show_track_info(current_track);
@@ -571,18 +617,23 @@ static int onplay_menu(int index)
case 5:
/* shuffle */
playlist_randomise(viewer.playlist, current_tick, false);
- ret = 1;
+ ret = PV_ONPLAY_CHANGED;
break;
case 6:
/* save playlist */
save_playlist_screen(viewer.playlist);
- ret = 0;
+ ret = PV_ONPLAY_UNCHANGED;
break;
case 7:
/* playlist viewer settings */
result = do_menu(&viewer_settings_menu, NULL, NULL, false);
- ret = (result == MENU_ATTACHED_USB) ? -1 : 0;
+ ret = (result == MENU_ATTACHED_USB) ? PV_ONPLAY_USB : PV_ONPLAY_UNCHANGED;
break;
+#ifdef HAVE_TAGCACHE
+ case 8:
+ ret = open_pictureflow(current_track);
+ break;
+#endif
}
}
return ret;
@@ -691,6 +742,71 @@ static int playlist_callback_voice(int selected_item, void *data)
return 0;
}
+static void update_lists(struct gui_synclist * playlist_lists)
+{
+ gui_synclist_set_voice_callback(playlist_lists,
+ global_settings.talk_file?
+ &playlist_callback_voice:NULL);
+ gui_synclist_set_icon_callback(playlist_lists,
+ global_settings.playlist_viewer_icons?
+ &playlist_callback_icons:NULL);
+ gui_synclist_set_title(playlist_lists, str(LANG_PLAYLIST), Icon_Playlist);
+ gui_synclist_draw(playlist_lists);
+ gui_synclist_speak_item(playlist_lists);
+}
+
+static bool update_viewer_with_changes(struct gui_synclist *playlist_lists, enum pv_onplay_result res)
+{
+ bool exit = false;
+ if (res == PV_ONPLAY_CHANGED ||
+ res == PV_ONPLAY_ITEM_REMOVED)
+ {
+ if (res == PV_ONPLAY_ITEM_REMOVED)
+ gui_synclist_del_item(playlist_lists);
+ update_playlist(true);
+ if (viewer.num_tracks <= 0)
+ exit = true;
+ if (viewer.selected_track >= viewer.num_tracks)
+ viewer.selected_track = viewer.num_tracks-1;
+ dirty = true;
+ }
+ /* the show_icons option in the playlist viewer settings
+ * menu might have changed */
+ update_lists(playlist_lists);
+ return exit;
+}
+
+static void prepare_lists(struct gui_synclist * playlist_lists)
+{
+ gui_synclist_init(playlist_lists, playlist_callback_name,
+ &viewer, false, 1, NULL);
+ gui_synclist_set_voice_callback(playlist_lists,
+ global_settings.talk_file ?
+ &playlist_callback_voice : NULL);
+ gui_synclist_set_icon_callback(playlist_lists,
+ global_settings.playlist_viewer_icons ?
+ &playlist_callback_icons : NULL);
+ gui_synclist_set_nb_items(playlist_lists, viewer.num_tracks);
+ gui_synclist_set_title(playlist_lists, str(LANG_PLAYLIST), Icon_Playlist);
+ gui_synclist_select_item(playlist_lists, viewer.selected_track);
+ gui_synclist_draw(playlist_lists);
+ gui_synclist_speak_item(playlist_lists);
+}
+
+static bool open_playlist_viewer(const char* filename,
+ struct gui_synclist *playlist_lists,
+ bool reload)
+{
+ push_current_activity(ACTIVITY_PLAYLISTVIEWER);
+
+ if (!playlist_viewer_init(&viewer, filename, reload))
+ return false;
+
+ prepare_lists(playlist_lists);
+
+ return true;
+}
+
/* Main viewer function. Filename identifies playlist to be viewed. If NULL,
view current playlist. */
enum playlist_viewer_result playlist_viewer_ex(const char* filename)
@@ -698,25 +814,11 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename)
enum playlist_viewer_result ret = PLAYLIST_VIEWER_OK;
bool exit = false; /* exit viewer */
int button;
- bool dirty = false;
struct gui_synclist playlist_lists;
- if (!playlist_viewer_init(&viewer, filename, false))
+
+ if (!open_playlist_viewer(filename, &playlist_lists, false))
goto exit;
- push_current_activity(ACTIVITY_PLAYLISTVIEWER);
- gui_synclist_init(&playlist_lists, playlist_callback_name,
- &viewer, false, 1, NULL);
- gui_synclist_set_voice_callback(&playlist_lists,
- global_settings.talk_file?
- &playlist_callback_voice:NULL);
- gui_synclist_set_icon_callback(&playlist_lists,
- global_settings.playlist_viewer_icons?
- &playlist_callback_icons:NULL);
- gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
- gui_synclist_set_title(&playlist_lists, str(LANG_PLAYLIST), Icon_Playlist);
- gui_synclist_select_item(&playlist_lists, viewer.selected_track);
- gui_synclist_draw(&playlist_lists);
- gui_synclist_speak_item(&playlist_lists);
while (!exit)
{
int track;
@@ -842,36 +944,22 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename)
}
case ACTION_STD_CONTEXT:
{
- /* ON+PLAY menu */
- int ret_val;
-
- ret_val = onplay_menu(viewer.selected_track);
+ int pv_onplay_result = onplay_menu(viewer.selected_track);
- if (ret_val < 0)
+ if (pv_onplay_result == PV_ONPLAY_USB)
{
ret = PLAYLIST_VIEWER_USB;
goto exit;
}
- else if (ret_val > 0)
+ else if (pv_onplay_result == PV_ONPLAY_USB_CLOSED)
+ return PLAYLIST_VIEWER_USB;
+ else if (pv_onplay_result == PV_ONPLAY_CLOSED)
{
- /* Playlist changed */
- if (ret_val == 2)
- gui_synclist_del_item(&playlist_lists);
- update_playlist(true);
- if (viewer.num_tracks <= 0)
- exit = true;
- if (viewer.selected_track >= viewer.num_tracks)
- viewer.selected_track = viewer.num_tracks-1;
- dirty = true;
+ if (!open_playlist_viewer(filename, &playlist_lists, true))
+ goto exit;
+ break;
}
- /* the show_icons option in the playlist viewer settings
- * menu might have changed */
- gui_synclist_set_icon_callback(&playlist_lists,
- global_settings.playlist_viewer_icons?
- &playlist_callback_icons:NULL);
- gui_synclist_set_title(&playlist_lists, playlist_lists.title, playlist_lists.title_icon);
- gui_synclist_draw(&playlist_lists);
- gui_synclist_speak_item(&playlist_lists);
+ exit = update_viewer_with_changes(&playlist_lists, pv_onplay_result);
break;
}
case ACTION_STD_MENU:
@@ -883,18 +971,50 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename)
{
quick_screen_quick(button);
update_playlist(true);
- gui_synclist_set_voice_callback(&playlist_lists,
- global_settings.talk_file?
- &playlist_callback_voice:NULL);
- gui_synclist_set_icon_callback(&playlist_lists,
- global_settings.playlist_viewer_icons?
- &playlist_callback_icons:NULL);
- gui_synclist_set_title(&playlist_lists, str(LANG_PLAYLIST), Icon_Playlist);
- gui_synclist_draw(&playlist_lists);
- gui_synclist_speak_item(&playlist_lists);
- break;
+ update_lists(&playlist_lists);
}
+ break;
+#endif
+#ifdef HAVE_HOTKEY
+ case ACTION_TREE_HOTKEY:
+ {
+ struct playlist_entry *current_track = playlist_buffer_get_track(
+ &viewer.buffer,
+ viewer.selected_track);
+ enum pv_onplay_result (*do_plugin)(const struct playlist_entry *) = NULL;
+#ifdef HAVE_TAGCACHE
+ if (global_settings.hotkey_tree == HOTKEY_PICTUREFLOW)
+ do_plugin = &open_pictureflow;
#endif
+ if (global_settings.hotkey_tree == HOTKEY_OPEN_WITH)
+ do_plugin = &open_with;
+
+ if (do_plugin != NULL)
+ {
+ if (do_plugin(current_track) == PV_ONPLAY_USB_CLOSED)
+ return PLAYLIST_VIEWER_USB;
+ else if (!open_playlist_viewer(filename, &playlist_lists, true))
+ goto exit;
+ }
+ else if (global_settings.hotkey_tree == HOTKEY_PROPERTIES)
+ {
+ if (show_track_info(current_track) == PV_ONPLAY_USB)
+ {
+ ret = PLAYLIST_VIEWER_USB;
+ goto exit;
+ }
+ update_lists(&playlist_lists);
+ }
+ else if (global_settings.hotkey_tree == HOTKEY_DELETE)
+ exit = update_viewer_with_changes(&playlist_lists,
+ delete_track(current_track->index,
+ viewer.selected_track,
+ (current_track->index == viewer.current_playing_track)));
+ else
+ onplay(current_track->name, FILE_ATTR_AUDIO, CONTEXT_STD, true);
+ break;
+ }
+#endif /* HAVE_HOTKEY */
default:
if(default_event_handler(button) == SYS_USB_CONNECTED)
{
@@ -906,6 +1026,12 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename)
}
exit:
+ close_playlist_viewer();
+ return ret;
+}
+
+static void close_playlist_viewer(void)
+{
talk_shutup();
pop_current_activity();
if (viewer.playlist)
@@ -914,7 +1040,7 @@ exit:
save_playlist_screen(viewer.playlist);
playlist_close(viewer.playlist);
}
- return ret;
+ dirty = false;
}
static const char* playlist_search_callback_name(int selected_item, void * data,
diff --git a/apps/plugins/brickmania.c b/apps/plugins/brickmania.c
index 4983d5a417..3e7ea27441 100644
--- a/apps/plugins/brickmania.c
+++ b/apps/plugins/brickmania.c
@@ -111,8 +111,7 @@
#elif CONFIG_KEYPAD == SANSA_C200_PAD || \
CONFIG_KEYPAD == SANSA_CLIP_PAD || \
-CONFIG_KEYPAD == SANSA_M200_PAD || \
-CONFIG_KEYPAD == SANSA_CONNECT_PAD
+CONFIG_KEYPAD == SANSA_M200_PAD
#define QUIT BUTTON_POWER
#define LEFT BUTTON_LEFT
#define RIGHT BUTTON_RIGHT
@@ -122,6 +121,18 @@ CONFIG_KEYPAD == SANSA_CONNECT_PAD
#define UP BUTTON_UP
#define DOWN BUTTON_DOWN
+#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define QUIT BUTTON_POWER
+#define LEFT BUTTON_LEFT
+#define RIGHT BUTTON_RIGHT
+#define SELECT BUTTON_SELECT
+#define UP BUTTON_UP
+#define DOWN BUTTON_DOWN
+
+#define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
+#define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
+
+
#elif CONFIG_KEYPAD == IRIVER_H10_PAD
#define QUIT BUTTON_POWER
#define LEFT BUTTON_LEFT
diff --git a/apps/plugins/doom/d_deh.c b/apps/plugins/doom/d_deh.c
index 1a399e3b49..0a67aa0aad 100644
--- a/apps/plugins/doom/d_deh.c
+++ b/apps/plugins/doom/d_deh.c
@@ -63,7 +63,7 @@ char* strlwr(char* str)
typedef struct {
const byte *inp; // Pointer to string
size_t size; // Bytes remaining in string
- int fd; // Current file descriptor
+ int fd; // Current file descriptor
} DEHFILE;
// killough 10/98: emulate IO whether input really comes from a file or not
@@ -2868,6 +2868,7 @@ boolean deh_GetData(char *s, char *k, uint_64_t *l, char **strval, int fpout)
if (*t == '=') break;
buffer[i] = *t; // copy it
}
+ if (i == 0) i = 1; /* Just in case */
buffer[--i] = '\0'; // terminate the key before the '='
if (!*t) // end of string with no equal sign
{
diff --git a/apps/plugins/doom/i_video.c b/apps/plugins/doom/i_video.c
index f5d07a8354..79f3212467 100644
--- a/apps/plugins/doom/i_video.c
+++ b/apps/plugins/doom/i_video.c
@@ -453,6 +453,9 @@ void I_ShutdownGraphics(void)
#define DOOMBUTTON_MAP BUTTON_BOTTOMRIGHT
#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
+#define DOOMBUTTON_SCROLLWHEEL
+#define DOOMBUTTON_SCROLLWHEEL_CC BUTTON_SCROLL_BACK
+#define DOOMBUTTON_SCROLLWHEEL_CW BUTTON_SCROLL_FWD
#define DOOMBUTTON_UP BUTTON_UP
#define DOOMBUTTON_DOWN BUTTON_DOWN
#define DOOMBUTTON_LEFT BUTTON_LEFT
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c
index 2f075a7e61..0e5585681d 100644
--- a/apps/plugins/pictureflow/pictureflow.c
+++ b/apps/plugins/pictureflow/pictureflow.c
@@ -963,6 +963,9 @@ const struct custom_format format_transposed = {
static const struct button_mapping* get_context_map(int context)
{
+#ifdef HAVE_LOCKED_ACTIONS
+ context &= ~CONTEXT_LOCKED;
+#endif
return pf_contexts[context & ~CONTEXT_PLUGIN];
}
@@ -4214,7 +4217,7 @@ static void set_initial_slide(const char* selected_file)
pf_cfg.last_album);
else
{
- struct mp3entry id3;
+ static struct mp3entry id3;
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
if (rb->tagcache_fill_tags(&id3, selected_file))
set_current_slide(id3_get_index(&id3));
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
index e5f00e307b..c4378a0356 100644
--- a/apps/plugins/properties.c
+++ b/apps/plugins/properties.c
@@ -313,7 +313,8 @@ enum plugin_status plugin_start(const void* parameter)
int button;
bool quit = false, usb = false;
const char *file = parameter;
- if(!parameter) return PLUGIN_ERROR;
+ if(!parameter || (file[0] != '/')) return PLUGIN_ERROR;
+
#ifdef HAVE_TOUCHSCREEN
rb->touchscreen_set_mode(rb->global_settings->touch_mode);
#endif
diff --git a/apps/plugins/spacerocks.c b/apps/plugins/spacerocks.c
index 8203fad612..1099672c4c 100644
--- a/apps/plugins/spacerocks.c
+++ b/apps/plugins/spacerocks.c
@@ -259,8 +259,8 @@
#define AST_QUIT BUTTON_POWER
#define AST_THRUST BUTTON_UP
#define AST_HYPERSPACE BUTTON_DOWN
-#define AST_LEFT BUTTON_LEFT
-#define AST_RIGHT BUTTON_RIGHT
+#define AST_LEFT BUTTON_SCROLL_BACK
+#define AST_RIGHT BUTTON_SCROLL_FWD
#define AST_FIRE BUTTON_SELECT
#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
diff --git a/apps/plugins/xworld/engine.c b/apps/plugins/xworld/engine.c
index b09e320078..d99d9df6c6 100644
--- a/apps/plugins/xworld/engine.c
+++ b/apps/plugins/xworld/engine.c
@@ -293,7 +293,7 @@ void engine_processInput(struct Engine* e) {
e->sys->input.save = false;
}
if (e->sys->input.fastMode) {
- e->vm._fastMode = !&e->vm._fastMode;
+ e->vm._fastMode = !e->vm._fastMode;
e->sys->input.fastMode = false;
}
if (e->sys->input.stateSlot != 0) {
diff --git a/apps/settings_list.c b/apps/settings_list.c
index fc526987e2..699afb92fd 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -240,8 +240,10 @@ static const char graphic_numeric[] = "graphic,numeric";
#define DEFAULT_FONTNAME "08-Rockfont"
#elif LCD_HEIGHT <= 220
#define DEFAULT_FONT_HEIGHT 12
-#elif LCD_HEIGHT <= 320
+#elif LCD_HEIGHT <= 240
#define DEFAULT_FONT_HEIGHT 15
+#elif LCD_HEIGHT <= 320
+ #define DEFAULT_FONT_HEIGHT 18
#elif defined(SHANLING_Q1)
/* 16pt font looks pretty aliased & ugly */
#define DEFAULT_FONT_HEIGHT 18
@@ -2113,10 +2115,23 @@ const struct settings_list settings[] = {
HOTKEY_OPEN_WITH, HOTKEY_DELETE, HOTKEY_BOOKMARK, HOTKEY_PLUGIN),
TABLE_SETTING(F_ALLOW_ARBITRARY_VALS, hotkey_tree,
LANG_HOTKEY_FILE_BROWSER, HOTKEY_OFF, "hotkey tree",
- "off,open with,delete,insert,insert shuffled",
- UNIT_INT, hotkey_formatter, hotkey_getlang, NULL, 5, HOTKEY_OFF,
- HOTKEY_OPEN_WITH, HOTKEY_DELETE, HOTKEY_INSERT, HOTKEY_INSERT_SHUFFLED),
+#ifdef HAVE_TAGCACHE
+ "off,properties,pictureflow,open with,delete,insert,insert shuffled",
+#else
+ "off,properties,open with,delete,insert,insert shuffled",
#endif
+ UNIT_INT, hotkey_formatter, hotkey_getlang, NULL,
+#ifdef HAVE_TAGCACHE
+ 7,
+#else
+ 6,
+#endif
+ HOTKEY_OFF,HOTKEY_PROPERTIES,
+#ifdef HAVE_TAGCACHE
+ HOTKEY_PICTUREFLOW,
+#endif
+ HOTKEY_OPEN_WITH, HOTKEY_DELETE, HOTKEY_INSERT, HOTKEY_INSERT_SHUFFLED),
+#endif /* HAVE_HOTKEY */
INT_SETTING(F_TIME_SETTING, resume_rewind, LANG_RESUME_REWIND, 0,
"resume rewind", UNIT_SEC, 0, 60, 5,
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 436d85812b..8db1569379 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -170,7 +170,7 @@ static const char * const tag_type_str[] = {
#endif /* ndef LOGF_ENABLE */
/* Status information of the tagcache. */
-static struct tagcache_stat tc_stat;
+struct tagcache_stat tc_stat;
/* Queue commands. */
enum tagcache_queue {
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 45d2bb991b..2694a764a0 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -1429,6 +1429,10 @@ static struct tagentry* get_entries(struct tree_context *tc)
return core_get_data(tc->cache.entries_handle);
}
+#ifdef HAVE_TC_RAMCACHE
+extern struct tagcache_stat tc_stat;
+#endif
+
static int retrieve_entries(struct tree_context *c, int offset, bool init)
{
struct tagcache_search tcs;
@@ -1447,6 +1451,9 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
otherwise show it after the normal 1/2 second delay */
show_search_progress(
#ifdef HAVE_DISK_STORAGE
+#ifdef HAVE_TC_RAMCACHE
+ tc_stat.ramcache ? true :
+#endif
storage_disk_is_active()
#else
true
diff --git a/bootloader/x1000/recovery.c b/bootloader/x1000/recovery.c
index e6cc041d99..371500826f 100644
--- a/bootloader/x1000/recovery.c
+++ b/bootloader/x1000/recovery.c
@@ -69,6 +69,7 @@ static const struct menuitem debug_menu_items[] = {
{MENUITEM_ACTION, "Enable screenshots", &screenshot_enable},
#endif
{MENUITEM_ACTION, "Flash info", &show_flash_info},
+ {MENUITEM_ACTION, "Flash ONFI info", &show_flash_onfi_info},
#ifdef OF_PLAYER_ADDR
{MENUITEM_ACTION, "Dump OF player", &dump_of_player},
#endif
diff --git a/bootloader/x1000/utils.c b/bootloader/x1000/utils.c
index 17eb502e1b..a2fd500f5d 100644
--- a/bootloader/x1000/utils.c
+++ b/bootloader/x1000/utils.c
@@ -146,14 +146,15 @@ int load_uimage_file(const char* filename,
struct nand_reader_data
{
- nand_drv* ndrv;
+ struct nand_drv* ndrv;
nand_page_t page;
nand_page_t end_page;
unsigned offset;
uint32_t count;
};
-static int uimage_nand_reader_init(struct nand_reader_data* d, nand_drv* ndrv,
+static int uimage_nand_reader_init(struct nand_reader_data* d,
+ struct nand_drv* ndrv,
uint32_t addr, uint32_t length)
{
unsigned pg_size = ndrv->chip->page_size;
@@ -177,7 +178,7 @@ static int uimage_nand_reader_init(struct nand_reader_data* d, nand_drv* ndrv,
static ssize_t uimage_nand_reader(void* buf, size_t count, void* rctx)
{
struct nand_reader_data* d = rctx;
- nand_drv* ndrv = d->ndrv;
+ struct nand_drv* ndrv = d->ndrv;
unsigned pg_size = ndrv->chip->page_size;
size_t read_count = 0;
int rc;
@@ -188,6 +189,15 @@ static ssize_t uimage_nand_reader(void* buf, size_t count, void* rctx)
while(d->page < d->end_page && read_count < count) {
rc = nand_page_read(ndrv, d->page, ndrv->page_buf);
+
+ /* Ignore ECC errors on the first page of a block. This may
+ * indicate a bad block. */
+ if(rc == NAND_ERR_ECC_FAIL &&
+ d->page % ndrv->ppb == 0 && d->offset == 0) {
+ d->page += ndrv->ppb;
+ continue;
+ }
+
if(rc < 0)
return -1;
@@ -223,7 +233,7 @@ static ssize_t uimage_nand_reader(void* buf, size_t count, void* rctx)
int load_uimage_flash(uint32_t addr, uint32_t length,
struct uimage_header* uh, size_t* sizep)
{
- nand_drv* ndrv = nand_init();
+ struct nand_drv* ndrv = nand_init();
nand_lock(ndrv);
if(nand_open(ndrv) != NAND_SUCCESS) {
splashf(5*HZ, "NAND open failed");
@@ -259,7 +269,7 @@ int dump_flash(int fd, uint32_t addr, uint32_t length)
static char buf[8192];
int ret = 0;
- nand_drv* ndrv = nand_init();
+ struct nand_drv* ndrv = nand_init();
nand_lock(ndrv);
ret = nand_open(ndrv);
@@ -365,22 +375,22 @@ static void probe_flash(int log_fd)
mdelay(10);
/* Try various read ID commands (cf. Linux's SPI NAND identify routine) */
- sfc_exec(NANDCMD_READID(0, 0), 0, buffer, readid_len|SFC_READ);
+ sfc_exec(NANDCMD_READID_OPCODE, 0, buffer, readid_len|SFC_READ);
fdprintf(log_fd, "readID opcode = %02x %02x %02x %02x\n",
buffer[0], buffer[1], buffer[2], buffer[3]);
- sfc_exec(NANDCMD_READID(1, 0), 0, buffer, readid_len|SFC_READ);
+ sfc_exec(NANDCMD_READID_ADDR, 0, buffer, readid_len|SFC_READ);
fdprintf(log_fd, "readID address = %02x %02x %02x %02x\n",
buffer[0], buffer[1], buffer[2], buffer[3]);
- sfc_exec(NANDCMD_READID(0, 8), 0, buffer, readid_len|SFC_READ);
+ sfc_exec(NANDCMD_READID_DUMMY, 0, buffer, readid_len|SFC_READ);
fdprintf(log_fd, "readID dummy = %02x %02x %02x %02x\n",
buffer[0], buffer[1], buffer[2], buffer[3]);
/* Try reading Ingenic SFC boot block */
- sfc_exec(NANDCMD_PAGE_READ(3), 0, NULL, 0);
+ sfc_exec(NANDCMD_PAGE_READ, 0, NULL, 0);
mdelay(500);
- sfc_exec(NANDCMD_READ_CACHE_SLOW(2), 0, buffer, 16|SFC_READ);
+ sfc_exec(NANDCMD_READ_CACHE_SLOW, 0, buffer, 16|SFC_READ);
fdprintf(log_fd, "sfc params0 = %02x %02x %02x %02x\n",
buffer[ 0], buffer[ 1], buffer[ 2], buffer[ 3]);
@@ -411,3 +421,78 @@ void show_flash_info(void)
close(fd);
splashf(3*HZ, "Dumped flash info\nSee flash_info.txt");
}
+
+static int dump_flash_onfi_info(int fd)
+{
+ struct nand_drv* ndrv = nand_init();
+ nand_lock(ndrv);
+
+ int ret = nand_open(ndrv);
+ if(ret != NAND_SUCCESS) {
+ splashf(5*HZ, "NAND open failed\n");
+ nand_unlock(ndrv);
+ return ret;
+ }
+
+ nand_enable_otp(ndrv, true);
+
+ /* read ONFI parameter page */
+ ret = nand_page_read(ndrv, 0x01, ndrv->page_buf);
+ if(ret != NAND_SUCCESS) {
+ splashf(5*HZ, "Dump failed\nNAND read error");
+ goto out;
+ }
+
+ uint8_t* buf = ndrv->page_buf;
+
+ fdprintf(fd, "signature = %08lx\n", load_le32(buf));
+ fdprintf(fd, "revision = %04x\n", load_le16(buf+4));
+
+ char strbuf[32];
+ memcpy(strbuf, &buf[32], 12);
+ strbuf[12] = '\0';
+ fdprintf(fd, "manufacturer = \"%s\"\n", strbuf);
+
+ memcpy(strbuf, &buf[44], 20);
+ strbuf[20] = '\0';
+ fdprintf(fd, "device model = \"%s\"\n", strbuf);
+
+ fdprintf(fd, "JEDEC mf. id = %02x\n", buf[64]);
+
+ fdprintf(fd, "data bytes per page = %lu\n", load_le32(buf+80));
+ fdprintf(fd, "spare bytes per page = %u\n", load_le16(buf+84));
+ fdprintf(fd, "pages per block = %lu\n", load_le32(buf+92));
+ fdprintf(fd, "blocks per lun = %lu\n", load_le32(buf+96));
+ fdprintf(fd, "number of luns = %u\n", buf[100]);
+ fdprintf(fd, "bits per cell = %u\n", buf[102]);
+ fdprintf(fd, "max bad blocks = %u\n", load_le16(buf+103));
+ fdprintf(fd, "block endurance = %u\n", load_le16(buf+105));
+ fdprintf(fd, "programs per page = %u\n", buf[110]);
+ fdprintf(fd, "page program time = %u\n", load_le16(buf+133));
+ fdprintf(fd, "block erase time = %u\n", load_le16(buf+135));
+ fdprintf(fd, "page read time = %u\n", load_le16(buf+137));
+
+ out:
+ nand_enable_otp(ndrv, false);
+ nand_close(ndrv);
+ nand_unlock(ndrv);
+ return ret;
+}
+
+void show_flash_onfi_info(void)
+{
+ if(check_disk(true) != DISK_PRESENT)
+ return;
+
+ int fd = open("/flash_onfi_info.txt", O_WRONLY|O_CREAT|O_TRUNC);
+ if(fd < 0) {
+ splashf(5*HZ, "Cannot create log file");
+ return;
+ }
+
+ splashf(0, "Reading ONFI info...");
+ dump_flash_onfi_info(fd);
+
+ close(fd);
+ splashf(3*HZ, "Dumped flash ONFI info\nSee flash_onfi_info.txt");
+}
diff --git a/bootloader/x1000/x1000bootloader.h b/bootloader/x1000/x1000bootloader.h
index e74a6a3b68..ba2baa33b5 100644
--- a/bootloader/x1000/x1000bootloader.h
+++ b/bootloader/x1000/x1000bootloader.h
@@ -198,6 +198,7 @@ void dump_of_player(void);
void dump_of_recovery(void);
void dump_entire_flash(void);
void show_flash_info(void);
+void show_flash_onfi_info(void);
void recovery_menu(void) __attribute__((noreturn));
diff --git a/docs/CREDITS b/docs/CREDITS
index 6f7c23fc7e..86e009c8a8 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -710,6 +710,8 @@ Marc Aarts
Fabrice Bellard
Selami Dinçer
Matej Golian
+James Le Cuirot
+Michael Landherr
The libmad team
The wavpack team
diff --git a/firmware/buflib.c b/firmware/buflib.c
index c6ec011653..7263f1b95d 100644
--- a/firmware/buflib.c
+++ b/firmware/buflib.c
@@ -65,7 +65,7 @@
* H - handle table entry pointer
* C - pointer to struct buflib_callbacks
* c - variable sized string identifier
- * L2 - second length marker for string identifier
+ * L2 - length of the metadata
* crc - crc32 protecting buflib metadata integrity
* X - actual payload
* Y - unallocated space
@@ -97,17 +97,106 @@
#define BPANICF panicf
+/* Available paranoia checks */
+#define PARANOIA_CHECK_LENGTH (1 << 0)
+#define PARANOIA_CHECK_HANDLE (1 << 1)
+#define PARANOIA_CHECK_BLOCK_HANDLE (1 << 2)
+#define PARANOIA_CHECK_CRC (1 << 3)
+#define PARANOIA_CHECK_PINNING (1 << 4)
+/* Bitmask of enabled paranoia checks */
+#define BUFLIB_PARANOIA \
+ (PARANOIA_CHECK_LENGTH | PARANOIA_CHECK_HANDLE | \
+ PARANOIA_CHECK_BLOCK_HANDLE | PARANOIA_CHECK_CRC | \
+ PARANOIA_CHECK_PINNING)
+
+#if BUFLIB_PARANOIA & PARANOIA_CHECK_CRC
+# define BUFLIB_HAS_CRC
+#endif
+
+/* Forward indices, used to index a block start pointer as block[fidx_XXX] */
+enum {
+ fidx_LEN, /* length of the block, must come first */
+ fidx_HANDLE, /* pointer to entry in the handle table */
+ fidx_OPS, /* pointer to an ops struct */
+ fidx_NAME, /* name, optional and variable length, must come last */
+};
+
+/* Backward indices, used to index a block end pointer as block[-bidx_XXX] */
+enum {
+ bidx_USER, /* dummy to get below fields to be 1-based */
+ bidx_PIN, /* pin count */
+#ifdef BUFLIB_HAS_CRC
+ bidx_CRC, /* CRC, protects all metadata behind it */
+#endif
+ bidx_BSIZE, /* total size of the block header */
+};
+
+/* Number of fields in the block header, excluding the name, which is
+ * accounted for using the BSIZE field. Note that bidx_USER is not an
+ * actual field so it is not included in the count. */
+#ifdef BUFLIB_HAS_CRC
+# define BUFLIB_NUM_FIELDS 6
+#else
+# define BUFLIB_NUM_FIELDS 5
+#endif
+
struct buflib_callbacks buflib_ops_locked = {
.move_callback = NULL,
.shrink_callback = NULL,
.sync_callback = NULL,
};
-#define IS_MOVABLE(a) (!a[2].ops || a[2].ops->move_callback)
+#define IS_MOVABLE(a) (!a[fidx_OPS].ops || a[fidx_OPS].ops->move_callback)
+
static union buflib_data* find_first_free(struct buflib_context *ctx);
static union buflib_data* find_block_before(struct buflib_context *ctx,
union buflib_data* block,
bool is_free);
+
+/* Check the length of a block to ensure it does not go beyond the end
+ * of the allocated area. The block can be either allocated or free.
+ *
+ * This verifies that it is safe to iterate to the next block in a loop.
+ */
+static void check_block_length(struct buflib_context *ctx,
+ union buflib_data *block);
+
+/* Check a handle table entry to ensure the user pointer is within the
+ * bounds of the allocated area and there is enough room for a minimum
+ * size block header.
+ *
+ * This verifies that it is safe to convert the entry's pointer to a
+ * block end pointer and dereference fields at the block end.
+ */
+static void check_handle(struct buflib_context *ctx,
+ union buflib_data *h_entry);
+
+/* Check a block's handle pointer to ensure it is within the handle
+ * table, and that the user pointer is pointing within the block.
+ *
+ * This verifies that it is safe to dereference the entry, in addition
+ * to all checks performed by check_handle(). It also ensures that the
+ * pointer in the handle table points within the block, as determined
+ * by the length field at the start of the block.
+ */
+static void check_block_handle(struct buflib_context *ctx,
+ union buflib_data *block);
+
+/* Update the block's CRC checksum if CRCs are enabled. */
+static void update_block_crc(struct buflib_context *ctx,
+ union buflib_data *block,
+ union buflib_data *block_end);
+
+/* Check the block's CRC if CRCs are enabled. */
+static void check_block_crc(struct buflib_context *ctx,
+ union buflib_data *block,
+ union buflib_data *block_end);
+
+static inline char* get_block_name(union buflib_data *block)
+{
+ return (char*)&block[fidx_NAME];
+}
+
/* Initialize buffer manager */
void
buflib_init(struct buflib_context *ctx, void *buf, size_t size)
@@ -144,7 +233,7 @@ bool buflib_context_relocate(struct buflib_context *ctx, void *buf)
/* cannot continue if the buffer is not aligned, since we would need
* to reduce the size of the buffer for aligning */
- if ((uintptr_t)buf & 0x3)
+ if (!IS_ALIGNED((uintptr_t)buf, sizeof(union buflib_data)))
return false;
/* relocate the handle table entries */
@@ -196,9 +285,22 @@ union buflib_data* handle_alloc(struct buflib_context *ctx)
if (handle >= ctx->alloc_end)
ctx->last_handle--;
else
+ {
+ /* We know the table is full, so update first_free_handle */
+ ctx->first_free_handle = ctx->last_handle - 1;
return NULL;
+ }
}
+
+ /* We know there are no free handles between the old first_free_handle
+ * and the found handle, therefore we can update first_free_handle */
+ ctx->first_free_handle = handle - 1;
+
+ /* We need to set the table entry to a non-NULL value to ensure that
+ * compactions triggered by an allocation do not compact the handle
+ * table and delete this handle. */
handle->val = -1;
+
return handle;
}
@@ -218,37 +320,65 @@ void handle_free(struct buflib_context *ctx, union buflib_data *handle)
ctx->compact = false;
}
+static inline
+union buflib_data* handle_to_block_end(struct buflib_context *ctx, int handle)
+{
+ void *ptr = buflib_get_data(ctx, handle);
+
+ /* this is a valid case for shrinking if handle
+ * was freed by the shrink callback */
+ if (!ptr)
+ return NULL;
+
+ union buflib_data *data = ALIGN_DOWN(ptr, sizeof(*data));
+ return data;
+}
+
/* Get the start block of an allocation */
static inline
union buflib_data* handle_to_block(struct buflib_context* ctx, int handle)
{
- union buflib_data *data = ALIGN_DOWN(buflib_get_data(ctx, handle), sizeof (*data));
- /* this is a valid case, e.g. during buflib_alloc_ex() when the handle
- * has already been allocated but not the data */
- if (!data)
+ void *ptr = buflib_get_data(ctx, handle);
+
+ /* this is a valid case for shrinking if handle
+ * was freed by the shrink callback */
+ if (!ptr)
return NULL;
- volatile size_t len = data[-2].val;
- return data - (len + 4);
+
+ union buflib_data *data = ALIGN_DOWN(ptr, sizeof(*data));
+ return data - data[-bidx_BSIZE].val;
+}
+
+/* Get the block end pointer from a handle table entry */
+static union buflib_data*
+h_entry_to_block_end(struct buflib_context *ctx, union buflib_data *h_entry)
+{
+ check_handle(ctx, h_entry);
+
+ void *alloc = h_entry->alloc;
+ union buflib_data *data = ALIGN_DOWN(alloc, sizeof(*data));
+ return data;
}
/* Shrink the handle table, returning true if its size was reduced, false if
* not
*/
-static inline
-bool
-handle_table_shrink(struct buflib_context *ctx)
+static inline bool handle_table_shrink(struct buflib_context *ctx)
{
- bool rv;
union buflib_data *handle;
- for (handle = ctx->last_handle; !(handle->alloc); handle++);
+ union buflib_data *old_last = ctx->last_handle;
+
+ for (handle = ctx->last_handle; handle != ctx->handle_table; ++handle)
+ if (handle->alloc)
+ break;
+
if (handle > ctx->first_free_handle)
ctx->first_free_handle = handle - 1;
- rv = handle != ctx->last_handle;
+
ctx->last_handle = handle;
- return rv;
+ return handle != old_last;
}
-
/* If shift is non-zero, it represents the number of places to move
* blocks in memory. Calculate the new address for this block,
* update its entry in the handle table, and then move its contents.
@@ -260,32 +390,23 @@ static bool
move_block(struct buflib_context* ctx, union buflib_data* block, int shift)
{
char* new_start;
+ union buflib_data *new_block;
- if (block < ctx->buf_start || block > ctx->alloc_end)
- buflib_panic(ctx, "buflib data corrupted %p", block);
-
- union buflib_data *new_block, *tmp = block[1].handle, *crc_slot;
- struct buflib_callbacks *ops = block[2].ops;
- crc_slot = (union buflib_data*)tmp->alloc - 1;
- if (crc_slot < ctx->buf_start || crc_slot > ctx->alloc_end)
- buflib_panic(ctx, "buflib metadata corrupted %p", crc_slot);
-
- const int metadata_size = (crc_slot - block)*sizeof(union buflib_data);
- uint32_t crc = crc_32((void *)block, metadata_size, 0xffffffff);
-
- /* check for metadata validity */
- if (crc != crc_slot->crc)
- buflib_panic(ctx, "buflib metadata corrupted, crc: 0x%08x, expected: 0x%08x",
- (unsigned int)crc, (unsigned int)crc_slot->crc);
+ check_block_handle(ctx, block);
+ union buflib_data *h_entry = block[fidx_HANDLE].handle;
+ union buflib_data *block_end = h_entry_to_block_end(ctx, h_entry);
+ check_block_crc(ctx, block, block_end);
- if (!IS_MOVABLE(block))
+ if (!IS_MOVABLE(block) || block_end[-bidx_PIN].pincount > 0)
return false;
- int handle = ctx->handle_table - tmp;
- BDEBUGF("%s(): moving \"%s\"(id=%d) by %d(%d)\n", __func__, block[3].name,
- handle, shift, shift*(int)sizeof(union buflib_data));
+ int handle = ctx->handle_table - h_entry;
+ BDEBUGF("%s(): moving \"%s\"(id=%d) by %d(%d)\n", __func__,
+ get_block_name(block), handle, shift, shift*(int)sizeof(union buflib_data));
new_block = block + shift;
- new_start = tmp->alloc + shift*sizeof(union buflib_data);
+ new_start = h_entry->alloc + shift*sizeof(union buflib_data);
+
+ struct buflib_callbacks *ops = block[fidx_OPS].ops;
/* If move must be synchronized with use, user should have specified a
callback that handles this */
@@ -293,10 +414,10 @@ move_block(struct buflib_context* ctx, union buflib_data* block, int shift)
ops->sync_callback(handle, true);
bool retval = false;
- if (!ops || ops->move_callback(handle, tmp->alloc, new_start)
+ if (!ops || ops->move_callback(handle, h_entry->alloc, new_start)
!= BUFLIB_CB_CANNOT_MOVE)
{
- tmp->alloc = new_start; /* update handle table */
+ h_entry->alloc = new_start; /* update handle table */
memmove(new_block, block, block->val * sizeof(union buflib_data));
retval = true;
}
@@ -333,6 +454,8 @@ buflib_compact(struct buflib_context *ctx)
* For simplicity only 1 hole at a time is considered */
for(block = find_first_free(ctx); block < ctx->alloc_end; block += len)
{
+ check_block_length(ctx, block);
+
bool movable = true; /* cache result to avoid 2nd call to move_block */
len = block->val;
/* This block is free, add its length to the shift value */
@@ -409,41 +532,52 @@ buflib_compact_and_shrink(struct buflib_context *ctx, unsigned shrink_hints)
this < ctx->alloc_end;
before = this, this += abs(this->val))
{
- if (this->val > 0 && this[2].ops
- && this[2].ops->shrink_callback)
+ check_block_length(ctx, this);
+ if (this->val < 0)
+ continue;
+
+ struct buflib_callbacks *ops = this[fidx_OPS].ops;
+ if (!ops || !ops->shrink_callback)
+ continue;
+
+ check_block_handle(ctx, this);
+ union buflib_data* h_entry = this[fidx_HANDLE].handle;
+ int handle = ctx->handle_table - h_entry;
+
+ unsigned pos_hints = shrink_hints & BUFLIB_SHRINK_POS_MASK;
+ /* adjust what we ask for if there's free space in the front
+ * this isn't too unlikely assuming this block is
+ * shrinkable but not movable */
+ if (pos_hints == BUFLIB_SHRINK_POS_FRONT &&
+ before != this && before->val < 0)
{
- int ret;
- int handle = ctx->handle_table - this[1].handle;
- char* data = this[1].handle->alloc;
- bool last = (this+this->val) == ctx->alloc_end;
- unsigned pos_hints = shrink_hints & BUFLIB_SHRINK_POS_MASK;
- /* adjust what we ask for if there's free space in the front
- * this isn't too unlikely assuming this block is
- * shrinkable but not movable */
- if (pos_hints == BUFLIB_SHRINK_POS_FRONT
- && before != this && before->val < 0)
- {
- size_t free_space = (-before->val) * sizeof(union buflib_data);
- size_t wanted = shrink_hints & BUFLIB_SHRINK_SIZE_MASK;
- if (wanted < free_space) /* no shrink needed? */
- continue;
- wanted -= free_space;
- shrink_hints = pos_hints | wanted;
- }
- ret = this[2].ops->shrink_callback(handle, shrink_hints,
- data, (char*)(this+this->val)-data);
- result |= (ret == BUFLIB_CB_OK);
- /* 'this' might have changed in the callback (if it shrinked
- * from the top or even freed the handle), get it again */
- this = handle_to_block(ctx, handle);
- /* The handle was possibly be freed in the callback,
- * re-run the loop with the handle before */
- if (!this)
- this = before;
- /* could also change with shrinking from back */
- else if (last)
- ctx->alloc_end = this + this->val;
+ size_t free_space = (-before->val) * sizeof(union buflib_data);
+ size_t wanted = shrink_hints & BUFLIB_SHRINK_SIZE_MASK;
+ if (wanted < free_space) /* no shrink needed? */
+ continue;
+ wanted -= free_space;
+ shrink_hints = pos_hints | wanted;
}
+
+ char* data = h_entry->alloc;
+ char* data_end = (char*)(this + this->val);
+ bool last = (data_end == (char*)ctx->alloc_end);
+
+ int ret = ops->shrink_callback(handle, shrink_hints,
+ data, data_end - data);
+ result |= (ret == BUFLIB_CB_OK);
+
+ /* 'this' might have changed in the callback (if it shrinked
+ * from the top or even freed the handle), get it again */
+ this = handle_to_block(ctx, handle);
+
+ /* The handle was possibly be freed in the callback,
+ * re-run the loop with the handle before */
+ if (!this)
+ this = before;
+ /* could also change with shrinking from back */
+ else if (last)
+ ctx->alloc_end = this + this->val;
}
/* shrinking was successful at least once, try compaction again */
if (result)
@@ -532,9 +666,7 @@ buflib_alloc_ex(struct buflib_context *ctx, size_t size, const char *name,
size += name_len;
size = (size + sizeof(union buflib_data) - 1) /
sizeof(union buflib_data)
- /* add 5 objects for alloc len, pointer to handle table entry and
- * name length, the ops pointer and crc */
- + 5;
+ + BUFLIB_NUM_FIELDS;
handle_alloc:
handle = handle_alloc(ctx);
if (!handle)
@@ -544,7 +676,7 @@ handle_alloc:
*/
union buflib_data* last_block = find_block_before(ctx,
ctx->alloc_end, false);
- struct buflib_callbacks* ops = last_block[2].ops;
+ struct buflib_callbacks* ops = last_block[fidx_OPS].ops;
unsigned hints = 0;
if (!ops || !ops->shrink_callback)
{ /* the last one isn't shrinkable
@@ -568,7 +700,7 @@ buffer_alloc:
/* need to re-evaluate last before the loop because the last allocation
* possibly made room in its front to fit this, so last would be wrong */
last = false;
- for (block = find_first_free(ctx);;block += block_len)
+ for (block = find_first_free(ctx);; block += block_len)
{
/* If the last used block extends all the way to the handle table, the
* block "after" it doesn't have a header. Because of this, it's easier
@@ -584,6 +716,8 @@ buffer_alloc:
block = NULL;
break;
}
+
+ check_block_length(ctx, block);
block_len = block->val;
/* blocks with positive length are already allocated. */
if(block_len > 0)
@@ -604,7 +738,6 @@ buffer_alloc:
{
goto buffer_alloc;
} else {
- handle->val=1;
handle_free(ctx, handle);
return -2;
}
@@ -613,23 +746,22 @@ buffer_alloc:
/* Set up the allocated block, by marking the size allocated, and storing
* a pointer to the handle.
*/
- union buflib_data *name_len_slot, *crc_slot;
- block->val = size;
- block[1].handle = handle;
- block[2].ops = ops;
+ block[fidx_LEN].val = size;
+ block[fidx_HANDLE].handle = handle;
+ block[fidx_OPS].ops = ops;
if (name_len > 0)
- strcpy(block[3].name, name);
- name_len_slot = (union buflib_data*)B_ALIGN_UP(block[3].name + name_len);
- name_len_slot->val = 1 + name_len/sizeof(union buflib_data);
- crc_slot = (union buflib_data*)(name_len_slot + 1);
- crc_slot->crc = crc_32((void *)block,
- (crc_slot - block)*sizeof(union buflib_data),
- 0xffffffff);
- handle->alloc = (char*)(crc_slot + 1);
-
- BDEBUGF("buflib_alloc_ex: size=%d handle=%p clb=%p crc=0x%0x name=\"%s\"\n",
- (unsigned int)size, (void *)handle, (void *)ops,
- (unsigned int)crc_slot->crc, name ? block[3].name:"");
+ strcpy(get_block_name(block), name);
+
+ size_t bsize = BUFLIB_NUM_FIELDS + name_len/sizeof(union buflib_data);
+ union buflib_data *block_end = block + bsize;
+ block_end[-bidx_PIN].pincount = 0;
+ block_end[-bidx_BSIZE].val = bsize;
+ update_block_crc(ctx, block, block_end);
+
+ handle->alloc = (char*)&block_end[-bidx_USER];
+
+ BDEBUGF("buflib_alloc_ex: size=%d handle=%p clb=%p name=\"%s\"\n",
+ (unsigned int)size, (void *)handle, (void *)ops, name ? name : "");
block += size;
/* alloc_end must be kept current if we're taking the last block. */
@@ -645,13 +777,14 @@ buffer_alloc:
static union buflib_data*
find_first_free(struct buflib_context *ctx)
{
- union buflib_data* ret = ctx->buf_start;
- while(ret < ctx->alloc_end)
+ union buflib_data *ret;
+ for(ret = ctx->buf_start; ret < ctx->alloc_end; ret += ret->val)
{
+ check_block_length(ctx, ret);
if (ret->val < 0)
break;
- ret += ret->val;
}
+
/* ret is now either a free block or the same as alloc_end, both is fine */
return ret;
}
@@ -664,23 +797,23 @@ find_block_before(struct buflib_context *ctx, union buflib_data* block,
union buflib_data *ret = ctx->buf_start,
*next_block = ret;
+ /* no previous block */
+ if (next_block == block)
+ return NULL;
+
/* find the block that's before the current one */
- while (next_block < block)
+ while (next_block != block)
{
+ check_block_length(ctx, ret);
ret = next_block;
next_block += abs(ret->val);
}
- /* If next_block == block, the above loop didn't go anywhere. If it did,
- * and the block before this one is empty, that is the wanted one
- */
- if (next_block == block && ret < block)
- {
- if (is_free && ret->val >= 0) /* NULL if found block isn't free */
- return NULL;
- return ret;
- }
- return NULL;
+ /* don't return it if the found block isn't free */
+ if (is_free && ret->val >= 0)
+ return NULL;
+
+ return ret;
}
/* Free the buffer associated with handle_num. */
@@ -700,13 +833,13 @@ buflib_free(struct buflib_context *ctx, int handle_num)
}
else
{
- /* Otherwise, set block to the newly-freed block, and mark it free, before
- * continuing on, since the code below expects block to point to a free
- * block which may have free space after it.
- */
+ /* Otherwise, set block to the newly-freed block, and mark it free,
+ * before continuing on, since the code below expects block to point
+ * to a free block which may have free space after it. */
block = freed_block;
block->val = -block->val;
}
+
next_block = block - block->val;
/* Check if we are merging with the free space at alloc_end. */
if (next_block == ctx->alloc_end)
@@ -729,8 +862,8 @@ static size_t
free_space_at_end(struct buflib_context* ctx)
{
/* subtract 5 elements for
- * val, handle, name_len, ops and the handle table entry*/
- ptrdiff_t diff = (ctx->last_handle - ctx->alloc_end - 5);
+ * val, handle, meta_len, ops and the handle table entry*/
+ ptrdiff_t diff = (ctx->last_handle - ctx->alloc_end - BUFLIB_NUM_FIELDS);
diff -= 16; /* space for future handles */
diff *= sizeof(union buflib_data); /* make it bytes */
diff -= 16; /* reserve 16 for the name */
@@ -745,24 +878,31 @@ free_space_at_end(struct buflib_context* ctx)
size_t
buflib_allocatable(struct buflib_context* ctx)
{
- union buflib_data *this;
size_t free_space = 0, max_free_space = 0;
+ intptr_t block_len;
/* make sure buffer is as contiguous as possible */
if (!ctx->compact)
buflib_compact(ctx);
/* now look if there's free in holes */
- for(this = find_first_free(ctx); this < ctx->alloc_end; this += abs(this->val))
+ for(union buflib_data *block = find_first_free(ctx);
+ block < ctx->alloc_end;
+ block += block_len)
{
- if (this->val < 0)
+ check_block_length(ctx, block);
+ block_len = block->val;
+
+ if (block_len < 0)
{
- free_space += -this->val;
+ block_len = -block_len;
+ free_space += block_len;
continue;
}
+
/* an unmovable section resets the count as free space
* can't be contigous */
- if (!IS_MOVABLE(this))
+ if (!IS_MOVABLE(block))
{
if (max_free_space < free_space)
max_free_space = free_space;
@@ -785,17 +925,16 @@ buflib_allocatable(struct buflib_context* ctx)
size_t
buflib_available(struct buflib_context* ctx)
{
- union buflib_data *this;
size_t free_space = 0;
- /* now look if there's free in holes */
- for(this = find_first_free(ctx); this < ctx->alloc_end; this += abs(this->val))
+ /* add up all holes */
+ for(union buflib_data *block = find_first_free(ctx);
+ block < ctx->alloc_end;
+ block += abs(block->val))
{
- if (this->val < 0)
- {
- free_space += -this->val;
- continue;
- }
+ check_block_length(ctx, block);
+ if (block->val < 0)
+ free_space += -block->val;
}
free_space *= sizeof(union buflib_data); /* make it bytes */
@@ -845,8 +984,6 @@ buflib_alloc_maximum(struct buflib_context* ctx, const char* name, size_t *size,
bool
buflib_shrink(struct buflib_context* ctx, int handle, void* new_start, size_t new_size)
{
- union buflib_data *crc_slot;
- int size_for_crc32;
char* oldstart = buflib_get_data(ctx, handle);
char* newstart = new_start;
char* newend = newstart + new_size;
@@ -870,9 +1007,10 @@ buflib_shrink(struct buflib_context* ctx, int handle, void* new_start, size_t ne
metadata_size.val = aligned_oldstart - block;
/* update val and the handle table entry */
new_block = aligned_newstart - metadata_size.val;
- block[0].val = new_next_block - new_block;
+ block[fidx_LEN].val = new_next_block - new_block;
- block[1].handle->alloc = newstart;
+ check_block_handle(ctx, block);
+ block[fidx_HANDLE].handle->alloc = newstart;
if (block != new_block)
{
/* move metadata over, i.e. pointer to handle table entry and name
@@ -893,9 +1031,9 @@ buflib_shrink(struct buflib_context* ctx, int handle, void* new_start, size_t ne
}
/* update crc of the metadata */
- crc_slot = (union buflib_data*)new_block[1].handle->alloc - 1;
- size_for_crc32 = (crc_slot - new_block)*sizeof(union buflib_data);
- crc_slot->crc = crc_32((void *)new_block, size_for_crc32, 0xffffffff);
+ union buflib_data *new_h_entry = new_block[fidx_HANDLE].handle;
+ union buflib_data *new_block_end = h_entry_to_block_end(ctx, new_h_entry);
+ update_block_crc(ctx, new_block, new_block_end);
/* Now deal with size changes that create free blocks after the allocation */
if (old_next_block != new_next_block)
@@ -916,13 +1054,48 @@ buflib_shrink(struct buflib_context* ctx, int handle, void* new_start, size_t ne
return true;
}
+void buflib_pin(struct buflib_context *ctx, int handle)
+{
+ if ((BUFLIB_PARANOIA & PARANOIA_CHECK_PINNING) && handle <= 0)
+ buflib_panic(ctx, "invalid handle pin: %d", handle);
+
+ union buflib_data *data = handle_to_block_end(ctx, handle);
+ data[-bidx_PIN].pincount++;
+}
+
+void buflib_unpin(struct buflib_context *ctx, int handle)
+{
+ if ((BUFLIB_PARANOIA & PARANOIA_CHECK_PINNING) && handle <= 0)
+ buflib_panic(ctx, "invalid handle unpin: %d", handle);
+
+ union buflib_data *data = handle_to_block_end(ctx, handle);
+ if (BUFLIB_PARANOIA & PARANOIA_CHECK_PINNING)
+ {
+ if (data[-bidx_PIN].pincount == 0)
+ buflib_panic(ctx, "handle pin underflow: %d", handle);
+ }
+
+ data[-bidx_PIN].pincount--;
+}
+
+unsigned buflib_pin_count(struct buflib_context *ctx, int handle)
+{
+ if ((BUFLIB_PARANOIA & PARANOIA_CHECK_PINNING) && handle <= 0)
+ buflib_panic(ctx, "invalid handle: %d", handle);
+
+ union buflib_data *data = handle_to_block_end(ctx, handle);
+ return data[-bidx_PIN].pincount;
+}
+
const char* buflib_get_name(struct buflib_context *ctx, int handle)
{
- union buflib_data *data = ALIGN_DOWN(buflib_get_data(ctx, handle), sizeof (*data));
- size_t len = data[-2].val;
- if (len <= 1)
+ union buflib_data *data = handle_to_block_end(ctx, handle);
+ size_t len = data[-bidx_BSIZE].val;
+ if (len <= BUFLIB_NUM_FIELDS)
return NULL;
- return data[-len-1].name;
+
+ data -= len;
+ return get_block_name(data);
}
#ifdef DEBUG
@@ -937,102 +1110,182 @@ void *buflib_get_data(struct buflib_context *ctx, int handle)
void buflib_check_valid(struct buflib_context *ctx)
{
- union buflib_data *crc_slot;
- int metadata_size;
- uint32_t crc;
-
- for(union buflib_data* this = ctx->buf_start;
- this < ctx->alloc_end;
- this += abs(this->val))
+ for(union buflib_data *block = ctx->buf_start;
+ block < ctx->alloc_end;
+ block += abs(block->val))
{
- if (this->val < 0)
+ check_block_length(ctx, block);
+ if (block->val < 0)
continue;
- crc_slot = (union buflib_data*)
- ((union buflib_data*)this[1].handle)->alloc - 1;
- metadata_size = (crc_slot - this)*sizeof(union buflib_data);
- crc = crc_32((void *)this, metadata_size, 0xffffffff);
-
- if (crc != crc_slot->crc)
- buflib_panic(ctx, "crc mismatch: 0x%08x, expected: 0x%08x",
- (unsigned int)crc, (unsigned int)crc_slot->crc);
+ check_block_handle(ctx, block);
+ union buflib_data *h_entry = block[fidx_HANDLE].handle;
+ union buflib_data *block_end = h_entry_to_block_end(ctx, h_entry);
+ check_block_crc(ctx, block, block_end);
}
}
#endif
-#ifdef BUFLIB_DEBUG_BLOCKS
-void buflib_print_allocs(struct buflib_context *ctx,
- void (*print)(int, const char*))
+#ifdef BUFLIB_DEBUG_BLOCK_SINGLE
+int buflib_get_num_blocks(struct buflib_context *ctx)
{
- union buflib_data *this, *end = ctx->handle_table;
- char buf[128];
- for(this = end - 1; this >= ctx->last_handle; this--)
+ int i = 0;
+ for(union buflib_data *block = ctx->buf_start;
+ block < ctx->alloc_end;
+ block += abs(block->val))
{
- if (!this->alloc) continue;
-
- int handle_num;
- const char *name;
- union buflib_data *block_start, *alloc_start;
- intptr_t alloc_len;
-
- handle_num = end - this;
- alloc_start = buflib_get_data(ctx, handle_num);
- name = buflib_get_name(ctx, handle_num);
- block_start = (union buflib_data*)name - 3;
- alloc_len = block_start->val * sizeof(union buflib_data);
-
- snprintf(buf, sizeof(buf),
- "%s(%d):\t%p\n"
- " \t%p\n"
- " \t%ld\n",
- name?:"(null)", handle_num, block_start, alloc_start, alloc_len);
- /* handle_num is 1-based */
- print(handle_num - 1, buf);
+ check_block_length(ctx, block);
+ ++i;
}
+ return i;
}
-void buflib_print_blocks(struct buflib_context *ctx,
- void (*print)(int, const char*))
+void buflib_print_block_at(struct buflib_context *ctx, int block_num,
+ char* buf, size_t bufsize)
{
- char buf[128];
- int i = 0;
- for(union buflib_data* this = ctx->buf_start;
- this < ctx->alloc_end;
- this += abs(this->val))
+ for(union buflib_data *block = ctx->buf_start;
+ block < ctx->alloc_end;
+ block += abs(block->val))
{
- snprintf(buf, sizeof(buf), "%8p: val: %4ld (%s)",
- this, this->val,
- this->val > 0? this[3].name:"<unallocated>");
- print(i++, buf);
+ check_block_length(ctx, block);
+
+ if (block_num-- == 0)
+ {
+ snprintf(buf, bufsize, "%8p: val: %4ld (%s)",
+ block, (long)block->val,
+ block->val > 0 ? get_block_name(block) : "<unallocated>");
+ }
}
}
#endif
-#ifdef BUFLIB_DEBUG_BLOCK_SINGLE
-int buflib_get_num_blocks(struct buflib_context *ctx)
+static void check_block_length(struct buflib_context *ctx,
+ union buflib_data *block)
{
- int i = 0;
- for(union buflib_data* this = ctx->buf_start;
- this < ctx->alloc_end;
- this += abs(this->val))
+ if (BUFLIB_PARANOIA & PARANOIA_CHECK_LENGTH)
+ {
+ intptr_t length = block[fidx_LEN].val;
+
+ /* Check the block length does not pass beyond the end */
+ if (length == 0 || block > ctx->alloc_end - abs(length))
+ {
+ buflib_panic(ctx, "block len wacky [%p]=%ld",
+ (void*)&block[fidx_LEN], (long)length);
+ }
+ }
+}
+
+static void check_handle(struct buflib_context *ctx,
+ union buflib_data *h_entry)
+{
+ if (BUFLIB_PARANOIA & PARANOIA_CHECK_HANDLE)
{
- i++;
+ /* For the pointer to be valid there needs to be room for a minimum
+ * size block header, so we add BUFLIB_NUM_FIELDS to ctx->buf_start. */
+ void *alloc = h_entry->alloc;
+ void *alloc_begin = ctx->buf_start + BUFLIB_NUM_FIELDS;
+ void *alloc_end = ctx->alloc_end;
+ /* buflib allows zero length allocations, so alloc_end is inclusive */
+ if (alloc < alloc_begin || alloc > alloc_end)
+ {
+ buflib_panic(ctx, "alloc outside buf [%p]=%p, %p-%p",
+ h_entry, alloc, alloc_begin, alloc_end);
+ }
}
- return i;
}
-void buflib_print_block_at(struct buflib_context *ctx, int block_num,
- char* buf, size_t bufsize)
+static void check_block_handle(struct buflib_context *ctx,
+ union buflib_data *block)
+{
+ if (BUFLIB_PARANOIA & PARANOIA_CHECK_BLOCK_HANDLE)
+ {
+ intptr_t length = block[fidx_LEN].val;
+ union buflib_data *h_entry = block[fidx_HANDLE].handle;
+
+ /* Check the handle pointer is properly aligned */
+ /* TODO: Can we ensure the compiler doesn't optimize this out?
+ * I dunno, maybe the compiler can assume the pointer is always
+ * properly aligned due to some C standard voodoo?? */
+ if (!IS_ALIGNED((uintptr_t)h_entry, alignof(*h_entry)))
+ {
+ buflib_panic(ctx, "handle unaligned [%p]=%p",
+ &block[fidx_HANDLE], h_entry);
+ }
+
+ /* Check the pointer is actually inside the handle table */
+ if (h_entry < ctx->last_handle || h_entry >= ctx->handle_table)
+ {
+ buflib_panic(ctx, "handle out of bounds [%p]=%p",
+ &block[fidx_HANDLE], h_entry);
+ }
+
+ /* Now check the allocation is within the block.
+ * This is stricter than check_handle(). */
+ void *alloc = h_entry->alloc;
+ void *alloc_begin = block;
+ void *alloc_end = block + length;
+ /* buflib allows zero length allocations, so alloc_end is inclusive */
+ if (alloc < alloc_begin || alloc > alloc_end)
+ {
+ buflib_panic(ctx, "alloc outside block [%p]=%p, %p-%p",
+ h_entry, alloc, alloc_begin, alloc_end);
+ }
+ }
+}
+
+#ifdef BUFLIB_HAS_CRC
+static uint32_t calc_block_crc(union buflib_data *block,
+ union buflib_data *block_end)
+{
+ union buflib_data *crc_slot = &block_end[-bidx_CRC];
+ const size_t size = (crc_slot - block) * sizeof(*block);
+ return crc_32(block, size, 0xffffffff);
+}
+
+static void update_block_crc(struct buflib_context *ctx,
+ union buflib_data *block,
+ union buflib_data *block_end)
+{
+ (void)ctx;
+
+ if (BUFLIB_PARANOIA & PARANOIA_CHECK_CRC)
+ {
+ block_end[-bidx_CRC].crc = calc_block_crc(block, block_end);
+ }
+}
+
+static void check_block_crc(struct buflib_context *ctx,
+ union buflib_data *block,
+ union buflib_data *block_end)
{
- union buflib_data* this = ctx->buf_start;
- while(block_num > 0 && this < ctx->alloc_end)
+ if (BUFLIB_PARANOIA & PARANOIA_CHECK_CRC)
{
- this += abs(this->val);
- block_num -= 1;
+ uint32_t crc = calc_block_crc(block, block_end);
+ if (block_end[-bidx_CRC].crc != crc)
+ {
+ buflib_panic(ctx, "buflib crc mismatch [%p]=%08lx, got %08lx",
+ &block_end[-bidx_CRC],
+ (unsigned long)block_end[-bidx_CRC].crc,
+ (unsigned long)crc);
+ }
}
- snprintf(buf, bufsize, "%8p: val: %4ld (%s)",
- this, (long)this->val,
- this->val > 0? this[3].name:"<unallocated>");
+}
+#else
+static void update_block_crc(struct buflib_context *ctx,
+ union buflib_data *block,
+ union buflib_data *block_end)
+{
+ (void)ctx;
+ (void)block;
+ (void)block_end;
}
+static void check_block_crc(struct buflib_context *ctx,
+ union buflib_data *block,
+ union buflib_data *block_end)
+{
+ (void)ctx;
+ (void)block;
+ (void)block_end;
+}
#endif
diff --git a/firmware/core_alloc.c b/firmware/core_alloc.c
index bf2f8e8298..0374c801c1 100644
--- a/firmware/core_alloc.c
+++ b/firmware/core_alloc.c
@@ -104,6 +104,21 @@ bool core_shrink(int handle, void* new_start, size_t new_size)
return buflib_shrink(&core_ctx, handle, new_start, new_size);
}
+void core_pin(int handle)
+{
+ buflib_pin(&core_ctx, handle);
+}
+
+void core_unpin(int handle)
+{
+ buflib_unpin(&core_ctx, handle);
+}
+
+unsigned core_pin_count(int handle)
+{
+ return buflib_pin_count(&core_ctx, handle);
+}
+
const char* core_get_name(int handle)
{
const char *name = buflib_get_name(&core_ctx, handle);
diff --git a/firmware/drivers/lcd-16bit-common.c b/firmware/drivers/lcd-16bit-common.c
index 1b84847929..523354d5d2 100644
--- a/firmware/drivers/lcd-16bit-common.c
+++ b/firmware/drivers/lcd-16bit-common.c
@@ -40,30 +40,6 @@ void lcd_clear_viewport(void)
width = lcd_current_viewport->width;
height = lcd_current_viewport->height;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
len = STRIDE_MAIN(width, height);
step = STRIDE_MAIN(ROW_INC, COL_INC);
@@ -182,30 +158,6 @@ void lcd_fillrect(int x, int y, int width, int height)
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
/* drawmode and optimisation */
if (lcd_current_viewport->drawmode & DRMODE_INVERSEVID)
{
@@ -310,32 +262,6 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
/* move starting point */
src += stride * (src_y >> 3) + src_x;
src_y &= 7;
@@ -568,35 +494,6 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- {
- BLEND_FINISH;
- return;
- }
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
/* the following drawmode combinations are possible:
* 1) COMPLEMENT: just negates the framebuffer contents
* 2) BG and BG+backdrop: draws _only_ background pixels with either
diff --git a/firmware/drivers/lcd-16bit-vert.c b/firmware/drivers/lcd-16bit-vert.c
index 4422fdea50..166af02791 100644
--- a/firmware/drivers/lcd-16bit-vert.c
+++ b/firmware/drivers/lcd-16bit-vert.c
@@ -93,20 +93,6 @@ void lcd_hline(int x1, int x2, int y)
x2 += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
- || (x2 < 0))
- return;
-
- /* clipping */
- if (x1 < 0)
- x1 = 0;
- if (x2 >= LCD_WIDTH)
- x2 = LCD_WIDTH-1;
-#endif
-
dst = FBADDR(x1 , y );
stride_dst = lcd_current_viewport->buffer->stride;
dst_end = dst + (x2 - x1) * stride_dst;
@@ -152,20 +138,6 @@ void lcd_vline(int x, int y1, int y2)
y1 += lcd_current_viewport->y;
y2 += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
- || (y2 < 0))
- return;
-
- /* clipping */
- if (y1 < 0)
- y1 = 0;
- if (y2 >= LCD_HEIGHT)
- y2 = LCD_HEIGHT-1;
-#endif
-
height = y2 - y1 + 1;
/* drawmode and optimisation */
@@ -250,32 +222,6 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
src += stride * src_x + src_y; /* move starting point */
dst = FBADDR(x, y);
stride_dst = lcd_current_viewport->buffer->stride;
@@ -326,32 +272,6 @@ void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
src += stride * src_x + src_y; /* move starting point */
dst = FBADDR(x, y);
stride_dst = lcd_current_viewport->buffer->stride;
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index d6bf5a500d..6dff6f3b50 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -92,20 +92,6 @@ void lcd_hline(int x1, int x2, int y)
x2 += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
- || (x2 < 0))
- return;
-
- /* clipping */
- if (x1 < 0)
- x1 = 0;
- if (x2 >= LCD_WIDTH)
- x2 = LCD_WIDTH-1;
-#endif
-
width = x2 - x1 + 1;
/* drawmode and optimisation */
@@ -188,20 +174,6 @@ void lcd_vline(int x, int y1, int y2)
y1 += lcd_current_viewport->y;
y2 += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
- || (y2 < 0))
- return;
-
- /* clipping */
- if (y1 < 0)
- y1 = 0;
- if (y2 >= LCD_HEIGHT)
- y2 = LCD_HEIGHT-1;
-#endif
-
dst = FBADDR(x , y1);
stride_dst = lcd_current_viewport->buffer->stride;
dst_end = dst + (y2 - y1) * stride_dst;
@@ -250,32 +222,6 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
src += stride * src_y + src_x; /* move starting point */
dst = FBADDR(x, y);
stride_dst = lcd_current_viewport->buffer->stride;
@@ -326,32 +272,6 @@ void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
src += stride * src_y + src_x; /* move starting point */
dst = FBADDR(x, y);
diff --git a/firmware/drivers/lcd-1bit-vert.c b/firmware/drivers/lcd-1bit-vert.c
index dcf5e49504..ff95eacdbc 100644
--- a/firmware/drivers/lcd-1bit-vert.c
+++ b/firmware/drivers/lcd-1bit-vert.c
@@ -274,10 +274,6 @@ void LCDFN(drawpixel)(int x, int y)
{
if ( ((unsigned)x < (unsigned)CURRENT_VP->width)
&& ((unsigned)y < (unsigned)CURRENT_VP->height)
-#if defined(HAVE_VIEWPORT_CLIP)
- && ((unsigned)x < (unsigned)LCDM(WIDTH))
- && ((unsigned)y < (unsigned)LCDM(HEIGHT))
-#endif
)
LCDFN(pixelfuncs)[CURRENT_VP->drawmode](CURRENT_VP->x + x, CURRENT_VP->y + y);
}
@@ -349,10 +345,6 @@ void LCDFN(drawline)(int x1, int y1, int x2, int y2)
{
if ( ((unsigned)x < (unsigned)CURRENT_VP->width)
&& ((unsigned)y < (unsigned)CURRENT_VP->height)
-#if defined(HAVE_VIEWPORT_CLIP)
- && ((unsigned)x < (unsigned)LCDM(WIDTH))
- && ((unsigned)y < (unsigned)LCDM(HEIGHT))
-#endif
)
pfunc(CURRENT_VP->x + x, CURRENT_VP->y + y);
@@ -403,20 +395,6 @@ void LCDFN(hline)(int x1, int x2, int y)
x2 += CURRENT_VP->x;
y += CURRENT_VP->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (((unsigned)y >= (unsigned) LCDM(HEIGHT)) || (x1 >= LCDM(WIDTH))
- || (x2 < 0))
- return;
-
- /* clipping */
- if (x1 < 0)
- x1 = 0;
- if (x2 >= LCDM(WIDTH))
- x2 = LCDM(WIDTH)-1;
-#endif
-
width = x2 - x1 + 1;
bfunc = LCDFN(blockfuncs)[CURRENT_VP->drawmode];
@@ -462,20 +440,6 @@ void LCDFN(vline)(int x, int y1, int y2)
y2 += CURRENT_VP->y;
x += CURRENT_VP->x;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (( (unsigned) x >= (unsigned)LCDM(WIDTH)) || (y1 >= LCDM(HEIGHT))
- || (y2 < 0))
- return;
-
- /* clipping */
- if (y1 < 0)
- y1 = 0;
- if (y2 >= LCDM(HEIGHT))
- y2 = LCDM(HEIGHT)-1;
-#endif
-
bfunc = LCDFN(blockfuncs)[CURRENT_VP->drawmode];
dst = LCDFB(x,y1>>3);
ny = y2 - (y1 & ~7);
@@ -544,30 +508,6 @@ void LCDFN(fillrect)(int x, int y, int width, int height)
x += CURRENT_VP->x;
y += CURRENT_VP->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > LCDM(WIDTH))
- width = LCDM(WIDTH) - x;
- if (y + height > LCDM(HEIGHT))
- height = LCDM(HEIGHT) - y;
-#endif
-
if (CURRENT_VP->drawmode & DRMODE_INVERSEVID)
{
if (CURRENT_VP->drawmode & DRMODE_BG)
@@ -670,32 +610,6 @@ void ICODE_ATTR LCDFN(bitmap_part)(const unsigned char *src, int src_x,
x += CURRENT_VP->x;
y += CURRENT_VP->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCDM(WIDTH))
- width = LCDM(WIDTH) - x;
- if (y + height > LCDM(HEIGHT))
- height = LCDM(HEIGHT) - y;
-#endif
-
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
y -= src_y;
diff --git a/firmware/drivers/lcd-24bit.c b/firmware/drivers/lcd-24bit.c
index c3aa27f7ce..279ed5924a 100644
--- a/firmware/drivers/lcd-24bit.c
+++ b/firmware/drivers/lcd-24bit.c
@@ -70,30 +70,6 @@ void lcd_clear_viewport(void)
width = lcd_current_viewport->width;
height = lcd_current_viewport->height;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
len = STRIDE_MAIN(width, height);
step = STRIDE_MAIN(ROW_INC, COL_INC);
@@ -222,30 +198,6 @@ void lcd_fillrect(int x, int y, int width, int height)
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
/* drawmode and optimisation */
if (lcd_current_viewport->drawmode & DRMODE_INVERSEVID)
{
@@ -362,32 +314,6 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
src_end = src + width;
@@ -592,32 +518,6 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
/* the following drawmode combinations are possible:
* 1) COMPLEMENT: just negates the framebuffer contents
* 2) BG and BG+backdrop: draws _only_ background pixels with either
@@ -887,20 +787,6 @@ void lcd_hline(int x1, int x2, int y)
x2 += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
- || (x2 < 0))
- return;
-
- /* clipping */
- if (x1 < 0)
- x1 = 0;
- if (x2 >= LCD_WIDTH)
- x2 = LCD_WIDTH-1;
-#endif
-
width = x2 - x1 + 1;
dst = FBADDR(x1 , y);
@@ -944,20 +830,6 @@ void lcd_vline(int x, int y1, int y2)
y1 += lcd_current_viewport->y;
y2 += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
- || (y2 < 0))
- return;
-
- /* clipping */
- if (y1 < 0)
- y1 = 0;
- if (y2 >= LCD_HEIGHT)
- y2 = LCD_HEIGHT-1;
-#endif
-
dst = FBADDR(x , y1);
dst_end = dst + (y2 - y1) * LCD_WIDTH;
@@ -1004,32 +876,6 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
src += stride * src_y + src_x; /* move starting point */
dst = FBADDR(x, y);
@@ -1078,32 +924,6 @@ void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
src += stride * src_y + src_x; /* move starting point */
dst = FBADDR(x, y);
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c
index 85918a735c..66313d624b 100644
--- a/firmware/drivers/lcd-2bit-horz.c
+++ b/firmware/drivers/lcd-2bit-horz.c
@@ -420,10 +420,6 @@ void lcd_drawpixel(int x, int y)
{
if ( ((unsigned)x < (unsigned)lcd_current_viewport->width)
&& ((unsigned)y < (unsigned)lcd_current_viewport->height)
-#if defined(HAVE_VIEWPORT_CLIP)
- && ((unsigned)x < (unsigned)LCD_WIDTH)
- && ((unsigned)y < (unsigned)LCD_HEIGHT)
-#endif
)
lcd_pixelfuncs[lcd_current_viewport->drawmode](lcd_current_viewport->x + x, lcd_current_viewport->y + y);
}
@@ -495,10 +491,6 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
{
if ( ((unsigned)x < (unsigned)lcd_current_viewport->width)
&& ((unsigned)y < (unsigned)lcd_current_viewport->height)
-#if defined(HAVE_VIEWPORT_CLIP)
- && ((unsigned)x < (unsigned)LCD_WIDTH)
- && ((unsigned)y < (unsigned)LCD_HEIGHT)
-#endif
)
pfunc(lcd_current_viewport->x + x, lcd_current_viewport->y + y);
@@ -549,20 +541,6 @@ void lcd_hline(int x1, int x2, int y)
x2 += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
- || (x2 < 0))
- return;
-
- /* clipping */
- if (x1 < 0)
- x1 = 0;
- if (x2 >= LCD_WIDTH)
- x2 = LCD_WIDTH-1;
-#endif
-
bfunc = lcd_blockfuncs[lcd_current_viewport->drawmode];
dst = FBADDR(x1>>2,y);
nx = x2 - (x1 & ~3);
@@ -611,20 +589,6 @@ void lcd_vline(int x, int y1, int y2)
y2 += lcd_current_viewport->y;
x += lcd_current_viewport->x;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
- || (y2 < 0))
- return;
-
- /* clipping */
- if (y1 < 0)
- y1 = 0;
- if (y2 >= LCD_HEIGHT)
- y2 = LCD_HEIGHT-1;
-#endif
-
bfunc = lcd_blockfuncs[lcd_current_viewport->drawmode];
dst = FBADDR(x>>2,y1);
stride_dst = LCD_FBSTRIDE(lcd_current_viewport->buffer->stride, 0);
@@ -688,30 +652,6 @@ void lcd_fillrect(int x, int y, int width, int height)
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
bfunc = lcd_blockfuncs[lcd_current_viewport->drawmode];
dst = FBADDR(x>>2,y);
stride_dst = LCD_FBSTRIDE(lcd_current_viewport->buffer->stride, 0);
@@ -792,32 +732,6 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
x += lcd_current_viewport->x; /* adjust for viewport */
y += lcd_current_viewport->y; /* adjust for viewport */
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
src_end = src + width;
@@ -1007,32 +921,6 @@ void ICODE_ATTR lcd_bitmap_part(const unsigned char *src, int src_x,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
stride = LCD_FBSTRIDE(stride, 0); /* convert to no. of bytes */
src += stride * src_y + (src_x >> 2); /* move starting point */
diff --git a/firmware/drivers/lcd-2bit-vert.c b/firmware/drivers/lcd-2bit-vert.c
index a059e3b512..4ce9960419 100644
--- a/firmware/drivers/lcd-2bit-vert.c
+++ b/firmware/drivers/lcd-2bit-vert.c
@@ -422,10 +422,6 @@ void lcd_drawpixel(int x, int y)
{
if ( ((unsigned)x < (unsigned)lcd_current_viewport->width)
&& ((unsigned)y < (unsigned)lcd_current_viewport->height)
-#if defined(HAVE_VIEWPORT_CLIP)
- && ((unsigned)x < (unsigned)LCD_WIDTH)
- && ((unsigned)y < (unsigned)LCD_HEIGHT)
-#endif
)
lcd_pixelfuncs[lcd_current_viewport->drawmode](lcd_current_viewport->x + x, lcd_current_viewport->y + y);
}
@@ -497,10 +493,6 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
{
if ( ((unsigned)x < (unsigned)lcd_current_viewport->width)
&& ((unsigned)y < (unsigned)lcd_current_viewport->height)
-#if defined(HAVE_VIEWPORT_CLIP)
- && ((unsigned)x < (unsigned)LCD_WIDTH)
- && ((unsigned)y < (unsigned)LCD_HEIGHT)
-#endif
)
pfunc(lcd_current_viewport->x + x, lcd_current_viewport->y + y);
@@ -552,20 +544,6 @@ void lcd_hline(int x1, int x2, int y)
x2 += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
- || (x2 < 0))
- return;
-
- /* clipping */
- if (x1 < 0)
- x1 = 0;
- if (x2 >= LCD_WIDTH)
- x2 = LCD_WIDTH-1;
-#endif
-
width = x2 - x1 + 1;
bfunc = lcd_blockfuncs[lcd_current_viewport->drawmode];
@@ -611,20 +589,6 @@ void lcd_vline(int x, int y1, int y2)
y2 += lcd_current_viewport->y;
x += lcd_current_viewport->x;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
- || (y2 < 0))
- return;
-
- /* clipping */
- if (y1 < 0)
- y1 = 0;
- if (y2 >= LCD_HEIGHT)
- y2 = LCD_HEIGHT-1;
-#endif
-
bfunc = lcd_blockfuncs[lcd_current_viewport->drawmode];
dst = FBADDR(x,y1>>2);
stride_dst = lcd_current_viewport->buffer->stride;
@@ -693,30 +657,6 @@ void lcd_fillrect(int x, int y, int width, int height)
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
if (lcd_current_viewport->drawmode & DRMODE_INVERSEVID)
{
if ((lcd_current_viewport->drawmode & DRMODE_BG) && !lcd_backdrop)
@@ -819,32 +759,6 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
-
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
y -= src_y;
@@ -1018,31 +932,6 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
x += lcd_current_viewport->x;
y += lcd_current_viewport->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCD_WIDTH)
- width = LCD_WIDTH - x;
- if (y + height > LCD_HEIGHT)
- height = LCD_HEIGHT - y;
-#endif
src += stride * (src_y >> 2) + src_x; /* move starting point */
src_y &= 3;
y -= src_y;
diff --git a/firmware/drivers/lcd-2bit-vi.c b/firmware/drivers/lcd-2bit-vi.c
index 423f4536d4..b969c93216 100644
--- a/firmware/drivers/lcd-2bit-vi.c
+++ b/firmware/drivers/lcd-2bit-vi.c
@@ -455,10 +455,6 @@ void LCDFN(drawpixel)(int x, int y)
{
if ( ((unsigned)x < (unsigned)CURRENT_VP->width)
&& ((unsigned)y < (unsigned)CURRENT_VP->height)
-#if defined(HAVE_VIEWPORT_CLIP)
- && ((unsigned)x < (unsigned)LCDM(WIDTH))
- && ((unsigned)y < (unsigned)LCDM(HEIGHT))
-#endif
)
LCDFN(pixelfuncs)[CURRENT_VP->drawmode](CURRENT_VP->x+x, CURRENT_VP->y+y);
}
@@ -530,10 +526,6 @@ void LCDFN(drawline)(int x1, int y1, int x2, int y2)
{
if ( ((unsigned)x < (unsigned)CURRENT_VP->width)
&& ((unsigned)y < (unsigned)CURRENT_VP->height)
-#if defined(HAVE_VIEWPORT_CLIP)
- && ((unsigned)x < (unsigned)LCDM(WIDTH))
- && ((unsigned)y < (unsigned)LCDM(HEIGHT))
-#endif
)
pfunc(CURRENT_VP->x + x, CURRENT_VP->y + y);
@@ -585,20 +577,6 @@ void LCDFN(hline)(int x1, int x2, int y)
x2 += CURRENT_VP->x;
y += CURRENT_VP->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (((unsigned)y >= (unsigned) LCDM(HEIGHT)) || (x1 >= LCDM(WIDTH))
- || (x2 < 0))
- return;
-
- /* clipping */
- if (x1 < 0)
- x1 = 0;
- if (x2 >= LCDM(WIDTH))
- x2 = LCDM(WIDTH)-1;
-#endif
-
width = x2 - x1 + 1;
bfunc = LCDFN(blockfuncs)[CURRENT_VP->drawmode];
@@ -644,20 +622,6 @@ void LCDFN(vline)(int x, int y1, int y2)
y2 += CURRENT_VP->y;
x += CURRENT_VP->x;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if (( (unsigned) x >= (unsigned)LCDM(WIDTH)) || (y1 >= LCDM(HEIGHT))
- || (y2 < 0))
- return;
-
- /* clipping */
- if (y1 < 0)
- y1 = 0;
- if (y2 >= LCDM(HEIGHT))
- y2 = LCDM(HEIGHT)-1;
-#endif
-
bfunc = LCDFN(blockfuncs)[CURRENT_VP->drawmode];
dst = LCDFB(x,y1>>3);
stride_dst = CURRENT_VP->buffer->stride;
@@ -728,31 +692,6 @@ void LCDFN(fillrect)(int x, int y, int width, int height)
x += CURRENT_VP->x;
y += CURRENT_VP->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y = 0;
- }
- if (x + width > LCDM(WIDTH))
- width = LCDM(WIDTH) - x;
- if (y + height > LCDM(HEIGHT))
- height = LCDM(HEIGHT) - y;
-#endif
-
-
if (CURRENT_VP->drawmode & DRMODE_INVERSEVID)
{
if ((CURRENT_VP->drawmode & DRMODE_BG) && !backdrop)
@@ -857,32 +796,6 @@ void ICODE_ATTR LCDFN(mono_bitmap_part)(const unsigned char *src, int src_x,
x += CURRENT_VP->x;
y += CURRENT_VP->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCDM(WIDTH))
- width = LCDM(WIDTH) - x;
- if (y + height > LCDM(HEIGHT))
- height = LCDM(HEIGHT) - y;
-#endif
-
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
y -= src_y;
@@ -1027,32 +940,6 @@ void ICODE_ATTR LCDFN(bitmap_part)(const FBFN(data) *src, int src_x,
x += CURRENT_VP->x;
y += CURRENT_VP->y;
-#if defined(HAVE_VIEWPORT_CLIP)
- /********************* Viewport on screen clipping ********************/
- /* nothing to draw? */
- if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
- || (x + width <= 0) || (y + height <= 0))
- return;
-
- /* clip image in viewport in screen */
- if (x < 0)
- {
- width += x;
- src_x -= x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- src_y -= y;
- y = 0;
- }
- if (x + width > LCDM(WIDTH))
- width = LCDM(WIDTH) - x;
- if (y + height > LCDM(HEIGHT))
- height = LCDM(HEIGHT) - y;
-#endif
-
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
y -= src_y;
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c
index c85d16cb70..24b302b6d4 100644
--- a/firmware/drivers/lcd-bitmap-common.c
+++ b/firmware/drivers/lcd-bitmap-common.c
@@ -139,11 +139,7 @@ struct viewport* LCDFN(set_viewport_ex)(struct viewport* vp, int flags)
|| vp->x + vp->width > LCDM(WIDTH)
|| vp->y + vp->height > LCDM(HEIGHT))
{
-#if !defined(HAVE_VIEWPORT_CLIP)
DEBUGF("ERROR: "
-#else
- DEBUGF("NOTE: "
-#endif
"set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
vp->x, vp->y, vp->width, vp->height);
}
diff --git a/firmware/drivers/lcd-color-common.c b/firmware/drivers/lcd-color-common.c
index a867583d36..36144b574c 100644
--- a/firmware/drivers/lcd-color-common.c
+++ b/firmware/drivers/lcd-color-common.c
@@ -198,10 +198,6 @@ void lcd_drawpixel(int x, int y)
{
if ( ((unsigned)x < (unsigned)lcd_current_viewport->width)
&& ((unsigned)y < (unsigned)lcd_current_viewport->height)
-#if defined(HAVE_VIEWPORT_CLIP)
- && ((unsigned)x < (unsigned)LCD_WIDTH)
- && ((unsigned)y < (unsigned)LCD_HEIGHT)
-#endif
)
lcd_fastpixelfuncs[lcd_current_viewport->drawmode](FBADDR(lcd_current_viewport->x+x, lcd_current_viewport->y+y));
}
@@ -281,10 +277,6 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
if ((x >= 0 && y >= 0)
&& (x < w_vp)
&& (y < h_vp)
-#if defined(HAVE_VIEWPORT_CLIP)
- && (x < LCD_WIDTH)
- && (y < LCD_HEIGHT)
-#endif
)
pfunc(fbaddr( x + x_vp, y + y_vp));
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 6465bdcb0e..2519b87f0d 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -926,6 +926,9 @@ Lyre prototype 1 */
#define INCLUDE_TIMEOUT_API
#define USB_DRIVER_CLOSE
#endif
+#if CONFIG_CPU == X1000
+#define USB_DRIVER_CLOSE
+#endif
#endif
#else /* !BOOTLOADER */
@@ -1075,8 +1078,16 @@ Lyre prototype 1 */
* only while main() runs), otherwise things may go wild,
* from crashes to freezes to exploding daps.
*/
-#define INIT_ATTR __attribute__ ((section(".init")))
-#define INITDATA_ATTR __attribute__ ((section(".initdata")))
+
+
+#if defined(__APPLE__) && defined(__MACH__)
+ #define INIT_ATTR __attribute__((section ("__INIT,.init")))
+ #define INITDATA_ATTR __attribute__((section ("__INITDATA,.initdata")))
+#else
+ #define INIT_ATTR __attribute__ ((section(".init")))
+ #define INITDATA_ATTR __attribute__ ((section(".initdata")))
+#endif
+
#define HAVE_INIT_ATTR
#else
#define INIT_ATTR
@@ -1178,6 +1189,11 @@ Lyre prototype 1 */
#define INCLUDE_TIMEOUT_API
#endif /* HAVE_USB_CHARGING_ENABLE && HAVE_USBSTACK */
+#if defined(USB_STATUS_BY_EVENT) && defined(HAVE_USBSTACK)
+/* Status by event requires timeout for debouncing */
+# define INCLUDE_TIMEOUT_API
+#endif
+
#ifndef SIMULATOR
#if defined(HAVE_USBSTACK) || (CONFIG_STORAGE & STORAGE_NAND) || (CONFIG_STORAGE & STORAGE_RAMDISK)
#define STORAGE_GET_INFO
diff --git a/firmware/export/config/ipod6g.h b/firmware/export/config/ipod6g.h
index 2e4afbdf63..b03b1131bd 100644
--- a/firmware/export/config/ipod6g.h
+++ b/firmware/export/config/ipod6g.h
@@ -133,11 +133,9 @@
/* 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
+/* Buffer for plugins and codecs. */
+#define PLUGIN_BUFFER_SIZE 0x200000 /* 2 MiB */
+#define CODEC_SIZE 0x100000 /* 1 MiB */
/* 6g has a standard battery of 550mAh, except for the thick 6g (2007 160gb)
* which has a standard battery of 850mAh.
diff --git a/firmware/export/config/mrobe500.h b/firmware/export/config/mrobe500.h
index ffc8a6bfb8..ebda42d160 100644
--- a/firmware/export/config/mrobe500.h
+++ b/firmware/export/config/mrobe500.h
@@ -65,9 +65,6 @@
/* define this if the target has volume keys which can be used in the lists */
#define HAVE_VOLUME_IN_LIST
-/* define this if you want viewport clipping enabled for safe LCD functions */
-#define HAVE_VIEWPORT_CLIP
-
/* LCD dimensions */
#define CONFIG_LCD LCD_MROBE500
diff --git a/firmware/export/config/sansaconnect.h b/firmware/export/config/sansaconnect.h
index fa929f3c10..a06ea9b207 100644
--- a/firmware/export/config/sansaconnect.h
+++ b/firmware/export/config/sansaconnect.h
@@ -66,9 +66,6 @@
/* define this if the target has volume keys which can be used in the lists */
#define HAVE_VOLUME_IN_LIST
-/* define this if you want viewport clipping enabled for safe LCD functions */
-#define HAVE_VIEWPORT_CLIP
-
/* LCD dimensions */
#define CONFIG_LCD LCD_CONNECT
diff --git a/firmware/include/buflib.h b/firmware/include/buflib.h
index e805ebbf1b..d2231ab79d 100644
--- a/firmware/include/buflib.h
+++ b/firmware/include/buflib.h
@@ -38,7 +38,7 @@ union buflib_data
intptr_t val; /* length of the block in n*sizeof(union buflib_data).
Includes buflib metadata overhead. A negative value
indicates block is unallocated */
- char name[1]; /* name, actually a variable sized string */
+ volatile unsigned pincount; /* number of pins */
struct buflib_callbacks* ops; /* callback functions for move and shrink. Can be NULL */
char* alloc; /* start of allocated memory area */
union buflib_data *handle; /* pointer to entry in the handle table.
@@ -65,7 +65,7 @@ struct buflib_context
* BUFLIB_ALLOC_OVERHEAD + requested bytes + strlen(<name passed to
* buflib_alloc_ex()) + pad to pointer size
*/
-#define BUFLIB_ALLOC_OVERHEAD (6*sizeof(union buflib_data))
+#define BUFLIB_ALLOC_OVERHEAD (5*sizeof(union buflib_data))
/**
* Callbacks used by the buflib to inform allocation that compaction
@@ -293,6 +293,25 @@ static inline void* buflib_get_data(struct buflib_context *ctx, int handle)
bool buflib_shrink(struct buflib_context *ctx, int handle, void* newstart, size_t new_size);
/**
+ * Increment the pin count for a handle. When pinned the handle will not
+ * be moved and move callbacks will not be triggered, allowing a pointer
+ * to the buffer to be kept across yields or used for I/O.
+ *
+ * Note that shrink callbacks can still be invoked for pinned handles.
+ */
+void buflib_pin(struct buflib_context *ctx, int handle);
+
+/**
+ * Decrement the pin count for a handle.
+ */
+void buflib_unpin(struct buflib_context *ctx, int handle);
+
+/**
+ * Get the current pin count of a handle. Zero means the handle is not pinned.
+ */
+unsigned buflib_pin_count(struct buflib_context *ctx, int handle);
+
+/**
* Frees memory associated with the given handle
*
* Returns: 0 (to invalidate handles in one line, 0 is not a valid handle)
@@ -342,27 +361,6 @@ void buflib_buffer_in(struct buflib_context *ctx, int size);
const char* buflib_get_name(struct buflib_context *ctx, int handle);
/**
- * Prints an overview of all current allocations with the help
- * of the passed printer helper
- *
- * This walks only the handle table and prints only valid allocations
- *
- * Only available if BUFLIB_DEBUG_BLOCKS is defined
- */
-void buflib_print_allocs(struct buflib_context *ctx, void (*print)(int, const char*));
-
-/**
- * Prints an overview of all blocks in the buflib buffer, allocated
- * or unallocated, with the help of the passed printer helper
- *
- * This walks the entire buffer and prints unallocated space also.
- * The output is also different from buflib_print_allocs().
- *
- * Only available if BUFLIB_DEBUG_BLOCKS is defined
- */
-void buflib_print_blocks(struct buflib_context *ctx, void (*print)(int, const char*));
-
-/**
* Gets the number of blocks in the entire buffer, allocated or unallocated
*
* Only available if BUFLIB_DEBUG_BLOCK_SIGNLE is defined
diff --git a/firmware/include/core_alloc.h b/firmware/include/core_alloc.h
index 67fe99dfdc..87246bcbd6 100644
--- a/firmware/include/core_alloc.h
+++ b/firmware/include/core_alloc.h
@@ -14,6 +14,9 @@ int core_alloc(const char* name, size_t size);
int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks *ops);
int core_alloc_maximum(const char* name, size_t *size, struct buflib_callbacks *ops);
bool core_shrink(int handle, void* new_start, size_t new_size);
+void core_pin(int handle);
+void core_unpin(int handle);
+unsigned core_pin_count(int handle);
int core_free(int handle);
size_t core_available(void);
size_t core_allocatable(void);
@@ -25,10 +28,6 @@ void core_check_valid(void);
/* DO NOT ADD wrappers for buflib_buffer_out/in. They do not call
* the move callbacks and are therefore unsafe in the core */
-#ifdef BUFLIB_DEBUG_BLOCKS
-void core_print_allocs(void (*print)(const char*));
-void core_print_blocks(void (*print)(const char*));
-#endif
#ifdef BUFLIB_DEBUG_BLOCK_SINGLE
int core_get_num_blocks(void);
void core_print_block_at(int block_num, char* buf, size_t bufsize);
diff --git a/firmware/include/rbendian.h b/firmware/include/rbendian.h
index 8adcb544f9..8a6bb43a05 100644
--- a/firmware/include/rbendian.h
+++ b/firmware/include/rbendian.h
@@ -184,4 +184,241 @@ static inline uint32_t swaw32_hw(uint32_t value)
#error "Unknown endianness!"
#endif
+/*
+ * Generic unaligned loads
+ */
+static inline uint16_t _generic_load_le16(const void* p)
+{
+ const uint8_t* d = p;
+ return d[0] | (d[1] << 8);
+}
+
+static inline uint32_t _generic_load_le32(const void* p)
+{
+ const uint8_t* d = p;
+ return d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
+}
+
+static inline uint64_t _generic_load_le64(const void* p)
+{
+ const uint8_t* d = p;
+ return (((uint64_t)d[0] << 0) | ((uint64_t)d[1] << 8) |
+ ((uint64_t)d[2] << 16) | ((uint64_t)d[3] << 24) |
+ ((uint64_t)d[4] << 32) | ((uint64_t)d[5] << 40) |
+ ((uint64_t)d[6] << 48) | ((uint64_t)d[7] << 56));
+}
+
+static inline uint16_t _generic_load_be16(const void* p)
+{
+ const uint8_t* d = p;
+ return (d[0] << 8) | d[1];
+}
+
+static inline uint32_t _generic_load_be32(const void* p)
+{
+ const uint8_t* d = p;
+ return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
+}
+
+static inline uint64_t _generic_load_be64(const void* p)
+{
+ const uint8_t* d = p;
+ return (((uint64_t)d[0] << 56) | ((uint64_t)d[1] << 48) |
+ ((uint64_t)d[2] << 40) | ((uint64_t)d[3] << 32) |
+ ((uint64_t)d[4] << 24) | ((uint64_t)d[5] << 16) |
+ ((uint64_t)d[6] << 8) | ((uint64_t)d[7] << 0));
+}
+
+static inline void _generic_store_le16(void* p, uint16_t val)
+{
+ uint8_t* d = p;
+ d[0] = val & 0xff;
+ d[1] = (val >> 8) & 0xff;
+}
+
+static inline void _generic_store_le32(void* p, uint32_t val)
+{
+ uint8_t* d = p;
+ d[0] = val & 0xff;
+ d[1] = (val >> 8) & 0xff;
+ d[2] = (val >> 16) & 0xff;
+ d[3] = (val >> 24) & 0xff;
+}
+
+static inline void _generic_store_le64(void* p, uint64_t val)
+{
+ uint8_t* d = p;
+ d[0] = val & 0xff;
+ d[1] = (val >> 8) & 0xff;
+ d[2] = (val >> 16) & 0xff;
+ d[3] = (val >> 24) & 0xff;
+ d[4] = (val >> 32) & 0xff;
+ d[5] = (val >> 40) & 0xff;
+ d[6] = (val >> 48) & 0xff;
+ d[7] = (val >> 56) & 0xff;
+}
+
+static inline void _generic_store_be16(void* p, uint16_t val)
+{
+ uint8_t* d = p;
+ d[0] = (val >> 8) & 0xff;
+ d[1] = val & 0xff;
+}
+
+static inline void _generic_store_be32(void* p, uint32_t val)
+{
+ uint8_t* d = p;
+ d[0] = (val >> 24) & 0xff;
+ d[1] = (val >> 16) & 0xff;
+ d[2] = (val >> 8) & 0xff;
+ d[3] = val & 0xff;
+}
+
+static inline void _generic_store_be64(void* p, uint64_t val)
+{
+ uint8_t* d = p;
+ d[0] = (val >> 56) & 0xff;
+ d[1] = (val >> 48) & 0xff;
+ d[2] = (val >> 40) & 0xff;
+ d[3] = (val >> 32) & 0xff;
+ d[4] = (val >> 24) & 0xff;
+ d[5] = (val >> 16) & 0xff;
+ d[6] = (val >> 8) & 0xff;
+ d[7] = val & 0xff;
+}
+
+#if !defined(HAVE_UNALIGNED_LOAD_STORE)
+
+/* Use generic unaligned loads */
+#define load_le16 _generic_load_le16
+#define load_le32 _generic_load_le32
+#define load_le64 _generic_load_le64
+#define load_be16 _generic_load_be16
+#define load_be32 _generic_load_be32
+#define load_be64 _generic_load_be64
+#define store_le16 _generic_store_le16
+#define store_le32 _generic_store_le32
+#define store_le64 _generic_store_le64
+#define store_be16 _generic_store_be16
+#define store_be32 _generic_store_be32
+#define store_be64 _generic_store_be64
+
+/* Define host byte order unaligned load */
+#if defined(ROCKBOX_LITTLE_ENDIAN)
+# define load_h16 load_le16
+# define load_h32 load_le32
+# define load_h64 load_le64
+# define store_h16 store_le16
+# define store_h32 store_le32
+# define store_h64 store_le64
+#elif defined(ROCKBOX_BIG_ENDIAN)
+# define load_h16 load_be16
+# define load_h32 load_be32
+# define load_h64 load_be64
+# define store_h16 store_be16
+# define store_h32 store_be32
+# define store_h64 store_be64
+#else
+# error
+#endif
+
+#else /* HAVE_UNALIGNED_LOAD_STORE */
+
+/* The arch should define unaligned loads in host byte order */
+#if defined(ROCKBOX_LITTLE_ENDIAN)
+# define load_le16 load_h16
+# define load_le32 load_h32
+# define load_le64 load_h64
+# define load_be16(p) swap16(load_h16((p)))
+# define load_be32(p) swap32(load_h32((p)))
+# define load_be64(p) swap64(load_h64((p)))
+# define store_le16 store_h16
+# define store_le32 store_h32
+# define store_le64 store_h64
+# define store_be16(p,v) store_h16((p),swap16((v)))
+# define store_be32(p,v) store_h32((p),swap32((v)))
+# define store_be64(p,v) store_h64((p),swap64((v)))
+#elif defined(ROCKBOX_BIG_ENDIAN)
+# define load_le16(p) swap16(load_h16((p)))
+# define load_le32(p) swap32(load_h32((p)))
+# define load_le64(p) swap64(load_h64((p)))
+# define load_be16 load_h16
+# define load_be32 load_h32
+# define load_be64 load_h64
+# define store_le16(p,v) store_h16((p),swap16((v)))
+# define store_le32(p,v) store_h32((p),swap32((v)))
+# define store_le64(p,v) store_h64((p),swap64((v)))
+# define store_be16 store_h16
+# define store_be32 store_h32
+# define store_be64 store_h64
+#else
+# error
+#endif
+
+#endif /* HAVE_UNALIGNED_LOAD_STORE */
+
+/*
+ * Aligned loads
+ */
+
+static inline uint16_t load_h16_aligned(const void* p)
+{
+ return *(const uint16_t*)p;
+}
+
+static inline uint32_t load_h32_aligned(const void* p)
+{
+ return *(const uint32_t*)p;
+}
+
+static inline uint64_t load_h64_aligned(const void* p)
+{
+ return *(const uint64_t*)p;
+}
+
+static inline void store_h16_aligned(void* p, uint16_t val)
+{
+ *(uint16_t*)p = val;
+}
+
+static inline void store_h32_aligned(void* p, uint32_t val)
+{
+ *(uint32_t*)p = val;
+}
+
+static inline void store_h64_aligned(void* p, uint64_t val)
+{
+ *(uint64_t*)p = val;
+}
+
+#if defined(ROCKBOX_LITTLE_ENDIAN)
+# define load_le16_aligned load_h16_aligned
+# define load_le32_aligned load_h32_aligned
+# define load_le64_aligned load_h64_aligned
+# define load_be16_aligned(p) swap16(load_h16_aligned((p)))
+# define load_be32_aligned(p) swap32(load_h32_aligned((p)))
+# define load_be64_aligned(p) swap64(load_h64_aligned((p)))
+# define store_le16_aligned store_h16_aligned
+# define store_le32_aligned store_h32_aligned
+# define store_le64_aligned store_h64_aligned
+# define store_be16_aligned(p,v) store_h16_aligned((p),swap16((v)))
+# define store_be32_aligned(p,v) store_h32_aligned((p),swap32((v)))
+# define store_be64_aligned(p,v) store_h64_aligned((p),swap64((v)))
+#elif defined(ROCKBOX_BIG_ENDIAN)
+# define load_le16_aligned(p) swap16(load_h16_aligned((p)))
+# define load_le32_aligned(p) swap32(load_h32_aligned((p)))
+# define load_le64_aligned(p) swap64(load_h64_aligned((p)))
+# define load_be16_aligned load_h16_aligned
+# define load_be32_aligned load_h32_aligned
+# define load_be64_aligned load_h64_aligned
+# define store_le16_aligned(p,v) store_h16_aligned((p),swap16((v)))
+# define store_le32_aligned(p,v) store_h32_aligned((p),swap32((v)))
+# define store_le64_aligned(p,v) store_h64_aligned((p),swap64((v)))
+# define store_be16_aligned store_h16_aligned
+# define store_be32_aligned store_h32_aligned
+# define store_be64_aligned store_h64_aligned
+#else
+# error "Unknown endian!"
+#endif
+
#endif /* _RBENDIAN_H_ */
diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.c b/firmware/target/mips/ingenic_x1000/boot-x1000.c
index aa97bfcd85..2f2714c67a 100644
--- a/firmware/target/mips/ingenic_x1000/boot-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/boot-x1000.c
@@ -20,6 +20,7 @@
****************************************************************************/
#include "system.h"
+#include "usb.h"
#include "boot-x1000.h"
#include "nand-x1000.h"
#include "gpio-x1000.h"
@@ -113,6 +114,14 @@ void x1000_boot_linux(const void* source, size_t length,
{
size_t args_len = strlen(args);
+ /* Shut off USB to avoid "irq 21 nobody cared" error */
+ usb_close();
+ usb_enable(false);
+
+ /* clear USB PHY voodoo bits, not all kernels use them */
+ jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0));
+ jz_writef(CPM_USBCDR, PHY_GATE(0));
+
disable_irq();
/* --- Beyond this point, do not call into DRAM --- */
@@ -121,7 +130,7 @@ void x1000_boot_linux(const void* source, size_t length,
/* copy argument string to a safe location */
char* args_copy = safe_mem + 32;
- iram_memmove(args_copy, args, args_len);
+ iram_memmove(args_copy, args, args_len+1);
/* generate argv array */
char** argv = safe_mem;
@@ -151,10 +160,6 @@ void x1000_dualboot_cleanup(void)
jz_writef(LCD_CTRL, BEDN(0), EOFM(0), SOFM(0), IFUM(0), QDM(0));
jz_writef(CPM_CLKGR, LCD(1));
- /* clear USB PHY voodoo bits, not all kernels use them */
- jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0));
- jz_writef(CPM_USBCDR, PHY_GATE(0));
-
#if defined(FIIO_M3K) || defined(EROS_QN)
/*
* Need to bring up MPLL before booting Linux
@@ -262,7 +267,7 @@ void x1000_dualboot_init_uart2(void)
int x1000_dualboot_load_pdma_fw(void)
{
- nand_drv* n = nand_init();
+ struct nand_drv* n = nand_init();
nand_lock(n);
int ret = nand_open(n);
diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.h b/firmware/target/mips/ingenic_x1000/boot-x1000.h
index 1b7a0db1e9..eb476c513d 100644
--- a/firmware/target/mips/ingenic_x1000/boot-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/boot-x1000.h
@@ -36,10 +36,10 @@ enum {
};
void x1000_boot_rockbox(const void* source, size_t length)
- __attribute__((section(".icode")));
+ __attribute__((section(".icode.x1000_boot_rockbox")));
void x1000_boot_linux(const void* source, size_t length,
void* load, void* entry, const char* args)
- __attribute__((section(".icode")));
+ __attribute__((section(".icode.x1000_boot_linux")));
/* dual boot support code */
void x1000_dualboot_cleanup(void);
diff --git a/firmware/target/mips/ingenic_x1000/installer-x1000.c b/firmware/target/mips/ingenic_x1000/installer-x1000.c
index 66aa42d4a1..48850f8a62 100644
--- a/firmware/target/mips/ingenic_x1000/installer-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/installer-x1000.c
@@ -65,7 +65,7 @@ static const int num_updates = sizeof(updates) / sizeof(struct update_part);
/* calculate the offset and length of the update image; this is constant
* for a given target, based on the update parts and the NAND chip geometry.
*/
-static void get_image_loc(nand_drv* ndrv, size_t* offptr, size_t* lenptr)
+static void get_image_loc(struct nand_drv* ndrv, size_t* offptr, size_t* lenptr)
{
size_t blk_size = ndrv->chip->page_size << ndrv->chip->log2_ppb;
size_t img_off = 0;
@@ -119,7 +119,7 @@ struct updater {
size_t img_len; /* image length in flash = size of the buffer */
mtar_t* tar;
- nand_drv* ndrv;
+ struct nand_drv* ndrv;
};
static int updater_init(struct updater* u)
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c
index 18d548ba8c..28e050fcef 100644
--- a/firmware/target/mips/ingenic_x1000/nand-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c
@@ -22,43 +22,91 @@
#include "nand-x1000.h"
#include "sfc-x1000.h"
#include "system.h"
+#include "logf.h"
#include <string.h>
-const nand_chip supported_nand_chips[] = {
-#if defined(FIIO_M3K) || defined(SHANLING_Q1) || defined(EROS_QN)
- {
- /* ATO25D1GA */
- .mf_id = 0x9b,
- .dev_id = 0x12,
- .row_cycles = 3,
- .col_cycles = 2,
- .log2_ppb = 6, /* 64 pages */
- .page_size = 2048,
- .oob_size = 64,
- .nr_blocks = 1024,
- .bbm_pos = 2048,
- .clock_freq = 150000000,
- .dev_conf = jz_orf(SFC_DEV_CONF,
- CE_DL(1), HOLD_DL(1), WP_DL(1),
- CPHA(0), CPOL(0),
- TSH(7), TSETUP(0), THOLD(0),
- STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
- SMP_DELAY(1)),
- .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT,
- },
-#else
- { 0 },
-#endif
+static void winbond_setup_chip(struct nand_drv* drv);
+
+static const struct nand_chip chip_ato25d1ga = {
+ .log2_ppb = 6, /* 64 pages */
+ .page_size = 2048,
+ .oob_size = 64,
+ .nr_blocks = 1024,
+ .bbm_pos = 2048,
+ .clock_freq = 150000000,
+ .dev_conf = jz_orf(SFC_DEV_CONF,
+ CE_DL(1), HOLD_DL(1), WP_DL(1),
+ CPHA(0), CPOL(0),
+ TSH(7), TSETUP(0), THOLD(0),
+ STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
+ SMP_DELAY(1)),
+ .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT,
+ .cmd_page_read = NANDCMD_PAGE_READ,
+ .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE,
+ .cmd_block_erase = NANDCMD_BLOCK_ERASE,
+ .cmd_read_cache = NANDCMD_READ_CACHE_x4,
+ .cmd_program_load = NANDCMD_PROGRAM_LOAD_x4,
};
-const size_t nr_supported_nand_chips =
- sizeof(supported_nand_chips) / sizeof(nand_chip);
+static const struct nand_chip chip_w25n01gvxx = {
+ .log2_ppb = 6, /* 64 pages */
+ .page_size = 2048,
+ .oob_size = 64,
+ .nr_blocks = 1024,
+ .bbm_pos = 2048,
+ .clock_freq = 150000000,
+ .dev_conf = jz_orf(SFC_DEV_CONF,
+ CE_DL(1), HOLD_DL(1), WP_DL(1),
+ CPHA(0), CPOL(0),
+ TSH(11), TSETUP(0), THOLD(0),
+ STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
+ SMP_DELAY(1)),
+ .flags = NAND_CHIPFLAG_ON_DIE_ECC,
+ /* TODO: quad mode? */
+ .cmd_page_read = NANDCMD_PAGE_READ,
+ .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE,
+ .cmd_block_erase = NANDCMD_BLOCK_ERASE,
+ .cmd_read_cache = NANDCMD_READ_CACHE_SLOW,
+ .cmd_program_load = NANDCMD_PROGRAM_LOAD,
+ .setup_chip = winbond_setup_chip,
+};
+
+static const struct nand_chip chip_gd5f1gq4xexx = {
+ .log2_ppb = 6, /* 64 pages */
+ .page_size = 2048,
+ .oob_size = 64, /* 128B when hardware ECC is disabled */
+ .nr_blocks = 1024,
+ .bbm_pos = 2048,
+ .clock_freq = 150000000,
+ .dev_conf = jz_orf(SFC_DEV_CONF,
+ CE_DL(1), HOLD_DL(1), WP_DL(1),
+ CPHA(0), CPOL(0),
+ TSH(7), TSETUP(0), THOLD(0),
+ STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
+ SMP_DELAY(1)),
+ .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT |
+ NAND_CHIPFLAG_ON_DIE_ECC,
+ .cmd_page_read = NANDCMD_PAGE_READ,
+ .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE,
+ .cmd_block_erase = NANDCMD_BLOCK_ERASE,
+ .cmd_read_cache = NANDCMD_READ_CACHE_x4,
+ .cmd_program_load = NANDCMD_PROGRAM_LOAD_x4,
+};
-static nand_drv static_nand_drv;
+const struct nand_chip_id supported_nand_chips[] = {
+ NAND_CHIP_ID(&chip_ato25d1ga, NAND_READID_ADDR, 0x9b, 0x12),
+ NAND_CHIP_ID(&chip_w25n01gvxx, NAND_READID_ADDR, 0xef, 0xaa, 0x21),
+ NAND_CHIP_ID(&chip_gd5f1gq4xexx, NAND_READID_ADDR, 0xc8, 0xd1),
+ NAND_CHIP_ID(&chip_gd5f1gq4xexx, NAND_READID_ADDR, 0xc8, 0xc1),
+};
+
+const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips);
+
+static struct nand_drv static_nand_drv;
static uint8_t static_scratch_buf[NAND_DRV_SCRATCHSIZE] CACHEALIGN_ATTR;
static uint8_t static_page_buf[NAND_DRV_MAXPAGESIZE] CACHEALIGN_ATTR;
-nand_drv* nand_init(void)
+struct nand_drv* nand_init(void)
{
static bool inited = false;
if(!inited) {
@@ -71,19 +119,19 @@ nand_drv* nand_init(void)
return &static_nand_drv;
}
-static uint8_t nand_get_reg(nand_drv* drv, uint8_t reg)
+static uint8_t nand_get_reg(struct nand_drv* drv, uint8_t reg)
{
sfc_exec(NANDCMD_GET_FEATURE, reg, drv->scratch_buf, 1|SFC_READ);
return drv->scratch_buf[0];
}
-static void nand_set_reg(nand_drv* drv, uint8_t reg, uint8_t val)
+static void nand_set_reg(struct nand_drv* drv, uint8_t reg, uint8_t val)
{
drv->scratch_buf[0] = val;
sfc_exec(NANDCMD_SET_FEATURE, reg, drv->scratch_buf, 1|SFC_WRITE);
}
-static void nand_upd_reg(nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val)
+static void nand_upd_reg(struct nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val)
{
uint8_t x = nand_get_reg(drv, reg);
x &= ~msk;
@@ -91,56 +139,50 @@ static void nand_upd_reg(nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val)
nand_set_reg(drv, reg, x);
}
-static bool identify_chip(nand_drv* drv)
+static const struct nand_chip* identify_chip_method(uint8_t method,
+ const uint8_t* id_buf)
+{
+ for (size_t i = 0; i < nr_supported_nand_chips; ++i) {
+ const struct nand_chip_id* chip_id = &supported_nand_chips[i];
+ if (chip_id->method == method &&
+ !memcmp(chip_id->id_bytes, id_buf, chip_id->num_id_bytes))
+ return chip_id->chip;
+ }
+
+ return NULL;
+}
+
+static bool identify_chip(struct nand_drv* drv)
{
/* Read ID command has some variations; Linux handles these 3:
* - no address or dummy bytes
* - 1 byte address, no dummy byte
* - no address byte, 1 byte dummy
*
- * Right now there is only a need for the 2nd variation, as that is
- * the method used by the ATO25D1GA.
- *
- * Some chips also output more than 2 ID bytes.
+ * Currently we use the 2nd method, aka. address read ID, the
+ * other methods can be added when needed.
*/
- sfc_exec(NANDCMD_READID(1, 0), 0, drv->scratch_buf, 2|SFC_READ);
- drv->mf_id = drv->scratch_buf[0];
- drv->dev_id = drv->scratch_buf[1];
-
- for(size_t i = 0; i < nr_supported_nand_chips; ++i) {
- const nand_chip* chip = &supported_nand_chips[i];
- if(chip->mf_id == drv->mf_id && chip->dev_id == drv->dev_id) {
- drv->chip = chip;
- return true;
- }
- }
+ sfc_exec(NANDCMD_READID_ADDR, 0, drv->scratch_buf, 4|SFC_READ);
+ drv->chip = identify_chip_method(NAND_READID_ADDR, drv->scratch_buf);
+ if (drv->chip)
+ return true;
return false;
}
-static void setup_chip_data(nand_drv* drv)
+static void setup_chip_data(struct nand_drv* drv)
{
drv->ppb = 1 << drv->chip->log2_ppb;
drv->fpage_size = drv->chip->page_size + drv->chip->oob_size;
}
-static void setup_chip_commands(nand_drv* drv)
+static void winbond_setup_chip(struct nand_drv* drv)
{
- /* Select commands appropriate for the chip */
- drv->cmd_page_read = NANDCMD_PAGE_READ(drv->chip->row_cycles);
- drv->cmd_program_execute = NANDCMD_PROGRAM_EXECUTE(drv->chip->row_cycles);
- drv->cmd_block_erase = NANDCMD_BLOCK_ERASE(drv->chip->row_cycles);
-
- if(drv->chip->flags & NAND_CHIPFLAG_QUAD) {
- drv->cmd_read_cache = NANDCMD_READ_CACHE_x4(drv->chip->col_cycles);
- drv->cmd_program_load = NANDCMD_PROGRAM_LOAD_x4(drv->chip->col_cycles);
- } else {
- drv->cmd_read_cache = NANDCMD_READ_CACHE(drv->chip->col_cycles);
- drv->cmd_program_load = NANDCMD_PROGRAM_LOAD(drv->chip->col_cycles);
- }
+ /* Ensure we are in buffered read mode. */
+ nand_upd_reg(drv, FREG_CFG, FREG_CFG_WINBOND_BUF, FREG_CFG_WINBOND_BUF);
}
-static void setup_chip_registers(nand_drv* drv)
+static void setup_chip_registers(struct nand_drv* drv)
{
/* Set chip registers to enter normal operation */
if(drv->chip->flags & NAND_CHIPFLAG_HAS_QE_BIT) {
@@ -149,14 +191,23 @@ static void setup_chip_registers(nand_drv* drv)
en ? FREG_CFG_QUAD_ENABLE : 0);
}
+ if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) {
+ /* Enable on-die ECC */
+ nand_upd_reg(drv, FREG_CFG, FREG_CFG_ECC_ENABLE, FREG_CFG_ECC_ENABLE);
+ }
+
/* Clear OTP bit to access the main data array */
nand_upd_reg(drv, FREG_CFG, FREG_CFG_OTP_ENABLE, 0);
/* Clear write protection bits */
nand_set_reg(drv, FREG_PROT, FREG_PROT_UNLOCK);
+
+ /* Call any chip-specific hooks */
+ if(drv->chip->setup_chip)
+ drv->chip->setup_chip(drv);
}
-int nand_open(nand_drv* drv)
+int nand_open(struct nand_drv* drv)
{
if(drv->refcount > 0) {
drv->refcount++;
@@ -165,8 +216,13 @@ int nand_open(nand_drv* drv)
/* Initialize the controller */
sfc_open();
- sfc_set_dev_conf(supported_nand_chips[0].dev_conf);
- sfc_set_clock(supported_nand_chips[0].clock_freq);
+ sfc_set_dev_conf(jz_orf(SFC_DEV_CONF,
+ CE_DL(1), HOLD_DL(1), WP_DL(1),
+ CPHA(0), CPOL(0),
+ TSH(15), TSETUP(0), THOLD(0),
+ STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
+ SMP_DELAY(0)));
+ sfc_set_clock(X1000_EXCLK_FREQ);
/* Send the software reset command */
sfc_exec(NANDCMD_RESET, 0, NULL, 0);
@@ -177,7 +233,6 @@ int nand_open(nand_drv* drv)
return NAND_ERR_UNKNOWN_CHIP;
setup_chip_data(drv);
- setup_chip_commands(drv);
/* Set new SFC parameters */
sfc_set_dev_conf(drv->chip->dev_conf);
@@ -190,7 +245,7 @@ int nand_open(nand_drv* drv)
return NAND_SUCCESS;
}
-void nand_close(nand_drv* drv)
+void nand_close(struct nand_drv* drv)
{
--drv->refcount;
if(drv->refcount > 0)
@@ -204,7 +259,13 @@ void nand_close(nand_drv* drv)
sfc_close();
}
-static uint8_t nand_wait_busy(nand_drv* drv)
+void nand_enable_otp(struct nand_drv* drv, bool enable)
+{
+ nand_upd_reg(drv, FREG_CFG, FREG_CFG_OTP_ENABLE,
+ enable ? FREG_CFG_OTP_ENABLE : 0);
+}
+
+static uint8_t nand_wait_busy(struct nand_drv* drv)
{
uint8_t reg;
do {
@@ -213,10 +274,10 @@ static uint8_t nand_wait_busy(nand_drv* drv)
return reg;
}
-int nand_block_erase(nand_drv* drv, nand_block_t block)
+int nand_block_erase(struct nand_drv* drv, nand_block_t block)
{
sfc_exec(NANDCMD_WR_EN, 0, NULL, 0);
- sfc_exec(drv->cmd_block_erase, block, NULL, 0);
+ sfc_exec(drv->chip->cmd_block_erase, block, NULL, 0);
uint8_t status = nand_wait_busy(drv);
if(status & FREG_STATUS_EFAIL)
@@ -225,11 +286,12 @@ int nand_block_erase(nand_drv* drv, nand_block_t block)
return NAND_SUCCESS;
}
-int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer)
+int nand_page_program(struct nand_drv* drv, nand_page_t page, const void* buffer)
{
sfc_exec(NANDCMD_WR_EN, 0, NULL, 0);
- sfc_exec(drv->cmd_program_load, 0, (void*)buffer, drv->fpage_size|SFC_WRITE);
- sfc_exec(drv->cmd_program_execute, page, NULL, 0);
+ sfc_exec(drv->chip->cmd_program_load,
+ 0, (void*)buffer, drv->fpage_size|SFC_WRITE);
+ sfc_exec(drv->chip->cmd_program_execute, page, NULL, 0);
uint8_t status = nand_wait_busy(drv);
if(status & FREG_STATUS_PFAIL)
@@ -238,15 +300,29 @@ int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer)
return NAND_SUCCESS;
}
-int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer)
+int nand_page_read(struct nand_drv* drv, nand_page_t page, void* buffer)
{
- sfc_exec(drv->cmd_page_read, page, NULL, 0);
+ sfc_exec(drv->chip->cmd_page_read, page, NULL, 0);
nand_wait_busy(drv);
- sfc_exec(drv->cmd_read_cache, 0, buffer, drv->fpage_size|SFC_READ);
+ sfc_exec(drv->chip->cmd_read_cache, 0, buffer, drv->fpage_size|SFC_READ);
+
+ if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) {
+ uint8_t status = nand_get_reg(drv, FREG_STATUS);
+
+ if(status & FREG_STATUS_ECC_UNCOR_ERR) {
+ logf("ecc uncorrectable error on page %08lx", (unsigned long)page);
+ return NAND_ERR_ECC_FAIL;
+ }
+
+ if(status & FREG_STATUS_ECC_HAS_FLIPS) {
+ logf("ecc corrected bitflips on page %08lx", (unsigned long)page);
+ }
+ }
+
return NAND_SUCCESS;
}
-int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer)
+int nand_read_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer)
{
if(byte_len == 0)
return NAND_SUCCESS;
@@ -274,7 +350,7 @@ int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void*
return NAND_SUCCESS;
}
-int nand_write_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer)
+int nand_write_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer)
{
if(byte_len == 0)
return NAND_SUCCESS;
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h
index 5e6d1f09bc..0ccd075079 100644
--- a/firmware/target/mips/ingenic_x1000/nand-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h
@@ -32,6 +32,7 @@
#define NAND_ERR_PROGRAM_FAIL (-2)
#define NAND_ERR_ERASE_FAIL (-3)
#define NAND_ERR_UNALIGNED (-4)
+#define NAND_ERR_ECC_FAIL (-5)
/* keep max page size in sync with the NAND chip table in the .c file */
#define NAND_DRV_SCRATCHSIZE 32
@@ -41,21 +42,25 @@
#define NAND_CHIPFLAG_QUAD 0x0001
/* Chip requires QE bit set to enable quad I/O mode */
#define NAND_CHIPFLAG_HAS_QE_BIT 0x0002
+/* True if the chip has on-die ECC */
+#define NAND_CHIPFLAG_ON_DIE_ECC 0x0004
/* cmd mode a d phase format has data */
#define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0)
-#define NANDCMD_READID(x,y) SFC_CMD(0x9f, SFC_TMODE_1_1_1, x, y, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_READID_OPCODE SFC_CMD(0x9f, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_READID_ADDR SFC_CMD(0x9f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_READID_DUMMY SFC_CMD(0x9f, SFC_TMODE_1_1_1, 0, 8, SFC_PFMT_ADDR_FIRST, 1)
#define NANDCMD_WR_EN SFC_CMD(0x06, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0)
#define NANDCMD_GET_FEATURE SFC_CMD(0x0f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1)
#define NANDCMD_SET_FEATURE SFC_CMD(0x1f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_PAGE_READ(x) SFC_CMD(0x13, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0)
-#define NANDCMD_READ_CACHE_SLOW(x) SFC_CMD(0x03, SFC_TMODE_1_1_1, x, 8, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_READ_CACHE(x) SFC_CMD(0x0b, SFC_TMODE_1_1_1, x, 8, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_READ_CACHE_x4(x) SFC_CMD(0x6b, SFC_TMODE_1_1_4, x, 8, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_PROGRAM_LOAD(x) SFC_CMD(0x02, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_PROGRAM_LOAD_x4(x) SFC_CMD(0x32, SFC_TMODE_1_1_4, x, 0, SFC_PFMT_ADDR_FIRST, 1)
-#define NANDCMD_PROGRAM_EXECUTE(x) SFC_CMD(0x10, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0)
-#define NANDCMD_BLOCK_ERASE(x) SFC_CMD(0xd8, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0)
+#define NANDCMD_PAGE_READ SFC_CMD(0x13, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0)
+#define NANDCMD_READ_CACHE_SLOW SFC_CMD(0x03, SFC_TMODE_1_1_1, 2, 8, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_READ_CACHE SFC_CMD(0x0b, SFC_TMODE_1_1_1, 2, 8, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_READ_CACHE_x4 SFC_CMD(0x6b, SFC_TMODE_1_1_4, 2, 8, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_PROGRAM_EXECUTE SFC_CMD(0x10, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0)
+#define NANDCMD_PROGRAM_LOAD SFC_CMD(0x02, SFC_TMODE_1_1_1, 2, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_PROGRAM_LOAD_x4 SFC_CMD(0x32, SFC_TMODE_1_1_4, 2, 0, SFC_PFMT_ADDR_FIRST, 1)
+#define NANDCMD_BLOCK_ERASE SFC_CMD(0xd8, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0)
/* Feature registers are found in linux/mtd/spinand.h,
* apparently these are pretty standardized */
@@ -67,6 +72,9 @@
#define FREG_CFG_ECC_ENABLE (1 << 4)
#define FREG_CFG_QUAD_ENABLE (1 << 0)
+/* Winbond-specific bit used on the W25N01GVxx */
+#define FREG_CFG_WINBOND_BUF (1 << 3)
+
#define FREG_STATUS 0xc0
#define FREG_STATUS_BUSY (1 << 0)
#define FREG_STATUS_EFAIL (1 << 2)
@@ -93,15 +101,9 @@
typedef uint32_t nand_block_t;
typedef uint32_t nand_page_t;
-typedef struct nand_chip {
- /* Manufacturer and device ID bytes */
- uint8_t mf_id;
- uint8_t dev_id;
-
- /* Row/column address width */
- uint8_t row_cycles;
- uint8_t col_cycles;
+struct nand_drv;
+struct nand_chip {
/* Base2 logarithm of the number of pages per block */
unsigned log2_ppb;
@@ -123,9 +125,38 @@ typedef struct nand_chip {
/* Chip specific flags */
uint32_t flags;
-} nand_chip;
-typedef struct nand_drv {
+ /* SFC commands for issuing I/O ops */
+ uint32_t cmd_page_read;
+ uint32_t cmd_program_execute;
+ uint32_t cmd_block_erase;
+ uint32_t cmd_read_cache;
+ uint32_t cmd_program_load;
+
+ /* Chip-specific setup routine */
+ void(*setup_chip)(struct nand_drv* drv);
+};
+
+enum nand_readid_method {
+ NAND_READID_OPCODE,
+ NAND_READID_ADDR,
+ NAND_READID_DUMMY,
+};
+
+struct nand_chip_id {
+ uint8_t method;
+ uint8_t num_id_bytes;
+ uint8_t id_bytes[4];
+ const struct nand_chip* chip;
+};
+
+#define NAND_CHIP_ID(_chip, _method, ...) \
+ { .method = _method, \
+ .num_id_bytes = ARRAYLEN(((uint8_t[]){__VA_ARGS__})), \
+ .id_bytes = {__VA_ARGS__}, \
+ .chip = _chip }
+
+struct nand_drv {
/* NAND access lock. Needs to be held during any operations. */
struct mutex mutex;
@@ -147,27 +178,16 @@ typedef struct nand_drv {
uint8_t* page_buf;
/* Pointer to the chip data. */
- const nand_chip* chip;
+ const struct nand_chip* chip;
/* Pages per block = 1 << chip->log2_ppb */
unsigned ppb;
/* Full page size = chip->page_size + chip->oob_size */
unsigned fpage_size;
+};
- /* Probed mf_id / dev_id for debugging, in case identification fails. */
- uint8_t mf_id;
- uint8_t dev_id;
-
- /* SFC commands used for I/O, these are set based on chip data */
- uint32_t cmd_page_read;
- uint32_t cmd_read_cache;
- uint32_t cmd_program_load;
- uint32_t cmd_program_execute;
- uint32_t cmd_block_erase;
-} nand_drv;
-
-extern const nand_chip supported_nand_chips[];
+extern const struct nand_chip_id supported_nand_chips[];
extern const size_t nr_supported_nand_chips;
/* Return the static NAND driver instance.
@@ -175,14 +195,14 @@ extern const size_t nr_supported_nand_chips;
* ALL normal Rockbox code should use this instance. The SPL does not
* use it, because it needs to manually place buffers in external RAM.
*/
-extern nand_drv* nand_init(void);
+extern struct nand_drv* nand_init(void);
-static inline void nand_lock(nand_drv* drv)
+static inline void nand_lock(struct nand_drv* drv)
{
mutex_lock(&drv->mutex);
}
-static inline void nand_unlock(nand_drv* drv)
+static inline void nand_unlock(struct nand_drv* drv)
{
mutex_unlock(&drv->mutex);
}
@@ -196,8 +216,11 @@ static inline void nand_unlock(nand_drv* drv)
*
* These functions require the lock to be held.
*/
-extern int nand_open(nand_drv* drv);
-extern void nand_close(nand_drv* drv);
+extern int nand_open(struct nand_drv* drv);
+extern void nand_close(struct nand_drv* drv);
+
+/* Enable/disable OTP access. OTP data pages are usually vendor-specific. */
+void nand_enable_otp(struct nand_drv* drv, bool enable);
/* Read / program / erase operations. Buffer needs to be cache-aligned for DMA.
* Read and program operate on full page data, ie. including OOB data areas.
@@ -205,15 +228,15 @@ extern void nand_close(nand_drv* drv);
* NOTE: ECC is not implemented. If it ever needs to be, these functions will
* probably use ECC transparently. All code should be written to expect this.
*/
-extern int nand_block_erase(nand_drv* drv, nand_block_t block);
-extern int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer);
-extern int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer);
+extern int nand_block_erase(struct nand_drv* drv, nand_block_t block);
+extern int nand_page_program(struct nand_drv* drv, nand_page_t page, const void* buffer);
+extern int nand_page_read(struct nand_drv* drv, nand_page_t page, void* buffer);
/* Wrappers to read/write bytes. For simple access to the main data area only.
* The write address / length must align to a block boundary. Reads do not have
* any alignment requirement. OOB data is never read, and is written as 0xff.
*/
-extern int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer);
-extern int nand_write_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer);
+extern int nand_read_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer);
+extern int nand_write_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer);
#endif /* __NAND_X1000_H__ */
diff --git a/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c
index 82a05abf75..24eb42081e 100644
--- a/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c
@@ -23,7 +23,7 @@
#include "gpio-x1000.h"
#include "nand-x1000.h"
-static nand_drv* ndrv = NULL;
+static struct nand_drv* ndrv = NULL;
int spl_storage_open(void)
{
@@ -31,7 +31,7 @@ int spl_storage_open(void)
gpioz_configure(GPIO_A, 0x3f << 26, GPIOF_DEVICE(1));
/* Allocate NAND driver manually in DRAM */
- ndrv = spl_alloc(sizeof(nand_drv));
+ ndrv = spl_alloc(sizeof(struct nand_drv));
ndrv->page_buf = spl_alloc(NAND_DRV_MAXPAGESIZE);
ndrv->scratch_buf = spl_alloc(NAND_DRV_SCRATCHSIZE);
ndrv->refcount = 0;
diff --git a/firmware/usb.c b/firmware/usb.c
index c4d07c5533..32f4902c7c 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -65,6 +65,9 @@
#define USB_FULL_INIT
#endif
+/* USB detect debouncing interval (200ms taken from the usb polling code) */
+#define USB_DEBOUNCE_TIME (200*HZ/1000)
+
bool do_screendump_instead_of_usb = false;
#if !defined(SIMULATOR) && !defined(USB_NONE)
@@ -580,8 +583,33 @@ void usb_charger_update(void)
#endif
#ifdef USB_STATUS_BY_EVENT
+static int usb_status_tmo_callback(struct timeout* tmo)
+{
+ if(usb_monitor_enabled)
+ {
+ int current_status = usb_detect();
+ int* last_status = (int*)tmo->data;
+
+ if(current_status != *last_status)
+ {
+ /* Signal changed during the timeout; wait longer */
+ *last_status = current_status;
+ return USB_DEBOUNCE_TIME;
+ }
+
+ /* Signal is stable, post the event. The thread will deal with
+ * any spurious transitions (like inserted -> inserted). */
+ queue_post(&usb_queue, current_status, 0);
+ }
+
+ return 0;
+}
+
void usb_status_event(int current_status)
{
+ static struct timeout tmo;
+ static int last_status = USB_EXTRACTED;
+
/* Caller isn't expected to filter for changes in status.
* current_status:
* USB_INSERTED, USB_EXTRACTED
@@ -589,8 +617,9 @@ void usb_status_event(int current_status)
if(usb_monitor_enabled)
{
int oldstatus = disable_irq_save(); /* Dual-use function */
- queue_remove_from_head(&usb_queue, current_status);
- queue_post(&usb_queue, current_status, 0);
+ last_status = current_status;
+ timeout_register(&tmo, usb_status_tmo_callback, USB_DEBOUNCE_TIME,
+ (intptr_t)&last_status);
restore_irq(oldstatus);
}
}
@@ -626,7 +655,6 @@ void usb_firewire_connect_event(void)
static void usb_tick(void)
{
- #define NUM_POLL_READINGS (HZ/5)
static int usb_countdown = -1;
static int last_usb_status = USB_EXTRACTED;
#ifdef USB_FIREWIRE_HANDLING
@@ -641,7 +669,7 @@ static void usb_tick(void)
if(current_firewire_status != last_firewire_status)
{
last_firewire_status = current_firewire_status;
- firewire_countdown = NUM_POLL_READINGS;
+ firewire_countdown = USB_DEBOUNCE_TIME;
}
else
{
@@ -649,8 +677,7 @@ static void usb_tick(void)
if(firewire_countdown >= 0)
firewire_countdown--;
- /* Report to the thread if we have had 3 identical status
- readings in a row */
+ /* Report status when the signal has been stable long enough */
if(firewire_countdown == 0)
{
queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
@@ -664,7 +691,7 @@ static void usb_tick(void)
if(current_status != last_usb_status)
{
last_usb_status = current_status;
- usb_countdown = NUM_POLL_READINGS;
+ usb_countdown = USB_DEBOUNCE_TIME;
}
else
{
@@ -672,8 +699,7 @@ static void usb_tick(void)
if(usb_countdown >= 0)
usb_countdown--;
- /* Report to the thread if we have had 3 identical status
- readings in a row */
+ /* Report status when the signal has been stable long enough */
if(usb_countdown == 0)
{
queue_post(&usb_queue, current_status, 0);
diff --git a/lib/rbcodec/codecs/libgme/blip_buffer.c b/lib/rbcodec/codecs/libgme/blip_buffer.c
index ba0a6558d2..9aaa9d2482 100644
--- a/lib/rbcodec/codecs/libgme/blip_buffer.c
+++ b/lib/rbcodec/codecs/libgme/blip_buffer.c
@@ -53,7 +53,9 @@ void Blip_clear( struct Blip_Buffer* this )
this->reader_accum_ = 0;
this->modified = false;
+#if 0 // this is redundant as buffer is static and triggers -Waddress
if ( this->buffer_ )
+#endif
{
int count = (entire_buffer ? this->buffer_size_ : Blip_samples_avail( this ));
memset( this->buffer_, 0, (count + blip_buffer_extra_) * sizeof (delta_t) );
diff --git a/lib/skin_parser/skin_parser.h b/lib/skin_parser/skin_parser.h
index fc15aff1be..4f613d219d 100644
--- a/lib/skin_parser/skin_parser.h
+++ b/lib/skin_parser/skin_parser.h
@@ -33,8 +33,19 @@ extern "C"
/* Use this type and macro to convert a pointer from the
* skin buffer to a useable pointer */
typedef long skinoffset_t;
-#define SKINOFFSETTOPTR(base, offset) ((offset) < 0 ? NULL : ((void*)&base[offset]))
-#define PTRTOSKINOFFSET(base, pointer) ((pointer) ? ((void*)pointer-(void*)base) : -1)
+/*
+ * The statement-expression here is needed to work around a
+ * bogus -Waddress warning produced by GCC 12 when this macro
+ * is used like "if (!SKINOFFSETTOPTR(...))".
+ *
+ * Related:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102967
+ * https://godbolt.org/z/YEY4Yzdnf
+ */
+#define SKINOFFSETTOPTR(base, offset) \
+ ({ void *__p = ((offset) < 0 ? NULL : ((void*)&base[offset])); __p; })
+#define PTRTOSKINOFFSET(base, pointer) \
+ ((pointer) ? ((void*)pointer-(void*)base) : -1)
/* Use this macro when declaring a variable to self-document the code.
* type is the actual type being pointed to (i.e OFFSETTYPE(char*) foo )
*
diff --git a/manual/appendix/config_file_options.tex b/manual/appendix/config_file_options.tex
index 9de95c257b..bf231de46c 100644
--- a/manual/appendix/config_file_options.tex
+++ b/manual/appendix/config_file_options.tex
@@ -124,6 +124,8 @@
wps & /path/filename.wps & N/A\\
autocreate bookmarks
& off, on & N/A\\
+ autoupdate bookmarks
+ & off, on & N/A\\
autoload bookmarks
& off, on & N/A\\
use most-recent-bookmarks
@@ -146,8 +148,8 @@
\opt{hotkey}{
hotkey wps & off, view playlist, show track info,
pitchscreen, open with, delete & N/A\\
- \nopt{touchscreen}{hotkey tree & off, open with, delete, insert,
- insert shuffled & N/A\\}
+ \nopt{touchscreen}{hotkey tree & off, properties, pictureflow, open with,
+ delete, insert, insert shuffled & N/A\\}
}
sort files & alpha, oldest, newest, type & N/A\\
sort dirs & alpha, oldest, newest & N/A\\
diff --git a/manual/rockbox_interface/hotkeys.tex b/manual/rockbox_interface/hotkeys.tex
index ec12bd00ca..28c8091a05 100644
--- a/manual/rockbox_interface/hotkeys.tex
+++ b/manual/rockbox_interface/hotkeys.tex
@@ -1,19 +1,20 @@
% $Id$ %
\opt{hotkey}{
\section{\label{ref:Hotkeys}Hotkeys}
- Hotkeys are shortcut keys for use in the \nopt{touchscreen}{\setting{File Browser}
- and }\setting{WPS} screen. To use one, press
- \nopt{touchscreen}{\ActionTreeHotkey{} within the \setting{File Browser} or}
+ Hotkeys are shortcut keys for use in the \nopt{touchscreen}{\setting{File Browser},
+ \setting{Database}, \setting{Playlist Viewer}, and }\setting{WPS} screen. To use one, press
+ \nopt{touchscreen}{\ActionTreeHotkey{} within the \setting{File Browser},
+ \setting{Database}, or \setting{Playlist Viewer}, or}
\ActionWpsHotkey{} within the \setting{WPS}
screen.\nopt{touchscreen}{ The assigned function will launch with reference
to the current file or directory, if applicable. Each screen has its own
assignment.} If there is no assignment for a given screen,
the hotkey is ignored.
-
+
The default assignment for the \nopt{touchscreen}{File Browser hotkey is
\setting{Off}, while the default for the }WPS hotkey is
\setting{View Playlist}.
-
+
The hotkey assignments are changed in the Hotkey menu (see
\reference{ref:HotkeySettings}) under \setting{General Settings}.
}
diff --git a/tools/rockboxdev.sh b/tools/rockboxdev.sh
index 6d16f7ba45..8ff5d1734c 100755
--- a/tools/rockboxdev.sh
+++ b/tools/rockboxdev.sh
@@ -762,7 +762,7 @@ fi
if [ -z "$RBDEV_TARGET" ]; then
echo "Select target arch:"
echo "m - m68k (iriver h1x0/h3x0, iaudio m3/m5/x5 and mpio hd200)"
- echo "a - arm (ipods, iriver H10, Sansa, D2, Gigabeat, etc)"
+ echo "a - arm (ipods, iriver H10, Sansa, D2, Gigabeat, older Sony NWZ, etc)"
echo "i - mips (Jz47xx and ATJ-based players)"
echo "x - arm-linux (Generic Linux ARM: Samsung ypr0, Linux-based Sony NWZ)"
echo "y - mips-linux (Generic Linux MIPS: eg the many HiBy-OS targets)"
diff --git a/utils/rbutilqt/CMakeLists.txt b/utils/rbutilqt/CMakeLists.txt
index 41954cb9ee..24e15ac1b4 100644
--- a/utils/rbutilqt/CMakeLists.txt
+++ b/utils/rbutilqt/CMakeLists.txt
@@ -255,9 +255,44 @@ if(APPLE)
${CMAKE_CURRENT_LIST_DIR}/base/ttscarbon.h)
endif()
+find_package(QuaZip-Qt${QT_VERSION_MAJOR} QUIET)
+if(QuaZip-Qt${QT_VERSION_MAJOR}_FOUND)
+ message("-- Found QuaZip")
+ set(QUAZIP_LIBRARY QuaZip::QuaZip)
+else()
+ message("-- QuaZip not found, building our own")
+ # TODO: Upstream has cmake support, use that instead.
+ add_library(quazip
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/ioapi.h
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/minizip_crypt.h
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/qioapi.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/quazip.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipfile.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipfile.h
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipfileinfo.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipfileinfo.h
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/quazip_global.h
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/quazip.h
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipnewinfo.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipnewinfo.h
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/unzip.c
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/unzip.h
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/zip.c
+ ${CMAKE_CURRENT_LIST_DIR}/quazip/zip.h
+ )
+ target_include_directories(quazip PUBLIC ${CMAKE_CURRENT_LIST_DIR}/quazip)
+ target_link_libraries(quazip z Qt${QT_VERSION_MAJOR}::Core)
+ if(QT_VERSION_MAJOR EQUAL 6)
+ target_link_libraries(quazip Qt${QT_VERSION_MAJOR}::Core5Compat)
+ endif()
+ target_compile_definitions(quazip PUBLIC QUAZIP_STATIC)
+ set_property(TARGET quazip PROPERTY AUTOMOC ON)
+ set(QUAZIP_LIBRARY quazip)
+endif()
+
target_link_libraries(rbbase
- cutelogger quazip mspack bspatch rbspeex voicefont
- sansapatcher ipodpatcher chinachippatcher
+ cutelogger ${QUAZIP_LIBRARY} mspack bspatch rbspeex
+ voicefont sansapatcher ipodpatcher chinachippatcher
mkamsboot mkimxboot mkmpioboot mktccboot mks5lboot
Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network)
target_include_directories(rbbase PUBLIC ${CMAKE_CURRENT_LIST_DIR}/base)
@@ -298,33 +333,6 @@ target_link_libraries(cutelogger PUBLIC Qt${QT_VERSION_MAJOR}::Core)
target_compile_definitions(cutelogger PUBLIC CUTELOGGER_STATIC)
set_property(TARGET cutelogger PROPERTY AUTOMOC ON)
-# TODO: Upstream has cmake support, use that instead.
-add_library(quazip
- ${CMAKE_CURRENT_LIST_DIR}/quazip/ioapi.h
- ${CMAKE_CURRENT_LIST_DIR}/quazip/minizip_crypt.h
- ${CMAKE_CURRENT_LIST_DIR}/quazip/qioapi.cpp
- ${CMAKE_CURRENT_LIST_DIR}/quazip/quazip.cpp
- ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipfile.cpp
- ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipfile.h
- ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipfileinfo.cpp
- ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipfileinfo.h
- ${CMAKE_CURRENT_LIST_DIR}/quazip/quazip_global.h
- ${CMAKE_CURRENT_LIST_DIR}/quazip/quazip.h
- ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipnewinfo.cpp
- ${CMAKE_CURRENT_LIST_DIR}/quazip/quazipnewinfo.h
- ${CMAKE_CURRENT_LIST_DIR}/quazip/unzip.c
- ${CMAKE_CURRENT_LIST_DIR}/quazip/unzip.h
- ${CMAKE_CURRENT_LIST_DIR}/quazip/zip.c
- ${CMAKE_CURRENT_LIST_DIR}/quazip/zip.h
- )
-target_include_directories(quazip PUBLIC ${CMAKE_CURRENT_LIST_DIR}/quazip)
-target_link_libraries(quazip z Qt${QT_VERSION_MAJOR}::Core)
-if(QT_VERSION_MAJOR EQUAL 6)
- target_link_libraries(quazip Qt${QT_VERSION_MAJOR}::Core5Compat)
-endif()
-target_compile_definitions(quazip PUBLIC QUAZIP_STATIC)
-set_property(TARGET quazip PROPERTY AUTOMOC ON)
-
add_library(mspack
#mspack/cabc.c
mspack/cabd.c
diff --git a/utils/rbutilqt/base/ziputil.cpp b/utils/rbutilqt/base/ziputil.cpp
index e285446711..877a861253 100644
--- a/utils/rbutilqt/base/ziputil.cpp
+++ b/utils/rbutilqt/base/ziputil.cpp
@@ -22,9 +22,9 @@
#include "progressloglevels.h"
#include "Logger.h"
-#include "quazip/quazip.h"
-#include "quazip/quazipfile.h"
-#include "quazip/quazipfileinfo.h"
+#include <quazip.h>
+#include <quazipfile.h>
+#include <quazipfileinfo.h>
ZipUtil::ZipUtil(QObject* parent) : ArchiveUtil(parent)
diff --git a/utils/rbutilqt/base/ziputil.h b/utils/rbutilqt/base/ziputil.h
index 73a87a820a..ea32ca42c3 100644
--- a/utils/rbutilqt/base/ziputil.h
+++ b/utils/rbutilqt/base/ziputil.h
@@ -21,9 +21,9 @@
#include <QtCore>
#include "archiveutil.h"
-#include "quazip/quazip.h"
-#include "quazip/quazipfile.h"
-#include "quazip/quazipfileinfo.h"
+#include <quazip.h>
+#include <quazipfile.h>
+#include <quazipfileinfo.h>
class ZipUtil : public ArchiveUtil
{
diff --git a/wps/WPSLIST b/wps/WPSLIST
index efb1030585..596f548747 100644
--- a/wps/WPSLIST
+++ b/wps/WPSLIST
@@ -116,7 +116,7 @@ Font.360x400x16: 18-Adobe-Helvetica.fnt
Font.320x480x(16|24): 27-Adobe-Helvetica.fnt
Font.320x240x(16|24): 15-Adobe-Helvetica.fnt
Font.240x400x(16|24): 16-Adobe-Helvetica.fnt
-Font.240x320x(16|24|32): 15-Adobe-Helvetica.fnt
+Font.240x320x(16|24|32): 18-Adobe-Helvetica.fnt
Font.220x176x(16|24): 12-Adobe-Helvetica.fnt
Font.176x220x(16|24): 12-Adobe-Helvetica.fnt
Font.176x132x(16|24): 12-Adobe-Helvetica.fnt
diff --git a/wps/cabbiev2.112x64x1.wps b/wps/cabbiev2.112x64x1.wps
index 0655becce2..72a05d27b6 100644
--- a/wps/cabbiev2.112x64x1.wps
+++ b/wps/cabbiev2.112x64x1.wps
@@ -47,9 +47,9 @@
#
# Track Info
%V(0,8,-,35,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%t(5)%ac%s%?Fn<%Sx(Next:) %?It<%It|%Fn>|%ac%?Sr<%pe %Sx(of) %pp|%pp %Sx(of) %pe>>%;%t(5)%ac%s%?Fn<%Sx(Next:) %?Ia<%Ia|%?IA<%IA|%Fn>|%ac%?Sr<%pe %Sx(of) %pp|%pp %Sx(of) %pe>>>
%V(0,48,-,8,-)
%pc%ar%pr
diff --git a/wps/cabbiev2.128x128x16.wps b/wps/cabbiev2.128x128x16.wps
index c23a10e952..176b07db58 100644
--- a/wps/cabbiev2.128x128x16.wps
+++ b/wps/cabbiev2.128x128x16.wps
@@ -62,14 +62,14 @@
#
# Track Info - Album Art
%ax%Vl(a,70,12,-,50,1)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?iy<%iy>
#
# Track Info - No Album Art
%Vl(b,0,12,-,50,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?iy<%iy>
diff --git a/wps/cabbiev2.128x128x2.wps b/wps/cabbiev2.128x128x2.wps
index 6a70baca4b..c96844f197 100644
--- a/wps/cabbiev2.128x128x2.wps
+++ b/wps/cabbiev2.128x128x2.wps
@@ -62,14 +62,14 @@
#
# Track Info - Album Art
%ax%Vl(a,70,12,-,50,-)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?iy<%iy>
#
# Track Info - No Album Art
%Vl(b,0,12,-,50,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?iy<%iy>
diff --git a/wps/cabbiev2.128x160x16.wps b/wps/cabbiev2.128x160x16.wps
index ebf28f9205..01df6229cd 100644
--- a/wps/cabbiev2.128x160x16.wps
+++ b/wps/cabbiev2.128x160x16.wps
@@ -51,9 +51,9 @@
#Now Playing - NOAA
%Vl(b,0,15,-,84,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%acNext Track:
%s%ac%?It<%It|%Fn>
diff --git a/wps/cabbiev2.128x64x1.wps b/wps/cabbiev2.128x64x1.wps
index 5a473261b3..ddd94eb1fb 100644
--- a/wps/cabbiev2.128x64x1.wps
+++ b/wps/cabbiev2.128x64x1.wps
@@ -53,9 +53,9 @@
#
# Current Track Info
%V(0,16,128,24,1)
+%ac%s%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%s%?it<%it|%fn>
%ac%s%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%ac%s%?id<%id|%?d(1)<%d(1)|%(root%)>>
#
# Next Track Info
%V(0,42,128,8,1)
diff --git a/wps/cabbiev2.128x96x16.wps b/wps/cabbiev2.128x96x16.wps
index a107447192..4136fa6d8d 100644
--- a/wps/cabbiev2.128x96x16.wps
+++ b/wps/cabbiev2.128x96x16.wps
@@ -62,14 +62,14 @@
#
# Track Info - Album Art
%ax%Vl(a,51,12,-,34,1)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?iy<%iy>
#
# Track Info - No Album Art
%Vl(b,0,12,-,34,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?iy<%iy>
diff --git a/wps/cabbiev2.128x96x2.wps b/wps/cabbiev2.128x96x2.wps
index 116de16a20..43d7adc197 100644
--- a/wps/cabbiev2.128x96x2.wps
+++ b/wps/cabbiev2.128x96x2.wps
@@ -50,7 +50,7 @@
#
# Track Info
%V(0,10,128,48,1)%Vf(0)%Vb(3)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%Sx(Next:) %ac%It
diff --git a/wps/cabbiev2.132x80x16.wps b/wps/cabbiev2.132x80x16.wps
index 644b829cdc..39e35c2e2c 100644
--- a/wps/cabbiev2.132x80x16.wps
+++ b/wps/cabbiev2.132x80x16.wps
@@ -54,14 +54,14 @@
#
# Track Info - Album Art
%ax%Vl(a,48,10,-,48,1)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%Sx(Next:) %?It<%It|%Fn>
#
# Track Info - No Album Art
%Vl(b,0,10,-,48,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%Sx(Next:) %?It<%It|%Fn>
diff --git a/wps/cabbiev2.138x110x2.wps b/wps/cabbiev2.138x110x2.wps
index 8abf02f335..b27b622004 100644
--- a/wps/cabbiev2.138x110x2.wps
+++ b/wps/cabbiev2.138x110x2.wps
@@ -58,16 +58,16 @@
#
# Track Info - Album Art
%ax%Vl(a,65,10,-,60,-)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%Sx(Next Track:)
%s%al%?It<%It|%Fn>
#
# Track Info - No Album Art
%Vl(b,0,10,-,60,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%Sx(Next Track:)
%s%ac%?It<%It|%Fn>
diff --git a/wps/cabbiev2.160x128x1.wps b/wps/cabbiev2.160x128x1.wps
index e0d982585f..3d7eb51735 100644
--- a/wps/cabbiev2.160x128x1.wps
+++ b/wps/cabbiev2.160x128x1.wps
@@ -51,9 +51,9 @@
#
# Track Info - No Album Art
%V(0,12,-,75,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%Sx(Next Track:)
%s%ac%?It<%It|%Fn>
diff --git a/wps/cabbiev2.160x128x16.wps b/wps/cabbiev2.160x128x16.wps
index 8abdcddd4d..10f16077c0 100644
--- a/wps/cabbiev2.160x128x16.wps
+++ b/wps/cabbiev2.160x128x16.wps
@@ -58,18 +58,18 @@
#
# Track Info - Album Art
%ax%Vl(a,77,10,-,75,-)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%Sx(Next Track:)
%s%?It<%It|%Fn>
#
# Track Info - No Album Art
%Vl(b,0,10,-,75,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%Sx(Next Track:)
%s%ac%?It<%It|%Fn>
diff --git a/wps/cabbiev2.160x128x2.wps b/wps/cabbiev2.160x128x2.wps
index 9b46c7df84..5c0a172a1e 100644
--- a/wps/cabbiev2.160x128x2.wps
+++ b/wps/cabbiev2.160x128x2.wps
@@ -58,18 +58,18 @@
#
# Track Info - Album Art
%ax%Vl(a,70,10,-,75,-)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%Sx(Next Track:)
%s%al%?It<%It|%Fn>
#
# Track Info - No Album Art
%Vl(b,0,10,-,75,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%Sx(Next Track:)
%s%ac%?It<%It|%Fn>
diff --git a/wps/cabbiev2.176x132x16.wps b/wps/cabbiev2.176x132x16.wps
index 03b4ced194..a8b599ea3e 100644
--- a/wps/cabbiev2.176x132x16.wps
+++ b/wps/cabbiev2.176x132x16.wps
@@ -58,18 +58,18 @@
#
# Track Info - Album Art
%ax%Vl(a,81,12,-,74,1)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%Sx(Next Track:)
%s%al%?It<%It|%Fn>
#
# Track Info - No Album Art
%Vl(b,0,12,-,74,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%Sx(Next Track:)
%s%ac%?It<%It|%Fn>
diff --git a/wps/cabbiev2.176x220x16.wps b/wps/cabbiev2.176x220x16.wps
index 46d34d2a3e..6281f6cc27 100644
--- a/wps/cabbiev2.176x220x16.wps
+++ b/wps/cabbiev2.176x220x16.wps
@@ -58,15 +58,15 @@
#
# Track Info - Album Art
%ax%Vl(a,0,142,-,36,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
#
# Track Info - No Album Art
%Vl(b,0,50,-,96,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?iy<%iy|>
%ac%Sx(Next Track:)
diff --git a/wps/cabbiev2.220x176x16.wps b/wps/cabbiev2.220x176x16.wps
index 62e44aa713..3963aa364a 100644
--- a/wps/cabbiev2.220x176x16.wps
+++ b/wps/cabbiev2.220x176x16.wps
@@ -58,18 +58,18 @@
#
# Track Info - Album Art
%ax%Vl(a,105,30,-,90,-)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%Sx(Next Track:)
%s%al%?It<%It|%Fn>
#
# Track Info - No Album Art
%Vl(b,0,30,-,90,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%Sx(Next Track:)
%s%ac%?It<%It|%Fn>
diff --git a/wps/cabbiev2.240x320x16.mini2440.wps b/wps/cabbiev2.240x320x16.mini2440.wps
index 3f78b95a11..14d65325d2 100644
--- a/wps/cabbiev2.240x320x16.mini2440.wps
+++ b/wps/cabbiev2.240x320x16.mini2440.wps
@@ -18,17 +18,17 @@
%Cl(55,30,130,130,c,c)
%pb(22,254,199,13,pb-240x320x16.bmp)
%?C<|>
+%?C<|%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>>
%?C<|%s%ac%?it<%it|%fn>>
%?C<|%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>>
-%?C<|%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>>
%?C<|%ac%?iy<%iy|>>
%?C<|>
%?C<|%ac%?ig<%ig|>>
%?C<|%ac%?fv<%(vbr%) |>%fb kbit/s %fc>
%?C<|>
+%?C<%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>|%ac%s%?It<%It|%Fn>>
%?C<%s%ac%?it<%it|%fn>|>
%?C<%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>|%ac%Sx(Next Track:)>>
-%?C<%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>|%ac%s%?It<%It|%Fn>>
%?C<|%s%ac%?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>>>
%?C<%s%ac%Sx(Next:) %?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>> - %?It<%It|%Fn>|%s%ac%?Id<%Id|%?D(1)<%D(1)|%(root%)>>>
diff --git a/wps/cabbiev2.240x320x16.wps b/wps/cabbiev2.240x320x16.wps
index 9f35bc5d60..95a056b123 100644
--- a/wps/cabbiev2.240x320x16.wps
+++ b/wps/cabbiev2.240x320x16.wps
@@ -52,30 +52,28 @@
%al%pc%ac%?Sr<%pe %Sx(of) %pp|%pp %Sx(of) %pe>%ar%pr
#
# Album Art
-%ax%Vl(a,55,30,130,130,-)
-%Cl(0,0,130,130,c,c)
+%ax%Vl(a,47,30,140,140,-)
+%Cl(0,0,140,140,c,c)
%Cd
#
# Track Info - Album Art
-%ax%Vl(a,0,165,-,78,1)
+%ax%Vl(a,0,175,-,72,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
-
%s%ac%Sx(Next:) %?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>> - %?It<%It|%Fn>
#
# Track Info - No Album Art
%Vl(b,0,45,-,198,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%?iy<%iy|>
%ac%?ig<%ig|>
%ac%?fv<%(vbr%) |>%fb kbit/s %fc
-
-%ac%Sx(Next Track:)
+%ac%Sx(Next:)
+%s%ac%?Id<%Id|%?D(1)<%D(1)|%(root%)>>
%ac%s%?It<%It|%Fn>
%s%ac%?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>>
-%s%ac%?Id<%Id|%?D(1)<%D(1)|%(root%)>>
diff --git a/wps/cabbiev2.240x400x16.wps b/wps/cabbiev2.240x400x16.wps
index beffd4a8e0..7bed444259 100644
--- a/wps/cabbiev2.240x400x16.wps
+++ b/wps/cabbiev2.240x400x16.wps
@@ -13,17 +13,17 @@
%?C<|>
%?C<|>
+%?C<|%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>>
%?C<|%s%ac%?it<%it|%fn>>
%?C<|%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>>
-%?C<|%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>>
%?C<|%ac%?iy<%iy|>>
%?C<|>
%?C<|%ac%?ig<%ig|>>
%?C<|%ac%?fv<%(vbr%) |>%fb kbit/s %fc>
%?C<|>
+%?C<%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>|%ac%s%?It<%It|%Fn>>
%?C<%s%ac%?it<%it|%fn>|>
%?C<%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>|%ac%Sx(Next Track:)>
-%?C<%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>|%ac%s%?It<%It|%Fn>>
%?C<|%s%ac%?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>>>
%?C<%s%ac%Sx(Next:) %?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>> - %?It<%It|%Fn>|%s%ac%?Id<%Id|%?D(1)<%D(1)|%(root%)>>>
diff --git a/wps/cabbiev2.320x240x16.mrobe500.wps b/wps/cabbiev2.320x240x16.mrobe500.wps
index 58ba2e5bad..d7bd9f2190 100644
--- a/wps/cabbiev2.320x240x16.mrobe500.wps
+++ b/wps/cabbiev2.320x240x16.mrobe500.wps
@@ -40,9 +40,9 @@
%s%al%?Ia<%Ia|%IA>
%Vl(b,0,30,-,130,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%iy
%ac%Sx(Next Track:)
diff --git a/wps/cabbiev2.320x240x16.wps b/wps/cabbiev2.320x240x16.wps
index fb0e4f5303..0aff77db77 100644
--- a/wps/cabbiev2.320x240x16.wps
+++ b/wps/cabbiev2.320x240x16.wps
@@ -58,9 +58,9 @@
#
# Track Info - Album Art
%ax%Vl(a,153,30,-,130,1)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?iy<%iy>
%s%al%Sx(Next Track:)
@@ -69,9 +69,9 @@
#
# Track Info - No Album Art
%ax%Vl(b,0,30,-,130,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?iy<%iy>
%ac%Sx(Next Track:)
diff --git a/wps/cabbiev2.320x480x16.wps b/wps/cabbiev2.320x480x16.wps
index 88c9404f48..77effcef4a 100644
--- a/wps/cabbiev2.320x480x16.wps
+++ b/wps/cabbiev2.320x480x16.wps
@@ -27,9 +27,9 @@
%Vl(a,0,60,-,110,-)
# tap on current title info for playlist (ie. where albumart would normally be)
%T(70,0,180,180,playlist)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%?iy<%iy|>
%Vl(b,0,200,-,140,-)
%ac%?ig<%ig|>
@@ -47,9 +47,9 @@
# current track info - AA
%Vl(d,0,240,-,-120,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
# next track info - AA
%Vl(d,0,338,-,-120,-)
diff --git a/wps/cabbiev2.360x400x16.wps b/wps/cabbiev2.360x400x16.wps
index 163d749e50..e98232e5df 100644
--- a/wps/cabbiev2.360x400x16.wps
+++ b/wps/cabbiev2.360x400x16.wps
@@ -58,24 +58,24 @@
#
# Track Info - Album Art
%ax%Vl(a,0,206,-,98,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%Sx(Next:) %?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>> - %?It<%It|%Fn>
#
# Track Info - No Album Art
%Vl(b,0,56,-,247,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%?iy<%iy|>
%ac%?ig<%ig|>
%ac%?fv<%(vbr%) |>%fb kbit/s %fc
-%ac%Sx(Next Track:)
+%ac%Sx(Next:)
+%s%ac%?Id<%Id|%?D(1)<%D(1)|%(root%)>>
%ac%s%?It<%It|%Fn>
%s%ac%?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>>
-%s%ac%?Id<%Id|%?D(1)<%D(1)|%(root%)>>
diff --git a/wps/cabbiev2.400x240x16.wps b/wps/cabbiev2.400x240x16.wps
index 3adb12ff04..469ee3d2f1 100644
--- a/wps/cabbiev2.400x240x16.wps
+++ b/wps/cabbiev2.400x240x16.wps
@@ -58,9 +58,9 @@
#
# Track Info - Album Art
%ax%Vl(a,153,32,-,122,1)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?iy<%iy>
%s%al%Sx(Next Track:)
@@ -69,9 +69,9 @@
#
# Track Info - No Album Art
%ax%Vl(b,0,32,-,122,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?iy<%iy>
%ac%Sx(Next Track:)
diff --git a/wps/cabbiev2.480x800x16.wps b/wps/cabbiev2.480x800x16.wps
index 05f24bc293..1b4994eba4 100644
--- a/wps/cabbiev2.480x800x16.wps
+++ b/wps/cabbiev2.480x800x16.wps
@@ -28,9 +28,9 @@
# tap on current title info for playlist (ie. where albumart would normally be)
%T(0,0,275,275,playlist)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%?iy<%iy|>
%Vl(b,0,400,-,180,-)
%ac%?ig<%ig|>
@@ -48,9 +48,9 @@
# current track info - AA
%Vl(d,0,370,-,-200,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
# next track info - AA
%Vl(d,0,550,-,-200,-)
diff --git a/wps/cabbiev2.800x480x16.wps b/wps/cabbiev2.800x480x16.wps
index 2994ab4498..525f45e6a9 100644
--- a/wps/cabbiev2.800x480x16.wps
+++ b/wps/cabbiev2.800x480x16.wps
@@ -17,9 +17,9 @@
# tap on current title info for playlist (ie. where albumart would normally be)
%T(0,0,225,225,playlist)
%Vl(b,0,79,-,225,-)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%ac%Sx(Next Track:)
%s%ac%?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>> - %?It<%It|%Fn>
@@ -34,9 +34,9 @@
# track & next track info - AA
%Vl(d,309,83,-,211,-)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%Sx(Next Track:)
%s%al%?Ia<%Ia|%?IA<%IA|%?D(2)<%D(2)|%(root%)>>> - %?It<%It|%Fn>
diff --git a/wps/cabbiev2.96x96x16.wps b/wps/cabbiev2.96x96x16.wps
index 327a5aad1c..102e5460b2 100644
--- a/wps/cabbiev2.96x96x16.wps
+++ b/wps/cabbiev2.96x96x16.wps
@@ -57,16 +57,16 @@
#
# Track Info - Album Art
%ax%Vl(a,51,12,-,34,1)
+%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?it<%it|%fn>
%s%al%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%al%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%al%?iy<%iy>
#
# Track Info - No Album Art
%Vl(b,0,12,-,34,1)
+%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?it<%it|%fn>
%s%ac%?ia<%ia|%?iA<%iA|%?d(2)<%d(2)|%(root%)>>>
-%s%ac%?id<%id|%?d(1)<%d(1)|%(root%)>>
%s%ac%?iy<%iy>
#
# Album Art