summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-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.h8
-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
26 files changed, 1022 insertions, 1267 deletions
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..5cb89ed15a 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 */
@@ -1178,6 +1181,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);