+
+/**************** Kblock interface ****************/
+
+
+static size_t mt29f_writeDirect(struct KBlock *kblk, block_idx_t idx, const void *buf, size_t offset, size_t size)
+{
+ ASSERT(offset <= MT29F_BLOCK_SIZE);
+ ASSERT(offset % MT29F_DATA_SIZE == 0);
+ ASSERT(size <= MT29F_BLOCK_SIZE);
+ ASSERT(size % MT29F_DATA_SIZE == 0);
+
+ LOG_INFO("mt29f_writeDirect: blk=%ld\n", idx);
+
+ mt29f_blockErase(MT29F_CAST(kblk), idx);
+
+ while (offset < size)
+ {
+ uint32_t page = PAGE(idx) + (offset / MT29F_DATA_SIZE);
+
+ if (!mt29f_write(MT29F_CAST(kblk), page, buf, MT29F_DATA_SIZE))
+ break;
+
+ offset += MT29F_DATA_SIZE;
+ buf = (const char *)buf + MT29F_DATA_SIZE;
+ }
+
+ return offset;
+}
+
+
+static size_t mt29f_readDirect(struct KBlock *kblk, block_idx_t idx, void *buf, size_t offset, size_t size)
+{
+ ASSERT(offset <= MT29F_BLOCK_SIZE);
+ ASSERT(offset % MT29F_DATA_SIZE == 0);
+ ASSERT(size <= MT29F_BLOCK_SIZE);
+ ASSERT(size % MT29F_DATA_SIZE == 0);
+
+ LOG_INFO("mt29f_readDirect: blk=%ld\n", idx);
+
+ while (offset < size)
+ {
+ uint32_t page = PAGE(idx) + (offset / MT29F_DATA_SIZE);
+
+ if (!mt29f_read(MT29F_CAST(kblk), page, buf, MT29F_DATA_SIZE))
+ break;
+
+ offset += MT29F_DATA_SIZE;
+ buf = (char *)buf + MT29F_DATA_SIZE;
+ }
+
+ return offset;
+}
+
+
+static int mt29f_error(struct KBlock *kblk)
+{
+ Mt29f *chip = MT29F_CAST(kblk);
+ return chip->status;
+}
+
+
+static void mt29f_clearError(struct KBlock *kblk)
+{
+ Mt29f *chip = MT29F_CAST(kblk);
+ chip->status = 0;
+}
+
+
+static const KBlockVTable mt29f_buffered_vt =
+{
+ .readDirect = mt29f_readDirect,
+ .writeDirect = mt29f_writeDirect,
+
+ .readBuf = kblock_swReadBuf,
+ .writeBuf = kblock_swWriteBuf,
+ .load = kblock_swLoad,
+ .store = kblock_swStore,
+
+ .error = mt29f_error,
+ .clearerr = mt29f_clearError,
+};
+
+static const KBlockVTable mt29f_unbuffered_vt =
+{
+ .readDirect = mt29f_readDirect,
+ .writeDirect = mt29f_writeDirect,
+
+ .error = mt29f_error,
+ .clearerr = mt29f_clearError,
+};
+
+
+bool mt29f_init(Mt29f *chip, struct Heap *heap, unsigned chip_select)
+{
+ if (!commonInit(chip, heap, chip_select))
+ return false;
+
+ chip->fd.priv.vt = &mt29f_buffered_vt;
+ chip->fd.priv.flags |= KB_BUFFERED;
+
+ chip->fd.priv.buf = heap_allocmem(heap, MT29F_BLOCK_SIZE);
+ if (!chip->fd.priv.buf)
+ {
+ LOG_ERR("mt29f: error allocating block buffer\n");
+ return false;
+ }
+
+ // Load the first block in the cache
+ return mt29f_readDirect(&chip->fd, 0, chip->fd.priv.buf, 0, MT29F_DATA_SIZE);
+}
+
+
+bool mt29f_initUnbuffered(Mt29f *chip, struct Heap *heap, unsigned chip_select)
+{
+ chip->fd.priv.vt = &mt29f_unbuffered_vt;
+ return commonInit(chip, heap, chip_select);
+}
+
+