summaryrefslogtreecommitdiffstats
path: root/libdpf
diff options
context:
space:
mode:
authorJames <git@panaceas.org>2014-05-05 17:50:20 +0100
committerJames <git@panaceas.org>2014-05-05 17:50:20 +0100
commit470457e22a1b5537013603d5e367c51e47bb61bf (patch)
tree6b72d32bfd9eaec31c8c520d18782ccaebc01759 /libdpf
downloadkmd_usb-470457e22a1b5537013603d5e367c51e47bb61bf.tar.gz
kmd_usb-470457e22a1b5537013603d5e367c51e47bb61bf.tar.bz2
kmd_usb-470457e22a1b5537013603d5e367c51e47bb61bf.zip
fish
Diffstat (limited to 'libdpf')
-rw-r--r--libdpf/Makefile12
-rw-r--r--libdpf/bootload.c379
-rw-r--r--libdpf/dpf.h189
-rw-r--r--libdpf/dpflib.c436
-rw-r--r--libdpf/flash.h19
-rw-r--r--libdpf/fwload.c121
-rw-r--r--libdpf/rawusb.c195
-rw-r--r--libdpf/scsi.c412
-rw-r--r--libdpf/sglib.h19
-rw-r--r--libdpf/spiflash.h30
-rw-r--r--libdpf/usbuser.h29
11 files changed, 1841 insertions, 0 deletions
diff --git a/libdpf/Makefile b/libdpf/Makefile
new file mode 100644
index 0000000..3c39ac5
--- /dev/null
+++ b/libdpf/Makefile
@@ -0,0 +1,12 @@
+OBJS = dpflib.o rawusb.o scsi.o bootload.o
+
+CFLAGS = -Wall -fPIC -I. -g
+# CFLAGS += -DDEBUG
+
+all: libdpf.a
+
+libdpf.a: $(OBJS)
+ ar ruv $@ $(OBJS)
+
+clean:
+ -rm -f libdpf.a *.o
diff --git a/libdpf/bootload.c b/libdpf/bootload.c
new file mode 100644
index 0000000..2d882cf
--- /dev/null
+++ b/libdpf/bootload.c
@@ -0,0 +1,379 @@
+// Bootstream generator for Buildwin firmware loader
+//
+// (c) 2011, <hackfin@section5.ch>
+//
+//
+
+#include "dpf.h"
+#include "usbuser.h" // our user defined flash commands
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+// Jump offsets for USB command:
+#define JMP_LOAD 0x0dae
+#define JMP_SPILIB 0x11bf
+#define JMP_USER 0x1000
+
+#define PAGESIZE 256
+#define BUFSIZE (64 - 6)
+#define PKTSIZE (64 - 7)
+
+typedef struct {
+ unsigned char len;
+ unsigned char chk;
+ unsigned char jmp[2];
+ union {
+ // Structures for various backends
+ // The default memory loader:
+ struct {
+ unsigned char offset[2]; // XDATA memory dest address
+ unsigned char buf[BUFSIZE]; // Binary data to write
+ } loader;
+ struct {
+ unsigned char opcode; // SPI operation opcode
+ unsigned char wnum; // Number of bytes to send (Host -> DPF)
+ unsigned char rnum; // Number of bytes to recv (DPF -> Host)
+ unsigned char seq[PKTSIZE]; // SPI cmd sequence
+ } spi;
+ } u;
+} UsbMsg;
+
+#define OPCODE_SPISEL 0x01 // assert SELECT
+#define OPCODE_CRYPT0 0x02
+#define OPCODE_CRYPT1 0x04
+#define OPCODE_SPIDES 0x10 // assert DESELECT
+
+int validate(UsbMsg *msg)
+{
+ unsigned short c = 0;
+ unsigned char *b = (unsigned char *) msg;
+ unsigned short l = msg->len;
+
+ if (l < 6 || l > 64) return -1;
+
+ while (l--) {
+ c += *b++;
+ }
+
+ msg->chk -= c;
+
+ return 0;
+}
+
+void hexdump(unsigned char *buf, unsigned long n)
+{
+ int i = 0;
+ int c = 0;
+
+ while (i < n) {
+ printf("%02x ", buf[i]);
+ c++;
+ if (c == 16) { c = 0; printf("\n"); }
+ i++;
+ }
+ if (c)
+ printf("\n");
+}
+
+int transmit(DPFContext *dpf, UsbMsg *m)
+{
+ int error;
+ unsigned char *s = (unsigned char *) m;
+ // hexdump(s, m->len);
+ error = usb_rawwrite(dpf->dev.udev, s, m->len);
+ if (error < 0) {
+ perror("Writing to USB");
+ }
+ return error;
+}
+
+int spilib_process(DPFContext *h, UsbMsg *umsg, unsigned char *out)
+{
+ int error;
+ umsg->jmp[0] = JMP_SPILIB & 0xff; umsg->jmp[1] = JMP_SPILIB >> 8;
+ umsg->len = 7 + umsg->u.spi.wnum;
+
+ validate(umsg);
+ error = transmit(h, umsg);
+ if (umsg->u.spi.rnum > 0 && error >= 0) {
+ error = usb_rawread(h->dev.udev, out, 64);
+ }
+ if (error < 0) perror("Reading USB");
+ else error = 0;
+ return error;
+}
+
+int go_hid(DPFContext *dpf, ADDR jmpoffset)
+{
+ UsbMsg umsg;
+ umsg.jmp[0] = jmpoffset; umsg.jmp[1] = jmpoffset >> 8;
+ umsg.len = 8;
+ validate(&umsg);
+ return transmit(dpf, &umsg);
+}
+
+int load(DPFContext *dpf, FILE *f, uint16_t jmpoffset)
+{
+ int size;
+ UsbMsg umsg;
+
+ unsigned short offset = jmpoffset - 0x800;
+
+ umsg.jmp[0] = JMP_LOAD & 0xff; umsg.jmp[1] = JMP_LOAD >> 8;
+ umsg.chk = 0xce;
+ size = fread(umsg.u.loader.buf, 1, BUFSIZE, f);
+ if (size < 0) return size;
+
+ while (size > 0) {
+ umsg.u.loader.offset[0] = offset;
+ umsg.u.loader.offset[1] = offset >> 8;
+ umsg.len = sizeof(UsbMsg) - BUFSIZE + size;
+ offset += size;
+ validate(&umsg);
+ transmit(dpf, &umsg);
+ size = fread(umsg.u.loader.buf, 1, BUFSIZE, f);
+ }
+
+ // And jump into the code:
+ if (jmpoffset != 0x0000) {
+ go_hid(dpf, jmpoffset);
+ }
+ return size;
+}
+/* Flash stuff, HID wrapped */
+
+static unsigned char s_rbuf[64];
+
+static
+int flash_probe_hid(DPFContext *h, unsigned char *id)
+{
+ int error;
+ UsbMsg umsg;
+ FILE *f;
+
+ // First, load spilib.bin
+ f = fopen("spilib.bin", "rb");
+
+ if (!f) {
+ printf("failed to open flash driver\n");
+ return -1;
+ }
+ umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES;
+
+ error = load(h, f, 0x0000); // Load, but do not execute
+ fclose(f);
+ usleep(500000);
+ if (error == 0) {
+ umsg.u.spi.wnum = 1;
+ umsg.u.spi.rnum = 4;
+ umsg.u.spi.seq[0] = SPM_RDID;
+ error = spilib_process(h, &umsg, s_rbuf);
+ id[0] = s_rbuf[0]; id[1] = s_rbuf[1]; id[2] = s_rbuf[2];
+ }
+ return error;
+}
+
+static
+int flash_cmd_hid(DPFContext *h, int command, int cmdlen, ADDR addr)
+{
+ UsbMsg umsg;
+ umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES;
+ umsg.u.spi.wnum = cmdlen;
+ umsg.u.spi.rnum = 0;
+ umsg.u.spi.seq[0] = command;
+ umsg.u.spi.seq[1] = addr >> 16;
+ umsg.u.spi.seq[2] = addr >> 8;
+ umsg.u.spi.seq[3] = addr;
+
+ return spilib_process(h, &umsg, 0);
+}
+
+int flash_status_hid(DPFHANDLE h, uint8_t *status)
+{
+ int error;
+ UsbMsg umsg;
+ umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES;
+ umsg.u.spi.wnum = 1;
+ umsg.u.spi.rnum = 1;
+ umsg.u.spi.seq[0] = SPM_RDSR;
+
+ error = spilib_process(h, &umsg, s_rbuf);
+ *status = s_rbuf[0];
+ return error;
+}
+
+static
+int chunk_read(DPFContext *h, unsigned char *buf, ADDR offset, int len)
+{
+ int error;
+ UsbMsg umsg;
+
+ if (len > PKTSIZE) len = PKTSIZE;
+
+ umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES;
+ umsg.u.spi.wnum = 4;
+ umsg.u.spi.rnum = PKTSIZE;
+ umsg.u.spi.seq[0] = SPM_READ;
+ umsg.u.spi.seq[1] = offset >> 16;
+ umsg.u.spi.seq[2] = offset >> 8;
+ umsg.u.spi.seq[3] = offset;
+
+ error = spilib_process(h, &umsg, buf);
+ if (error < 0) return error;
+
+ return len;
+}
+
+
+static
+int flash_read_hid(DPFContext *h, unsigned char *buf, ADDR offset, int len)
+{
+ int n;
+
+ while (len > 0) {
+ n = chunk_read(h, buf, offset, len);
+ if (n < 0) return n;
+ len -= n; offset += n; buf += n;
+ }
+ return 0;
+}
+
+int fill_spimsg(UsbMsg *umsg, const unsigned char *buf,
+ unsigned short offset, int len)
+{
+ int n = PKTSIZE - offset;
+ if (len > n) len = n;
+ memcpy(&umsg->u.spi.seq[offset], buf, len);
+ umsg->u.spi.wnum = offset + len;
+ return len;
+}
+
+static
+int flash_writechunk_hid(DPFContext *h,
+ const unsigned char *buf, ADDR offset, int len)
+{
+ UsbMsg umsg;
+ int error;
+ int n;
+
+ if (len > PAGESIZE) len = PAGESIZE;
+
+ umsg.u.spi.rnum = 0;
+ umsg.u.spi.seq[0] = SPM_PP;
+ umsg.u.spi.seq[1] = offset >> 16;
+ umsg.u.spi.seq[2] = offset >> 8;
+ umsg.u.spi.seq[3] = offset;
+
+ n = fill_spimsg(&umsg, buf, 4, len);
+ len -= n; buf += n; offset += n;
+
+ umsg.u.spi.opcode = OPCODE_SPISEL;
+ error = spilib_process(h, &umsg, 0);
+ if (error < 0) return error;
+
+ umsg.u.spi.opcode = 0;
+ while (len > PKTSIZE) {
+ n = fill_spimsg(&umsg, buf, 0, PKTSIZE);
+ error = spilib_process(h, &umsg, 0);
+ if (error < 0) return error;
+ len -= n; buf += n; offset += n;
+ }
+
+ umsg.u.spi.opcode = OPCODE_SPIDES;
+ fill_spimsg(&umsg, buf, 0, len);
+ error = spilib_process(h, &umsg, 0);
+ if (error < 0) return error;
+
+ return PAGESIZE;
+}
+
+int blk_write(DPFContext *h, ADDR dst, const unsigned char *src,
+ unsigned short len)
+{
+ static UsbMsg umsg;
+
+ if (len > BUFSIZE) len = BUFSIZE;
+
+ umsg.jmp[0] = JMP_LOAD & 0xff; umsg.jmp[1] = JMP_LOAD >> 8;
+ memcpy(umsg.u.loader.buf, src, len);
+ umsg.u.loader.offset[0] = dst;
+ umsg.u.loader.offset[1] = dst >> 8;
+ umsg.len = sizeof(UsbMsg) - BUFSIZE + len;
+
+ validate(&umsg);
+ transmit(h, &umsg);
+ return len;
+}
+
+int mem_write_hid(DPFContext *h,
+ ADDR dst, const unsigned char *src, unsigned short n)
+{
+ int len;
+
+ while (n > 0) {
+ len = blk_write(h, dst, src, n);
+ n -= len; src += len; dst += len;
+ }
+ return n;
+}
+
+
+AccessMethods
+hid_methods = {
+ .mem_read = NULL,
+ .mem_write = mem_write_hid,
+ .go = go_hid,
+ .bootstrap = NULL,
+ .flash_probe = flash_probe_hid,
+ .flash_cmd = flash_cmd_hid,
+ .flash_status = flash_status_hid,
+ .flash_read = flash_read_hid,
+ .flash_writechunk = flash_writechunk_hid,
+ .flash_lock = NULL,
+};
+
+
+#ifdef TEST
+int main(int argc, char **argv)
+{
+ FILE *f;
+ int error;
+ DPFHANDLE dpf;
+ uint16_t startaddr = 0x1000;
+
+ if (argc >= 2) {
+
+ f = fopen(argv[1], "rb");
+
+ if (!f) {
+ printf("failed to open file\n");
+ return -1;
+ }
+ if (argc == 3) {
+ startaddr = strtol(argv[2], NULL, 16);
+ printf("Starting at %04x\n", startaddr);
+ }
+
+ error = dpf_open("usb0", &dpf);
+ if (error < 0) {
+ printf("Failed to open DPF\n");
+ return error;
+ }
+ if (dpf->mode == MODE_USBHID) {
+ error = load(dpf, f, startaddr);
+ } else {
+ printf("Not in BOOTLOAD mode! Press Reset and hold MENU\n");
+ }
+ dpf_close(dpf);
+ } else {
+ printf("Needs boot image argument\n");
+ }
+
+ if (error < 0) {
+ printf("Error\n");
+ }
+ return error;
+}
+#endif
diff --git a/libdpf/dpf.h b/libdpf/dpf.h
new file mode 100644
index 0000000..d8d698d
--- /dev/null
+++ b/libdpf/dpf.h
@@ -0,0 +1,189 @@
+/** libdpf header file
+ *
+ * (c) 2010, 2011 <hackfin@section5.ch>
+ *
+ */
+
+#include <stdint.h>
+#include <usb.h>
+#include "usbuser.h"
+#include "spiflash.h"
+
+#define ADDR unsigned int
+
+#define MODE_SG 0x00 ///< generic device mode (original)
+#define MODE_USB 0x01 ///< libusb operation mode (hacked)
+#define MODE_USBHID 0x02 ///< libusb HID boot mode
+
+#define FLAG_CAN_LOCK 0x80 ///< Has the locking feature (new firmware)
+
+enum {
+ DEVERR_FILE = -16,
+ DEVERR_OPEN,
+ DEVERR_HEX,
+ DEVERR_CHK,
+ DEVERR_IO,
+ DEVERR_MALLOC,
+ DEVERR_TIMEOUT,
+ DEVERR_UNSUPP,
+};
+
+/** The DPF context structure */
+struct dpf_context;
+#define DPFHANDLE struct dpf_context *
+
+typedef struct {
+ int (*mem_read)(DPFHANDLE h, unsigned char *buf, ADDR offset, int len);
+ int (*mem_write)(DPFHANDLE h,
+ ADDR dst, const unsigned char *buf, unsigned short n);
+ int (*go)(DPFHANDLE h, ADDR start);
+ int (*bootstrap)(DPFHANDLE h,
+ ADDR dest, unsigned char *src, unsigned short n, ADDR start);
+ int (*flash_probe)(DPFHANDLE h, unsigned char *id);
+ int (*flash_cmd)(DPFHANDLE h, int command, int cmdlen, ADDR addr);
+ int (*flash_status)(DPFHANDLE h, uint8_t *status);
+ int (*flash_read)(DPFHANDLE h, uint8_t *buf, ADDR offset, int len);
+ int (*flash_writechunk)(DPFHANDLE h,
+ const uint8_t *buf, ADDR offset, int len);
+ int (*flash_lock)(DPFHANDLE h, char enable);
+} AccessMethods;
+
+typedef
+struct dpf_context {
+ unsigned char mode;
+ unsigned char flags;
+ union {
+ usb_dev_handle *udev;
+ int fd;
+ } dev;
+ AccessMethods methods;
+ unsigned int width;
+ unsigned int height;
+ int bpp;
+ int proto;
+ char* buff;
+ unsigned char* oldpix;
+ int offx;
+ int offy;
+} DPFContext;
+
+
+/** A value proxy for the property API */
+typedef struct dpf_proxy {
+ union {
+ short integer;
+ char *sequence;
+ } value;
+ char type;
+} DPFValue;
+
+enum {
+ TYPE_INTEGER,
+ TYPE_STRING,
+};
+
+/**
+ Opens the DPF device. if dev is not NULL, open device, otherwise, look for
+ USB device.
+ */
+int dpf_open(const char *dev, DPFHANDLE *h);
+
+/** Close DPF device */
+void dpf_close(DPFHANDLE h);
+
+/** Set color register
+ * \param rgb RGB tuple */
+int dpf_setcol(DPFHANDLE h, const unsigned char *rgb);
+
+/** Blit data to screen
+ *
+ * \param buf buffer to 16 bpp RGB 565 image data
+ * \param rect rectangle tuple: [x0, y0, x1, y1]
+ */
+
+int dpf_screen_blit(DPFHANDLE h, const unsigned char *buf, short rect[4]);
+
+/** Set property on DPF
+ * \param token Property token
+ * \param value Pointer to value
+ */
+int dpf_setproperty(DPFHANDLE h, int token, const DPFValue *value);
+
+/* USB raw */
+
+int emulate_scsi(usb_dev_handle *d, unsigned char *cmd, int cmdlen, char out,
+ unsigned char *data, unsigned long block_len);
+
+const char *dev_errstr(int err);
+
+// Private stuff:
+int dpf_usb_open(int index, usb_dev_handle **u);
+int sgdev_open(const char *portname, int *fd);
+int usb_rawread(usb_dev_handle *dev, unsigned char *buf, int len);
+int usb_rawwrite(usb_dev_handle *dev, const unsigned char *buf, int len);
+int probe(DPFHANDLE h);
+
+////////////////////////////////////////////////////////////////////////////
+// Bootloader functionality
+
+int bl_go(DPFContext *dpf, uint16_t jmpoffset);
+
+////////////////////////////////////////////////////////////////////////////
+// FLASH stuff
+
+// Maximum size for flash_read
+#define MAX_CHUNKSIZE 0x10000
+
+int read_mem(DPFHANDLE h, unsigned char *buf, ADDR src, unsigned short len);
+int write_mem(DPFHANDLE h,
+ ADDR dst, const unsigned char *buf, unsigned short len);
+
+int load_hexfile(DPFHANDLE h, const char *hexfile);
+int code_go(DPFHANDLE h, ADDR start);
+
+int dpf_bootstrap(DPFHANDLE h,
+ ADDR dst, unsigned char *src, unsigned short n, ADDR start);
+
+int flash_cmd(DPFHANDLE h, int command, int cmdlen, ADDR addr);
+int flash_probe(DPFContext *h, unsigned char *id);
+int flash_erase(DPFHANDLE h, ADDR offset);
+int flash_erase_full(DPFHANDLE h);
+int flash_write(DPFHANDLE h, const unsigned char *buf, ADDR offset, int len);
+int flash_read(DPFHANDLE h, unsigned char *buf, ADDR offset, int len);
+
+int load_ihx(DPFHANDLE h, const char *fname, unsigned char *data,
+ unsigned int *buflen, unsigned int reloc);
+
+int patch_sector(DPFHANDLE h,
+ ADDR reloc, unsigned long addr, const char *hexfile);
+
+////////////////////////////////////////////////////////////////////////////
+/* DPF specific stuff: */
+
+#define RGB565_0(r, g, b) \
+ (( ((r) & 0xf8) ) | (((g) & 0xe0) >> 5))
+#define RGB565_1(r, g, b) \
+ (( ((g) & 0x1c) << 3 ) | (((b) & 0xf8) >> 3))
+
+#define RGB565(r, g, b) { RGB565_0(r, g, b), RGB565_1(r, g, b) }
+
+#define RGB565_S(r, g, b) ((RGB565_0(r, g, b) << 8) | RGB565_1(r, g, b))
+
+int dpfcpy(ADDR dst, unsigned char *src, unsigned short n);
+
+// int clr_screen(DPFHANDLE h, const unsigned char *col);
+int write_screen(DPFHANDLE h, const unsigned char *buf, unsigned int len);
+
+
+// Some internal address offsets. They may change, but so far all types
+// seem to have the same
+//
+// w: word, <n>: length, [LE, BE]
+//
+// FIXME: Use packed struct later.
+
+// FIXME: Should be 0x0020, once we have the firmware replaced
+#define OFFSET_PROPS 0x3f0020 ///< w[2]:LE : Resolution X, Y
+
+
+
diff --git a/libdpf/dpflib.c b/libdpf/dpflib.c
new file mode 100644
index 0000000..cfda55b
--- /dev/null
+++ b/libdpf/dpflib.c
@@ -0,0 +1,436 @@
+/** DPF access library for AX206 based HW
+ *
+ * 12/2010 <hackfin@section5.ch>
+ *
+ * This is an ugly hack, because we use existing SCSI vendor specific
+ * extensions to pass on our requests to the DPF.
+ *
+ * One day we might use a proper protocol like netpp.
+ *
+ */
+
+// FIXME: Put all those SCSI commands in one (wrapped) place.
+
+#include "dpf.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#ifdef DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+extern AccessMethods scsi_methods;
+extern AccessMethods hid_methods;
+
+
+/*
+static
+int dpf_query(DPFHANDLE h)
+{
+ int ret;
+ unsigned char buf[64]; // Do not change size
+
+ static
+ unsigned char cmd[16] = {
+ 0xcd, 0, 0, 0,
+ 0, 3, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+ };
+
+ return wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, buf, sizeof(buf));
+}
+*/
+
+
+
+int dpf_open(const char *dev, DPFHANDLE *h)
+{
+ int error = 0;
+ DPFContext *dpf;
+ int i;
+ usb_dev_handle *u;
+
+ int fd;
+
+ if (!dev) {
+ fprintf(stderr, "Please specify a string like 'usb0' or a sg device\n");
+ return DEVERR_OPEN;
+ }
+
+ if (strncmp(dev, "usb", 3) == 0) {
+ i = dev[3] - '0';
+ error = dpf_usb_open(i, &u);
+ if (error < 0) return error;
+ if (!u) return DEVERR_OPEN;
+ i = error; // USB mode
+ error = 0;
+ } else {
+ fprintf(stderr, "Opening generic SCSI device '%s'\n", dev);
+ if (sgdev_open(dev, &fd) < 0) return DEVERR_OPEN;
+ i = MODE_SG;
+ }
+
+ dpf = (DPFHANDLE) malloc(sizeof(DPFContext));
+ if (!dpf) return DEVERR_MALLOC;
+
+ dpf->flags = 0;
+ dpf->mode = i;
+
+ switch (dpf->mode) {
+ case MODE_USB:
+ dpf->dev.udev = u;
+ error = probe(dpf);
+ fprintf(stderr, "Got LCD dimensions: %dx%d\n",
+ dpf->width, dpf->height);
+ dpf->methods = scsi_methods;
+ break;
+ case MODE_USBHID:
+ dpf->dev.udev = u;
+ dpf->methods = hid_methods;
+ break;
+ case MODE_SG:
+ dpf->dev.fd = fd;
+ dpf->methods = scsi_methods;
+ break;
+ default:
+ fprintf(stderr, "Unknown interface mode\n");
+ error = -1;
+ }
+
+ *h = dpf;
+ return error;
+}
+
+void dpf_close(DPFContext *h)
+{
+ switch (h->mode) {
+ case MODE_USBHID:
+ case MODE_SG:
+ close(h->dev.fd);
+ break;
+ case MODE_USB:
+ usb_release_interface(h->dev.udev, 0);
+ usb_close(h->dev.udev);
+ break;
+ }
+ free(h);
+}
+
+const char *dev_errstr(int err)
+{
+ switch (err) {
+ case DEVERR_FILE: return "File I/O error";
+ case DEVERR_OPEN: return "File open error";
+ case DEVERR_HEX: return "Hex file error";
+ case DEVERR_CHK: return "Checksum error";
+ case DEVERR_IO: return "Common I/O error";
+ case DEVERR_UNSUPP: return "Unsupported feature";
+ default: return "Unknown error";
+ }
+}
+
+
+int flash_probe(DPFContext *h, unsigned char *id)
+{
+ return h->methods.flash_probe(h, id);
+}
+
+int flash_cmd(DPFContext *h, int command, int cmdlen, ADDR addr)
+{
+ return h->methods.flash_cmd(h, command, cmdlen, addr);
+}
+
+
+/* Flash functions, API */
+
+int flash_read(DPFContext *h, unsigned char *buf, ADDR offset, int len)
+{
+ return h->methods.flash_read(h, buf, offset, len);
+}
+
+int flash_status_wait(DPFContext *h, uint8_t mask)
+{
+ int error;
+ uint8_t status;
+
+ do {
+ error = h->methods.flash_status(h, &status);
+ } while ((status & mask) && !error);
+
+ return error;
+}
+
+
+int flash_write(DPFContext *h, const unsigned char *buf, ADDR offset, int len)
+{
+ int n;
+ int error = 0;
+
+ while (len > 0) {
+ error = h->methods.flash_cmd(h, SPM_WREN, 1, 0);
+ DEB(printf("Write pages at %06x\n", offset));
+ n = h->methods.flash_writechunk(h, buf, offset, len);
+ error = flash_status_wait(h, SPS_WIP);
+
+ if (n < 0) break;
+ len -= n; buf += n; offset += n;
+ }
+ return error;
+}
+
+/* Mid level flash */
+
+int load_ihx(DPFContext *h, const char *fname, unsigned char *data,
+ unsigned int *buflen, unsigned int reloc)
+{
+ unsigned char csum_is, csum_need;
+ int ret;
+ FILE *f;
+
+ static char line[512];
+ static unsigned char buf[0x100];
+ int count;
+ unsigned int addr, len, type;
+ unsigned short b;
+ unsigned int total = 0;
+
+ DEB(printf("Opening %s...\n", fname));
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ return DEVERR_OPEN;
+ }
+
+ while(1) {
+ fgets(line, sizeof(line), f);
+
+ if (feof(f) || ferror(f)) break;
+
+ if ((line[0] != ':') || (strlen(line) < 9)) {
+ fprintf(stderr, "invalid line in ihx\n");
+ break;
+ }
+
+ ret = sscanf(&line[1], "%02x", &len);
+ if (ret != 1) { ret = DEVERR_HEX; break; }
+
+ ret = sscanf(&line[3], "%04x", &addr);
+ if (ret != 1) { ret = DEVERR_HEX; break; }
+
+ ret = sscanf(&line[7], "%02x", &type);
+ if (ret != 1) { ret = DEVERR_HEX; break; }
+
+#ifdef DEBUG
+ printf("len %u addr %04x type %u\n", len, addr, type);
+#endif
+
+ if (type == 1) break;
+
+ if (type != 0) {
+ fprintf(stderr, "ihx: unknown type %u\n", type);
+ continue;
+ }
+
+ csum_need = len + (addr & 0xff) + (addr >> 8) + type;
+
+ total += len;
+ if (total > *buflen) {
+ fprintf(stderr, "Buffer length exceeded. IHX file too big.\n");
+ ret = DEVERR_HEX;
+ break;
+ }
+
+ if (len > sizeof(buf)) {
+ fprintf(stderr, "Buffer length exceeded. Too long lines.\n");
+ ret = DEVERR_HEX;
+ break;
+ }
+
+ for(count = 0; count < len; count++) {
+ ret = sscanf(&line[9 + count * 2], "%02hx", &b);
+ if (ret != 1) {
+ fprintf(stderr, "hex file: could not parse data!\n");
+ break;
+ }
+
+ buf[count] = b;
+ csum_need += buf[count];
+ }
+
+ if (ret != 1) { ret = DEVERR_HEX; break; }
+
+ ret = sscanf(&line[9 + len * 2], "%02hx", &b);
+ if (ret != 1) { ret = DEVERR_HEX; break; }
+
+ csum_is = b;
+ if (((csum_need+csum_is) & 0xff) != 0x00) {
+ fprintf(stderr, "ihx: checksum failure! is: %02x should be:%02x\n",
+ csum_is, csum_need);
+ ret = DEVERR_CHK;
+ break;
+ }
+
+ if (addr < reloc) {
+ fprintf(stderr, "Bad relocation value\n");
+ ret = DEVERR_HEX;
+ break;
+ }
+ // Copy to data buffer at relocated address
+ if (data) {
+ DEB(printf("Patching at offset %08x, chunk size %d\n",
+ addr - reloc, len));
+ memcpy(&data[addr - reloc], buf, len);
+ } else {
+ DEB(printf("Writing to %04x (CODE: %04x), chunk size %d\n",
+ addr - reloc, addr, len));
+ h->methods.mem_write(h, addr - reloc, buf, len);
+ }
+ }
+ *buflen = total;
+ fclose(f);
+ return ret;
+}
+
+int flash_erase_full(DPFContext *h)
+{
+ flash_cmd(h, SPM_RES, 1, 0);
+ flash_cmd(h, SPM_WRSR, 2, 0); // clr status
+ flash_cmd(h, SPM_WREN, 1, 0);
+ flash_cmd(h, SPM_FLASH_BE, 1, 0);
+ printf("Erase full flash...\n");
+
+ return flash_status_wait(h, SPS_WIP);
+}
+
+int flash_erase(DPFContext *h, ADDR addr)
+{
+ int error;
+ flash_cmd(h, SPM_RES, 1, 0);
+ flash_cmd(h, SPM_WREN, 1, 0);
+ flash_cmd(h, SPM_WRSR, 2, 0); // clr status
+
+ // now erase flash sector:
+ flash_cmd(h, SPM_WREN, 1, 0);
+ flash_cmd(h, SPM_FLASH_SE, 4, addr);
+
+ error = flash_status_wait(h, SPS_WIP);
+ flash_cmd(h, SPM_WRDI, 1, 0);
+
+ return error;
+}
+
+int dpf_flash_lock(DPFContext *h, char enable)
+{
+ if (h->methods.flash_lock)
+ return h->methods.flash_lock(h, enable);
+ else
+ return DEVERR_UNSUPP;
+}
+
+
+int patch_sector(DPFContext *h,
+ ADDR reloc, unsigned long addr, const char *hexfile)
+{
+ int error;
+ unsigned short offset;
+ static
+ unsigned char readbuf[0x10000];
+ unsigned int len = sizeof(readbuf);
+
+ offset = addr & 0xffff;
+ addr -= offset;
+
+ error = flash_read(h, readbuf, addr, 0x10000);
+ if (error < 0) {
+ perror("Reading flash");
+ return error;
+ }
+
+ error = load_ihx(h, hexfile, &readbuf[offset], &len, reloc);
+ if (error < 0) {
+ fprintf(stderr, "Failed to load HEX file\n");
+ return error;
+ }
+ // Lock DPF handler so nothing can interfere with the flashing (in case
+ // we flash ourselves)
+ dpf_flash_lock(h, 1);
+ error = flash_cmd(h, SPM_WREN, 1, 0);
+ error = flash_cmd(h, SPM_WRSR, 2, 0); // clr status
+
+ error = flash_erase(h, addr);
+ if (error < 0) return error;
+
+ error = flash_write(h, readbuf, addr, 0x10000); // clr status
+ dpf_flash_lock(h, 0);
+
+ return error;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// High level functions, generic
+// These require a hacked command handler with extended command set.
+
+
+int load_hexfile(DPFContext *h, const char *hexfile)
+{
+ unsigned int len = 0xc000;
+ int error;
+
+ error = load_ihx(h, hexfile, 0, &len, 0x800);
+ return error;
+}
+
+#define CHUNK_SIZE 1024
+
+int read_mem(DPFContext *h, unsigned char *buf, ADDR src, unsigned short len)
+{
+ int error = 0;
+ if (!h->methods.mem_read) return DEVERR_UNSUPP;
+
+ while (len > CHUNK_SIZE && error >= 0) {
+ error = h->methods.mem_read(h, buf, src, CHUNK_SIZE);
+ src += CHUNK_SIZE; len -= CHUNK_SIZE; buf += CHUNK_SIZE;
+ }
+ error = h->methods.mem_read(h, buf, src, len);
+
+ return error;
+}
+
+int write_mem(DPFContext *h, ADDR dst, const unsigned char *buf, unsigned short len)
+{
+ return h->methods.mem_write(h, dst, buf, len);
+}
+
+int code_go(DPFContext *h, ADDR start)
+{
+ printf("Executing applet..\n");
+ if (h->methods.go)
+ return h->methods.go(h, start);
+ return DEVERR_UNSUPP;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////
+// High level functions, DPF specific
+
+/* Bootstrap mode: Expects contiguous memory block to download, then jumps
+ * into start address
+ */
+
+int dpf_bootstrap(DPFContext *h,
+ ADDR dest, unsigned char *src, unsigned short n, ADDR start)
+{
+ if (h->methods.bootstrap)
+ return h->methods.bootstrap(h, dest, src, n, start);
+ else
+ return DEVERR_UNSUPP;
+}
+
+
+
diff --git a/libdpf/flash.h b/libdpf/flash.h
new file mode 100644
index 0000000..f753bd5
--- /dev/null
+++ b/libdpf/flash.h
@@ -0,0 +1,19 @@
+// SPI STM flash commands:
+// stolen from BFloader
+
+#define SPM_RDID 0x9f // Read ID
+#define SPM_WREN 0x06 // Write enable
+#define SPM_WRDI 0x04 // Write disable
+#define SPM_RDSR 0x05 // Read status register
+#define SPM_WRSR 0x01 // Write status register
+#define SPM_READ 0x03 // Read data bytes
+#define SPM_PP 0x02 // Page program
+#define SPM_DP 0xb9 // Deep power down
+#define SPM_RES 0xab // Release from deep power down
+ // and read signature
+#define SPM_FLASH_SE 0xd8 // Sector erase
+#define SPM_FLASH_BE 0xc7 // Bulk erase
+#define SPM_FLASH_FAST_READ 0x0B // Read data bytes fast
+
+#define SPM_SR_SRWD 0x80 // SR write protection (HW)
+
diff --git a/libdpf/fwload.c b/libdpf/fwload.c
new file mode 100644
index 0000000..2b98762
--- /dev/null
+++ b/libdpf/fwload.c
@@ -0,0 +1,121 @@
+/** DPF firmware loader
+ *
+ * 12/2010 <hackfin@section5.ch>
+ *
+ * Based on the FX2 ihx loader
+ *
+ */
+
+#include "dpf.h"
+#include <stdio.h>
+
+////////////////////////////////////////////////////////////////////////////
+
+// Demo stuff:
+
+void memory_dump(unsigned char *buf, unsigned int n)
+{
+ int i = 0;
+ int c = 0;
+
+ while (i < n) {
+ printf("%02x ", buf[i]);
+ c++;
+ if (c == 16) { c = 0; printf("\n"); }
+ i++;
+ }
+ if (c)
+ printf("\n");
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+
+#if EXPERIMENTAL
+
+int xmain(int argc, char **argv)
+{
+ int ret;
+ int i;
+ struct banktable *bt;
+
+ // flash offset, offset after jump table
+ unsigned int offset = 0x80000 + 0x200;
+
+
+ static unsigned char buf[0x10000];
+ unsigned int len = sizeof(buf);
+ ret = load_ihx(argv[1], buf, &len, 0x127c, g_banktab);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to load HEX file\n");
+ return ret;
+ } else {
+ printf("Read %d banks\n", ret);
+ for (i = 0; i < ret; i++) {
+ bt = &g_banktab[i];
+ printf(" { XADDR(0x%04x), XADDR(0x%04x), FOFFS(0x%06x) },\n",
+ bt->reloc, bt->reloc + bt->len, offset + bt->offset);
+
+ }
+ }
+ return 0;
+}
+
+#endif
+
+int main(int argc, char **argv)
+{
+ int ret;
+ DPFHANDLE h;
+
+ int i = 2;
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "Usage:\n"
+ "%s <generic scsi dev> <.ihx file>\n"
+ "or in USB mode:\n"
+ "%s <.ihx file>\n",
+ argv[0], argv[0]);
+ return -1;
+ }
+
+ if (argc == 2) {
+ ret = dpf_open(NULL, &h);
+ i--;
+ } else
+ if (argc == 3) {
+ ret = dpf_open(argv[1], &h);
+ }
+
+ if (ret < 0) {
+ perror("opening DPF device:");
+ return ret;
+ }
+
+// This patches a module to init the relocated jump table on a certain
+// menu action:
+// ret = patch_sector(h, 0x1330, 0x4af7a, "hack2.ihx");
+
+
+// patch_sector(h, 0x0, 0x100000, "jumptbl.ihx");
+
+ if (0) {
+ patch_sector(h, 0x0, 0x100000, "jumptbl.ihx");
+ ret = patch_sector(h, 0x1330, 0x110000, "hack.ihx");
+ ret = patch_sector(h, 0x132a, 0x120000, "main.ihx");
+ if (ret < 0) printf("Failed.\n");
+ } else {
+ // demo0(h);
+
+ }
+ ret = load_hexfile(h, argv[i]);
+ code_go(h, 0x18a0);
+ if (ret < 0) printf("Failed.\n");
+
+ // unsigned char buf[256];
+ // ret = read_mem(h, buf, 0x18a0, 64);
+ // memory_dump(buf, 64);
+
+ dpf_close(h);
+ return ret;
+}
diff --git a/libdpf/rawusb.c b/libdpf/rawusb.c
new file mode 100644
index 0000000..cbd344c
--- /dev/null
+++ b/libdpf/rawusb.c
@@ -0,0 +1,195 @@
+/* Low level USB code to access DPF.
+ *
+ * (c) 2010, 2011 <hackfin@section5.ch>
+ *
+ * This currently uses the SCSI command set
+ *
+ * The reason for this is that we want to access the hacked frame
+ * non-root and without having to wait for the SCSI interface to
+ * intialize.
+ *
+ * Later, we'll replace the SCSI command stuff.
+ */
+
+#include "dpf.h"
+#include "sglib.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#define ENDPT_OUT 1
+#define ENDPT_IN 0x81
+
+struct known_device {
+ char *desc;
+ unsigned short vid;
+ unsigned short pid;
+} g_known_devices[] = {
+ { "AX206 DPF", 0x1908, 0x0102 },
+ { "AX206 DPF (bootloader)", 0x1908, 0x3318 },
+ { 0 , 0, 0 } /* NEVER REMOVE THIS */
+};
+
+int handle_error(char *txt)
+{
+ fprintf(stderr, "Error: %s\n", txt);
+ return -1;
+}
+
+void usb_flush(usb_dev_handle *dev)
+{
+ char buf[20];
+ usb_bulk_read(dev, ENDPT_IN, buf, 3, 1000);
+}
+
+int check_known_device(struct usb_device *d)
+{
+ struct known_device *dev = g_known_devices;
+
+ while (dev->desc) {
+ if ((d->descriptor.idVendor == dev->vid) &&
+ (d->descriptor.idProduct == dev->pid)) {
+ fprintf(stderr, "Found %s\n", dev->desc);
+ return 1;
+ }
+ dev++;
+ }
+ return 0;
+}
+
+static struct usb_device *find_dev(int index)
+{
+ struct usb_bus *b;
+ struct usb_device *d;
+ int enumeration = 0;
+
+ b = usb_get_busses();
+
+ while (b) {
+ d = b->devices;
+ while (d) {
+ if (check_known_device(d)) {
+ if (enumeration == index) return d;
+ else enumeration++;
+ }
+
+#ifdef DEBUG
+ printf("enum: %d index: %d\n", enumeration, index);
+ printf("%04x %04x\n",
+ d->descriptor.idVendor,
+ d->descriptor.idProduct);
+#endif
+ d = d->next;
+ }
+ b = b->next;
+ }
+ return NULL;
+}
+
+char g_buf[] = {
+ 0x55, 0x53, 0x42, 0x43, // dCBWSignature
+ 0xde, 0xad, 0xbe, 0xef, // dCBWTag
+ 0x00, 0x80, 0x00, 0x00, // dCBWLength
+ 0x00, // bmCBWFlags: 0x80: data in (dev to host), 0x00: Data out
+ 0x00, // bCBWLUN
+ 0x10, // bCBWCBLength
+
+ // SCSI cmd:
+ 0xcd, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x11, 0xf8,
+ 0x70, 0x00, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+};
+
+int emulate_scsi(usb_dev_handle *dev, unsigned char *cmd, int cmdlen, char out,
+ unsigned char *data, unsigned long block_len)
+{
+ int len;
+ int ret;
+ static unsigned char ansbuf[13]; // Do not change size.
+
+ g_buf[14] = cmdlen;
+ memcpy(&g_buf[15], cmd, cmdlen);
+
+ g_buf[8] = block_len;
+ g_buf[9] = block_len >> 8;
+ g_buf[10] = block_len >> 16;
+ g_buf[11] = block_len >> 24;
+
+ ret = usb_bulk_write(dev, ENDPT_OUT, g_buf, sizeof(g_buf), 1000);
+ if (ret < 0) return ret;
+
+ if (out == DIR_OUT) {
+ if (data) {
+ ret = usb_bulk_write(dev, ENDPT_OUT, (char* )data,
+ block_len, 3000);
+ if (ret != block_len) {
+ perror("bulk write");
+ return ret;
+ }
+ }
+ } else if (data) {
+ ret = usb_bulk_read(dev, ENDPT_IN, (char *) data, block_len, 4000);
+ if (ret != block_len) {
+ perror("bulk data read");
+ }
+ }
+ // get ACK:
+ len = sizeof(ansbuf);
+ int retry = 0;
+ do {
+ ret = usb_bulk_read(dev, ENDPT_IN, (char *) ansbuf, len, 5000);
+ if (ret != len) {
+ perror("bulk ACK read");
+ ret = DEVERR_TIMEOUT;
+ }
+ retry++;
+ } while (ret == DEVERR_TIMEOUT && retry < 5);
+ if (strncmp((char *) ansbuf, "USBS", 4)) {
+ return handle_error("Got invalid reply\n");
+ }
+ // pass back return code set by peer:
+ return ansbuf[12];
+}
+
+int dpf_usb_open(int index, usb_dev_handle **u)
+{
+ struct usb_device *d;
+ usb_dev_handle *usb_dev;
+
+ usb_find_busses();
+ usb_find_devices();
+
+ d = find_dev(index);
+ if (!d) {
+ handle_error("No matching USB device found!");
+ return -1;
+ }
+
+ usb_dev = usb_open(d);
+ if (usb_dev == NULL) {
+ handle_error("Failed to open usb device!");
+ return -1;
+ }
+ if (usb_claim_interface(usb_dev, 0) < 0) {
+ handle_error("Failed to claim usb device!");
+ printf("Possibly you have to 'sudo libhid-detach-device 1908:3318'\n");
+ return -1;
+ }
+ *u = usb_dev;
+
+ if (d->descriptor.idProduct == 0x3318)
+ return MODE_USBHID;
+ else
+ return MODE_USB;
+}
+
+int usb_rawwrite(usb_dev_handle *dev, const unsigned char *buf, int len)
+{
+ return usb_interrupt_write(dev, ENDPT_OUT, (char *) buf, len, 1000);
+}
+
+int usb_rawread(usb_dev_handle *dev, unsigned char *buf, int len)
+{
+ return usb_interrupt_read(dev, ENDPT_IN, (char *) buf, len, 4000);
+}
diff --git a/libdpf/scsi.c b/libdpf/scsi.c
new file mode 100644
index 0000000..3f82fc7
--- /dev/null
+++ b/libdpf/scsi.c
@@ -0,0 +1,412 @@
+/**
+ * (c) 2011, <hackfin@section5.ch>
+ *
+ */
+
+#include "sglib.h"
+#include "usbuser.h" // our user defined flash commands
+#include "dpf.h"
+
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+
+int do_scsi(int fd, unsigned char *cmd, int cmdlen, char out,
+ unsigned char *data, unsigned long block_len)
+{
+ int error;
+ unsigned char sensebuf[32];
+ sg_io_hdr_t io_hdr;
+ memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
+
+ io_hdr.interface_id = 'S';
+ io_hdr.sbp = sensebuf;
+ io_hdr.mx_sb_len = sizeof(sensebuf);
+ if (data == 0) {
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ } else {
+ if (out) {
+ io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
+ } else {
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ }
+ }
+ io_hdr.dxferp = data;
+ io_hdr.dxfer_len = block_len;
+ io_hdr.cmdp = cmd;
+ io_hdr.cmd_len = cmdlen;
+ io_hdr.timeout = 5000; // in ms
+ error = ioctl(fd, SG_IO, &io_hdr);
+ if (error < 0) perror("calling SCSI ioctl()");
+ return error;
+}
+
+
+int wrap_scsi(DPFContext *h, unsigned char *cmd, int cmdlen, char out,
+ unsigned char *data, unsigned long block_len)
+{
+ int error;
+ switch (h->mode) {
+ case MODE_USB:
+ error = emulate_scsi(h->dev.udev,
+ cmd, cmdlen, out, data, block_len);
+ break;
+ case MODE_SG:
+ error = do_scsi(h->dev.fd, cmd, cmdlen, out, data, block_len);
+ break;
+ case MODE_USBHID:
+ fprintf(stderr, "USBHID mode not (yet) supported\n");
+ error = -1;
+ }
+ return error;
+}
+
+
+/** Vendor command for our hacks */
+static
+unsigned char g_excmd[16] = {
+ 0xcd, 0, 0, 0,
+ 0, 6, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+
+/* device wrapper */
+
+const char idstring[] = "buildwin Photo Frame 1.01";
+
+#define INQ_REPLY_LEN 96
+
+int sgdev_open(const char *portname, int *fd)
+{
+ int error;
+
+ static
+ unsigned char inquiry[] = {
+ INQUIRY, 0, 0, 0,
+ INQ_REPLY_LEN, 0
+ };
+
+ static unsigned char inqbuf[INQ_REPLY_LEN + 2];
+
+ *fd = open(portname, O_RDONLY | O_NONBLOCK );
+ error = do_scsi(*fd, inquiry, sizeof(inquiry), DIR_IN, inqbuf,
+ INQ_REPLY_LEN);
+
+ if (error < 0) {
+ fprintf(stderr, "SCSI inquiry failed\n");
+ close(*fd); error = DEVERR_OPEN;
+ } else
+ if (memcmp(idstring, &inqbuf[8], sizeof(idstring) - 1) != 0) {
+ close(*fd); error = DEVERR_OPEN;
+ fprintf(stderr, "Not a photo frame. Refuse to open device.\n");
+ }
+ return error;
+}
+
+int probe(DPFHANDLE h)
+{
+ int ret;
+
+ // We abuse a command that just responds with a '0' status in the
+ // original firmware.
+ static unsigned char buf[5];
+
+
+ static
+ unsigned char cmd[16] = {
+ 0xcd, 0, 0, 0,
+ 0, 3, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+ };
+
+ cmd[5] = 3;
+ ret = wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, 0, 0);
+
+ switch (ret) {
+ case 0:
+ // The original protocol.
+ fprintf(stderr,
+ "Warning: This firmware can not lock the flash\n");
+ break;
+ case 1:
+ // The improved hack
+ h->flags |= FLAG_CAN_LOCK;
+ break;
+ }
+
+ cmd[5] = 2; // get LCD parameters
+ ret = wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, buf, 5);
+ h->width = (buf[0]) | (buf[1] << 8);
+ h->height = (buf[2]) | (buf[3] << 8);
+ h->bpp = 2;
+
+ return ret;
+}
+
+/* Memory stuff */
+
+static
+int mem_read_scsi(DPFContext *h, unsigned char *buf, ADDR offset, int len)
+{
+ unsigned char *cmd = g_excmd;
+
+ if (h->mode == MODE_USBHID) return DEVERR_UNSUPP;
+
+ cmd[6] = USBCMD_MEMREAD; // memory_read
+ cmd[7] = offset;
+ cmd[8] = offset >> 8;
+ cmd[9] = len;
+ cmd[10] = len >> 8;
+
+ return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_IN, buf, len);
+}
+
+int mem_write_scsi(DPFContext *h,
+ ADDR dst, const unsigned char *src, unsigned short n)
+{
+ unsigned char *cmd = g_excmd;
+
+ cmd[6] = 0x01; // memory_write
+ cmd[7] = dst;
+ cmd[8] = dst >> 8;
+ cmd[9] = n;
+ cmd[10] = n >> 8;
+
+ return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, (unsigned char *) src, n);
+}
+
+
+
+/* Flash stuff, SCSI wrapped */
+
+static
+int flash_cmd_scsi(DPFContext *h, int command, int cmdlen, ADDR addr)
+{
+ static
+ unsigned char cmd[16] = {
+ 0xcb, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0
+ };
+
+ cmd[10] = command;
+ cmd[6] = cmdlen;
+
+ // Sector number or addr:
+ cmd[13] = addr;
+ cmd[12] = addr >> 8;
+ cmd[11] = addr >> 16;
+
+ return wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, 0, 0);
+}
+
+int flash_status_scsi(DPFHANDLE h, uint8_t *status)
+{
+ *status = 0;
+ // FIXME : Really get status
+ return 0;
+}
+
+static
+int flash_read_scsi(DPFContext *h, unsigned char *buf, ADDR offset, int len)
+{
+ static
+ unsigned char cmd[16] = {
+ 0xcd, 0, 0, 0, 0, 0,
+ 0x04, /* num of bytes: */ 0, 0, 0,
+ SPM_READ, /* SPI offset: */ 0, 0, 0,
+ 0, 0
+ };
+
+ cmd[9] = len >> 0;
+ cmd[8] = len >> 8;
+ cmd[7] = len >> 16;
+
+ cmd[13] = offset >> 0;
+ cmd[12] = offset >> 8;
+ cmd[11] = offset >> 16;
+
+ return wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, buf, len);
+}
+
+static
+int flash_writechunk_scsi(DPFContext *h,
+ const unsigned char *buf, ADDR offset, int len)
+{
+ int error;
+ static
+ unsigned char cmd[16] = {
+ 0xcb, 0, 0, 0, 0, 0,
+ 4, /* num of bytes: */ 0, 0, 0,
+ SPM_PP, /* SPI offset: */ 0, 0, 0,
+ 0, 0
+ };
+
+ if (len > MAX_CHUNKSIZE) len = MAX_CHUNKSIZE;
+
+ cmd[9] = len >> 0;
+ cmd[8] = len >> 8;
+ cmd[7] = len >> 16;
+
+ cmd[13] = offset >> 0;
+ cmd[12] = offset >> 8;
+ cmd[11] = offset >> 16;
+
+ error = wrap_scsi(h, cmd, sizeof(cmd), DIR_OUT,
+ (unsigned char*) buf, len);
+ if (error < 0) return error;
+ return len;
+}
+
+int flash_lock_usb(DPFContext *h, char enable)
+{
+ unsigned char *cmd = g_excmd;
+
+ if (!(h->flags & FLAG_CAN_LOCK)) return DEVERR_UNSUPP;
+
+ printf("Lock flash %d\n", enable);
+ cmd[6] = USBCMD_FLASHLOCK; // flash lock
+ cmd[7] = enable;
+
+ wrap_scsi(h, cmd, sizeof(g_excmd), DIR_IN, 0, 0);
+ return 0;
+}
+
+static
+int flash_probe_scsi(DPFContext *h, unsigned char *id)
+{
+ int error;
+ static
+ unsigned char buf[64];
+ static
+ unsigned char cmd[16] = {
+ 0xcd, 0, 0, 0, 0, 0,
+ 1, sizeof(buf) >> 16, sizeof(buf) >> 8, sizeof(buf) >> 0,
+ // flash command sequence:
+ SPM_RDID, 0, 0, 0,
+ 0, 0
+ };
+
+ error = wrap_scsi(h, cmd, sizeof(cmd), DIR_IN, buf, sizeof(buf));
+ id[0] = buf[0]; id[1] = buf[1]; id[2] = buf[2];
+ return error;
+}
+
+
+static
+int go_scsi(DPFContext *h, ADDR start)
+{
+ unsigned char *cmd = g_excmd;
+ cmd[6] = 0x02; // execute
+ cmd[7] = start;
+ cmd[8] = start >> 8;
+
+ return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_IN, 0, 0);
+}
+
+static
+int bootstrap_scsi(DPFContext *h,
+ ADDR dest, unsigned char *src, unsigned short n, ADDR start)
+{
+ unsigned char *cmd = g_excmd;
+
+ cmd[6] = USBCMD_APPLOAD; // Enter bootstrap mode
+ cmd[7] = dest;
+ cmd[8] = dest >> 8;
+ cmd[9] = n;
+ cmd[10] = n >> 8;
+ cmd[11] = start;
+ cmd[12] = start >> 8;
+
+ return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, src, n);
+}
+
+AccessMethods
+scsi_methods = {
+ .mem_read = mem_read_scsi,
+ .mem_write = mem_write_scsi,
+ .go = go_scsi,
+ .bootstrap = bootstrap_scsi,
+ .flash_probe = flash_probe_scsi,
+ .flash_cmd = flash_cmd_scsi,
+ .flash_status = flash_status_scsi,
+ .flash_read = flash_read_scsi,
+ .flash_writechunk = flash_writechunk_scsi,
+ .flash_lock = flash_lock_usb,
+};
+
+////////////////////////////////////////////////////////////////////////////
+// SCSI only high level commands:
+
+int dpf_setcol(DPFContext *h, const unsigned char *rgb)
+{
+ unsigned char *cmd = g_excmd;
+
+ if (h->mode == MODE_USBHID) return DEVERR_UNSUPP;
+
+ cmd[6] = USBCMD_SETPROPERTY;
+ cmd[7] = PROPERTY_FGCOLOR;
+ cmd[8] = PROPERTY_FGCOLOR >> 8;
+
+ cmd[9] = RGB565_0(rgb[0], rgb[1], rgb[2]);
+ cmd[10] = RGB565_1(rgb[0], rgb[1], rgb[2]);
+
+ return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, NULL, 0);
+}
+
+int dpf_screen_blit(DPFContext *h,
+ const unsigned char *buf, short rect[4])
+{
+ unsigned long len = (rect[2] - rect[0]) * (rect[3] - rect[1]);
+ len <<= 1;
+ unsigned char *cmd = g_excmd;
+
+ if (h->mode == MODE_USBHID) return DEVERR_UNSUPP;
+
+ cmd[6] = USBCMD_BLIT;
+ cmd[7] = rect[0];
+ cmd[8] = rect[0] >> 8;
+ cmd[9] = rect[1];
+ cmd[10] = rect[1] >> 8;
+ cmd[11] = rect[2] - 1;
+ cmd[12] = (rect[2] - 1) >> 8;
+ cmd[13] = rect[3] - 1;
+ cmd[14] = (rect[3] - 1) >> 8;
+ cmd[15] = 0;
+
+ return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT,
+ (unsigned char*) buf, len);
+}
+
+int dpf_setproperty(DPFContext *h, int token, const DPFValue *value)
+{
+ unsigned char *cmd = g_excmd;
+
+ if (h->mode == MODE_USBHID) return DEVERR_UNSUPP;
+
+ cmd[6] = USBCMD_SETPROPERTY;
+ cmd[7] = token;
+ cmd[8] = token >> 8;
+
+ switch (value->type) {
+ case TYPE_INTEGER:
+ cmd[9] = value->value.integer;
+ cmd[10] = value->value.integer >> 8;
+ break;
+ default:
+ break;
+ }
+
+ return wrap_scsi(h, cmd, sizeof(g_excmd), DIR_OUT, NULL, 0);
+}
+
+
diff --git a/libdpf/sglib.h b/libdpf/sglib.h
new file mode 100644
index 0000000..a2bc232
--- /dev/null
+++ b/libdpf/sglib.h
@@ -0,0 +1,19 @@
+#include <stdint.h>
+
+
+/* generic device wrapper: */
+
+const char* dev_errstr(int error);
+
+
+/* generic SCSI device stuff: */
+
+#define DIR_IN 0
+#define DIR_OUT 1
+
+
+/* Special functions */
+
+
+
+
diff --git a/libdpf/spiflash.h b/libdpf/spiflash.h
new file mode 100644
index 0000000..fe7a8fd
--- /dev/null
+++ b/libdpf/spiflash.h
@@ -0,0 +1,30 @@
+/** \file flashcmd_st.h
+ *
+ * ST compatible flash cmds
+ *
+ */
+
+
+#define SPM_RDID 0x9f // Read Id
+#define SPM_NO_CMD 0x00 // No command
+
+#define SPM_WREN 0x06 // Write enable
+#define SPM_WRDI 0x04 // Write disable
+#define SPM_RDSR 0x05 // Read status register
+#define SPM_WRSR 0x01 // Write status register
+#define SPM_READ 0x03 // Read data bytes
+#define SPM_PP 0x02 // Page program
+#define SPM_DP 0xb9 // Deep power down
+#define SPM_RES 0xab // Release from deep power down
+ // and read signature
+#define SPM_FLASH_SE 0xd8 // Sector erase
+#define SPM_FLASH_BE 0xc7 // Bulk erase
+#define SPM_FLASH_FAST_READ 0x0B // Read data bytes fast
+
+#define SPM_SR_SRWD 0x80 // SR write protection (HW)
+
+// Status register bit definitions
+#define SPS_WIP 0x01 // write in progress
+#define SPS_WEL 0x02 // write enable latch
+
+
diff --git a/libdpf/usbuser.h b/libdpf/usbuser.h
new file mode 100644
index 0000000..37fb705
--- /dev/null
+++ b/libdpf/usbuser.h
@@ -0,0 +1,29 @@
+/* USB user commands
+ *
+ * Only temporary. Should move to dpflib or into a dclib configuration.
+ *
+ */
+
+#define PROTOCOL_VERSION 1
+
+/** Our vendor specific USB commands to do stuff on the DPF */
+
+#define USBCMD_GETPROPERTY 0x00 ///< Get property
+#define USBCMD_SETPROPERTY 0x01 ///< Set property
+#define USBCMD_MEMREAD 0x04 ///< Memory read
+#define USBCMD_APPLOAD 0x05 ///< Load and run applet
+#define USBCMD_FILLRECT 0x11 ///< Fill screen rectangle
+#define USBCMD_BLIT 0x12 ///< Blit to screen
+#define USBCMD_COPYRECT 0x13 ///< Copy screen rectangle
+#define USBCMD_FLASHLOCK 0x20 ///< Lock USB for flash access
+#define USBCMD_PROBE 0xff ///< Get version code (probe)
+
+/* Some special return codes */
+#define USB_IN_SEQUENCE 0x7f ///< We're inside a command sequence
+
+// Property handling:
+
+#define PROPERTY_BRIGHTNESS 0x01
+#define PROPERTY_FGCOLOR 0x02
+#define PROPERTY_BGCOLOR 0x03
+#define PROPERTY_ORIENTATION 0x10