From ab5d1fd17f1892b25299b5dd7ae7de0c5121613e Mon Sep 17 00:00:00 2001 From: michael Date: Thu, 23 May 2013 03:05:50 +0000 Subject: DPF patch by superelchi git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@1198 3ae390bd-cb1e-0410-b409-cd5a39f66f1f --- configure.in | 3 - drivers.m4 | 12 +- drv_dpf.c | 644 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 549 insertions(+), 110 deletions(-) diff --git a/configure.in b/configure.in index e6fb646..477c5ae 100644 --- a/configure.in +++ b/configure.in @@ -87,9 +87,6 @@ AC_CHECK_HEADERS(serdisplib/serdisp.h, [has_serdisplib="true"], [has_serdisplib= # check for st2205 libs AC_CHECK_HEADERS(st2205.h, [has_st2205="true"], [has_st2205="false"]) -# check for libdpf libs -AC_CHECK_HEADERS(libdpf/libdpf.h, [has_libdpf="true"], [has_libdpf="false"]) - # check for vncserver libs AC_CHECK_HEADERS(rfb/rfb.h, [has_vncserverlib="true"], [has_vncserverlib="false"]) diff --git a/drivers.m4 b/drivers.m4 index a692bf2..c3b9d46 100644 --- a/drivers.m4 +++ b/drivers.m4 @@ -378,14 +378,10 @@ if test "$D4D" = "yes"; then fi if test "$DPF" = "yes"; then - if test "$has_libdpf" = "true"; then - GRAPHIC="yes" - DRIVERS="$DRIVERS drv_dpf.o" - DRVLIBS="$DRVLIBS -Llibdpf -ldpf -lusb" - AC_DEFINE(WITH_DPF,1,[DPF driver]) - else - AC_MSG_WARN(libdpf.h not found: DPF driver disabled) - fi + GRAPHIC="yes" + DRIVERS="$DRIVERS drv_dpf.o" + LIBUSB="yes" + AC_DEFINE(WITH_DPF,1,[DPF driver]) fi if test "$EA232graphic" = "yes"; then diff --git a/drv_dpf.c b/drv_dpf.c index 39e1708..eff490e 100644 --- a/drv_dpf.c +++ b/drv_dpf.c @@ -1,16 +1,17 @@ /* $Id: drv_dpf.c 980 2009-01-28 21:18:52Z michux $ * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_dpf.c $ * - * Very basic hacked picture frame driver. Uses external libdpf. - * This is a first working approach for AX206 based DPFs. In future, - * more DPFs might be covered by that library. Work in progress. + * Driver for hacked digital picture frames. Uses *NO* external libraries. + * See http://dpf-ax.sourceforge.net/ for more information. * - * See http://picframe.spritesserver.nl/ for more info. - * * Copyright (C) 2008 Jeroen Domburg * Modified from sample code by: * Copyright (C) 2005 Michael Reinelt * Copyright (C) 2005, 2006, 2007 The LCD4Linux Team + * + * Mods by + * Complete rewrite 05/2013 by superelchi + * * * This file is part of LCD4Linux. * @@ -46,8 +47,6 @@ #include #include -#include - #include "debug.h" #include "cfg.h" #include "qprintf.h" @@ -61,148 +60,308 @@ #include "drv_generic_graphic.h" +//################################################################### +// Start dpfcore4driver.h +// See http://dpf-ax.sourceforge.net/ +//################################################################### + +#define DPFAXHANDLE void * // Handle needed for dpf_ax access +#define DPF_BPP 2 //bpp for dfp-ax is currently always 2! + +/** + * Open DPF device. + * + * Device must be string in the form "usbX" or "dpfX", with X = 0 .. number of connected dpfs. + * The open function will scan the USB bus and return a handle to access dpf #X. + * If dpf #X is not found, returns NULL. + * + * \param dev device name to open + * \return device handle or NULL + */ +DPFAXHANDLE dpf_ax_open(const char *device); + +/** + * Close DPF device. + */ +void dpf_ax_close(DPFAXHANDLE h); + +/** Blit data to screen. + * + * \param buf buffer to 16 bpp RGB 565 image data + * \param rect rectangle tuple: [x0, y0, x1, y1] + */ +void dpf_ax_screen_blit(DPFAXHANDLE h, const unsigned char *buf, short rect[4]); + +/** Set backlight brightness. + * + * \param value Backlight value 0..7 (0 = off, 7 = max brightness) + */ +void dpf_ax_setbacklight(DPFAXHANDLE h, int value); + +/** Get screen width. + * + * \return width in pixel + */ +int dpf_ax_getwidth(DPFAXHANDLE h); + +/** Get screen height. + * + * \return height in pixel + */ +int dpf_ax_getheight(DPFAXHANDLE h); + +//################################################################### +// End dpfcore4driver.h +//################################################################### + + static char Name[] = "DPF"; -static DPFContext *g_h; -/* Display data */ -static unsigned char *g_fb; +/* + * Dpf status + */ +static struct { + unsigned char *lcdBuf; // Display data buffer + unsigned char *xferBuf; // USB transfer buffer + DPFAXHANDLE dpfh; // Handle for dpf access + int pwidth; // Physical display width + int pheight; // Physical display height -static int drv_dpf_open(const char *section) -{ - int error; - char *dev; + // Flags to translate logical to physical orientation + int isPortrait; + int rotate90; + int flip; - // Currently, the Port specification is unused. + // Current dirty rectangle + int minx, maxx; + int miny, maxy; - dev = cfg_get(section, "Port", NULL); - if (dev == NULL || *dev == '\0') { - error("dpf: no '%s.Port' entry from %s", section, cfg_source()); - return -1; - } + // Config properties + int orientation; + int backlight; +} dpf; - error = dpf_open(NULL, &g_h); - if (error < 0) { - error("dpf: cannot open dpf device %s", dev); - return -1; - } - return 0; -} +// Convert RGBA pixel to RGB565 pixel(s) +#define _RGB565_0(p) (( ((p.R) & 0xf8) ) | (((p.G) & 0xe0) >> 5)) +#define _RGB565_1(p) (( ((p.G) & 0x1c) << 3 ) | (((p.B) & 0xf8) >> 3)) -static int drv_dpf_close(void) +/* + * Set one pixel in lcdBuf. + * + * Respects orientation and updates dirty rectangle. + * + * in: x, y - pixel coordinates + * pix - RGBA pixel value + * out: - + */ +static void drv_set_pixel(int x, int y, RGBA pix) { - dpf_close(g_h); + int changed = 0; + + int sx = DCOLS; + int sy = DROWS; + int lx = x % sx; + int ly = y % sy; + + if (dpf.flip) { + // upside down orientation + lx = DCOLS - 1 - lx; + ly = DROWS - 1 - ly; + } - return 0; -} + if (dpf.rotate90) { + // wrong Orientation, rotate + int i = ly; + ly = dpf.pheight - 1 - lx; + lx = i; + } + + if (lx < 0 || lx >= (int) dpf.pwidth || ly < 0 || ly >= (int) dpf.pheight) + { + error("dpf: x/y out of bounds (x=%d, y=%d, rot=%d, flip=%d, lx=%d, ly=%d)\n", x, y, dpf.rotate90, dpf.flip, lx, ly); + return; + } -#define _RGB565_0(p) \ - (( ((p.R) & 0xf8) ) | (((p.G) & 0xe0) >> 5)) -#define _RGB565_1(p) \ - (( ((p.G) & 0x1c) << 3 ) | (((p.B) & 0xf8) >> 3)) + unsigned char c1 = _RGB565_0(pix); + unsigned char c2 = _RGB565_1(pix); + unsigned int i = (ly * dpf.pwidth + lx) * DPF_BPP; + if (dpf.lcdBuf[i] != c1 || dpf.lcdBuf[i+1] != c2) + { + dpf.lcdBuf[i] = c1; + dpf.lcdBuf[i+1] = c2; + changed = 1; + } + if (changed) + { + if (lx < dpf.minx) dpf.minx = lx; + if (lx > dpf.maxx) dpf.maxx = lx; + if (ly < dpf.miny) dpf.miny = ly; + if (ly > dpf.maxy) dpf.maxy = ly; + } +} + +/* + * Send pixel data to dpf + */ static void drv_dpf_blit(const int row, const int col, const int height, const int width) { - int r, c; - short rect[4]; - unsigned long i; - RGBA p; - unsigned char *pix; - - pix = g_fb; - for (r = row; r < row + height; r++) { - for (c = col; c < col + width; c++) { - p = drv_generic_graphic_rgb(r, c); - *pix++ = _RGB565_0(p); - *pix++ = _RGB565_1(p); - } + int x, y; + + // Set pixels one by one + // Note: here is room for optimization :-) + for (y = row; y < row + height; y++) + for (x = col; x < col + width; x++) + drv_set_pixel(x, y, drv_generic_graphic_rgb(y, x)); + + // If nothing has changed, skip transfer + if (dpf.minx > dpf.maxx || dpf.miny > dpf.maxy) + return; + + // Copy data in dirty rectangle from data buffer to temp transfer buffer + unsigned int cpylength = (dpf.maxx - dpf.minx + 1) * DPF_BPP; + unsigned char *ps = dpf.lcdBuf + (dpf.miny * dpf.pwidth + dpf.minx) * DPF_BPP; + unsigned char *pd = dpf.xferBuf; + for (y = dpf.miny; y <= dpf.maxy; y++) { + memcpy(pd, ps, cpylength); + ps += dpf.pwidth * DPF_BPP; + pd += cpylength; } - rect[0] = col; - rect[1] = row; - rect[2] = col + width; - rect[3] = row + height; - dpf_screen_blit(g_h, g_fb, rect); + + // Send the buffer + short rect[4]; + rect[0] = dpf.minx; + rect[1] = dpf.miny; + rect[2] = dpf.maxx + 1; + rect[3] = dpf.maxy + 1; + dpf_ax_screen_blit(dpf.dpfh, dpf.xferBuf, rect); + + // Reset dirty rectangle + dpf.minx = dpf.pwidth - 1; + dpf.maxx = 0; + dpf.miny = dpf.pheight - 1; + dpf.maxy = 0; } /* start graphic display */ -static int drv_dpf_start2(const char *section) +static int drv_dpf_start(const char *section) { + int i; + char *dev; char *s; + // Check if config is valid + + // Get the device + dev = cfg_get(section, "Port", NULL); + if (dev == NULL || *dev == '\0') { + error("dpf: no '%s.Port' entry from %s", section, cfg_source()); + return -1; + } + + // Get font s = cfg_get(section, "Font", "6x8"); if (s == NULL || *s == '\0') { - error("%s: no '%s.Font' entry from %s", Name, section, cfg_source()); - return -1; + error("%s: no '%s.Font' entry from %s", Name, section, cfg_source()); + return -1; } XRES = -1; YRES = -1; if (sscanf(s, "%dx%d", &XRES, &YRES) != 2 || XRES < 1 || YRES < 1) { - error("%s: bad Font '%s' from %s", Name, s, cfg_source()); - return -1; + error("%s: bad Font '%s' from %s", Name, s, cfg_source()); + return -1; } - /* Fixme: provider other fonts someday... */ - /* Overridden - we have scaled the textout drawing */ -/* if (XRES != 6 && YRES != 8) { - error("%s: bad Font '%s' from %s (only 6x8 at the moment)", Name, s, cfg_source()); - return -1; - } */ - /* we dont want fonts below 6 width */ if (XRES < 6) { - error("%s: bad Font '%s' width '%d' using minimum of 6)", Name, s, XRES); - XRES = 6; + error("%s: bad Font '%s' width '%d' using minimum of 6)", Name, s, XRES); + XRES = 6; } /* we dont want fonts below 8 height */ if (YRES < 8) { - error("%s: bad Font '%s' height '%d' using minimum of 8)", Name, s, YRES); - YRES = 8; + error("%s: bad Font '%s' height '%d' using minimum of 8)", Name, s, YRES); + YRES = 8; } + // Get the logical orientation (0 = landscape, 1 = portrait, 2 = reverse landscape, 3 = reverse portrait) + if (cfg_number(section, "Orientation", 0, 0, 3, &i) > 0) + dpf.orientation = i; + else + dpf.orientation = 0; + + // Get the backlight value (0 = off, 7 = max brightness) + if (cfg_number(section, "Backlight", 0, 0, 7, &i) > 0) + dpf.backlight = i; + else + dpf.backlight = 7; + /* open communication with the display */ - if (drv_dpf_open(section) < 0) { - return -1; + dpf.dpfh = dpf_ax_open(dev); + if (dpf.dpfh == NULL) { + error("dpf: cannot open dpf device %s", dev); + return -1; } - /* you surely want to allocate a framebuffer or something... */ - g_fb = malloc(g_h->height * g_h->width * g_h->bpp); - - /* set width/height from dpf firmware specs */ - DROWS = g_h->height; - DCOLS = g_h->width; + // Get dpfs physical dimensions + dpf.pwidth = dpf_ax_getwidth(dpf.dpfh); + dpf.pheight = dpf_ax_getheight(dpf.dpfh); + + // See, if we have to rotate the display + dpf.isPortrait = dpf.pwidth < dpf.pheight; + if (dpf.isPortrait) { + if (dpf.orientation == 0 || dpf.orientation == 2) + dpf.rotate90 = 1; + } + else + if (dpf.orientation == 1 || dpf.orientation == 3) + dpf.rotate90 = 1; + dpf.flip = (!dpf.isPortrait && dpf.rotate90); // adjust to make rotate por/land = physical por/land + if (dpf.orientation > 1) dpf.flip = !dpf.flip; + + // allocate display buffer + temp transfer buffer + dpf.lcdBuf = malloc(dpf.pwidth * dpf.pheight * DPF_BPP); + dpf.xferBuf = malloc(dpf.pwidth * dpf.pheight * DPF_BPP); + + // clear display buffer + set it to "dirty" + memset(dpf.lcdBuf, 0, dpf.pwidth * dpf.pheight * DPF_BPP); //Black + dpf.minx = 0; + dpf.maxx = dpf.pwidth - 1; + dpf.miny = 0; + dpf.maxy = dpf.pheight - 1; + + // set the logical width/height for lcd4linux + DCOLS = ((!dpf.rotate90) ? dpf.pwidth : dpf.pheight); + DROWS = ((!dpf.rotate90) ? dpf.pheight : dpf.pwidth); + + // Set backlight (brightness) + dpf_ax_setbacklight(dpf.dpfh, dpf.backlight); + return 0; } + /****************************************/ /*** plugins ***/ /****************************************/ static void plugin_backlight(RESULT * result, RESULT * arg1) { - int bl_on; - bl_on = (R2N(arg1) == 0 ? 0 : 1); - dpf_backlight(g_h, bl_on); - SetResult(&result, R_NUMBER, &bl_on); + int b = R2N(arg1); + if (b < 0) b = 0; + if (b > 7) b = 7; + + dpf_ax_setbacklight(dpf.dpfh, b); + SetResult(&result, R_NUMBER, &b); } -/****************************************/ -/*** widget callbacks ***/ -/****************************************/ - - -/* using drv_generic_text_draw(W) */ -/* using drv_generic_text_icon_draw(W) */ -/* using drv_generic_text_bar_draw(W) */ -/* using drv_generic_gpio_draw(W) */ - - /****************************************/ /*** exported functions ***/ /****************************************/ @@ -211,13 +370,13 @@ static void plugin_backlight(RESULT * result, RESULT * arg1) /* list models */ int drv_dpf_list(void) { - printf("generic hacked photo frame"); + printf("Hacked dpf-ax digital photo frame"); return 0; } /* initialize driver & display */ -int drv_dpf_init2(const char *section, const int quiet) +int drv_dpf_init(const char *section, const int quiet) { int ret; @@ -225,7 +384,7 @@ int drv_dpf_init2(const char *section, const int quiet) drv_generic_graphic_real_blit = drv_dpf_blit; /* start display */ - if ((ret = drv_dpf_start2(section)) != 0) + if ((ret = drv_dpf_start(section)) != 0) return ret; /* initialize generic graphic driver */ @@ -249,7 +408,7 @@ int drv_dpf_init2(const char *section, const int quiet) /* close driver & display */ -int drv_dpf_quit2(const int quiet) +int drv_dpf_quit(const int quiet) { info("%s: shutting down.", Name); @@ -264,7 +423,7 @@ int drv_dpf_quit2(const int quiet) drv_generic_graphic_quit(); debug("closing connection"); - drv_dpf_close(); + dpf_ax_close(dpf.dpfh); return (0); } @@ -273,6 +432,293 @@ int drv_dpf_quit2(const int quiet) DRIVER drv_DPF = { .name = Name, .list = drv_dpf_list, - .init = drv_dpf_init2, - .quit = drv_dpf_quit2, + .init = drv_dpf_init, + .quit = drv_dpf_quit, +}; + +//################################################################### +// Start dpfcore4driver.c +// See http://dpf-ax.sourceforge.net/ +//################################################################### + +#include + +#define AX206_VID 0x1908 // Hacked frames USB Vendor ID +#define AX206_PID 0x0102 // Hacked frames USB Product ID + +#define USBCMD_SETPROPERTY 0x01 // USB command: Set property +#define USBCMD_BLIT 0x12 // USB command: Blit to screen + +/* Generic SCSI device stuff */ + +#define DIR_IN 0 +#define DIR_OUT 1 + +/* The DPF context structure */ +typedef +struct dpf_context { + usb_dev_handle *udev; + unsigned int width; + unsigned int height; +} DPFContext; + +static int wrap_scsi(DPFContext *h, unsigned char *cmd, int cmdlen, char out, + unsigned char *data, unsigned long block_len); + +/** + * Open DPF device. + * + * Device must be string in the form "usbX" or "dpfX", with X = 0 .. number of connected dpfs. + * The open function will scan the USB bus and return a handle to access dpf #X. + * If dpf #X is not found, returns NULL. + * + * \param dev device name to open + * \return device handle or NULL + */ +DPFAXHANDLE dpf_ax_open(const char *dev) +{ + DPFContext *dpf; + int index = -1; + usb_dev_handle *u; + + if (dev && strlen(dev) == 4 && (strncmp(dev, "usb", 3) == 0 || strncmp(dev, "dpf", 3) == 0)) + index = dev[3] - '0'; + + if (index < 0 || index > 9) { + fprintf(stderr, "dpf_ax_open: wrong device '%s'. Please specify a string like 'usb0'\n", dev); + return NULL; + } + + usb_init(); + usb_find_busses(); + usb_find_devices(); + + struct usb_bus *b = usb_get_busses(); + struct usb_device *d = NULL; + int enumeration = 0; + int found = 0; + + while (b && !found) { + d = b->devices; + while (d) { + if ((d->descriptor.idVendor == AX206_VID) && (d->descriptor.idProduct == AX206_PID)) { + fprintf(stderr, "dpf_ax_open: found AX206 #%d\n", enumeration+1); + if (enumeration == index) { + found = 1; + break; + } + else enumeration++; + } + d = d->next; + } + b = b->next; + } + + if (!d) { + fprintf(stderr,"dpf_ax_open: no matching USB device '%s' found!\n", dev); + return NULL; + } + + dpf = (DPFContext *) malloc(sizeof(DPFContext)); + if (!dpf) { + fprintf(stderr, "dpf_ax_open: error allocation memory.\n"); + return NULL; + } + + u = usb_open(d); + if (u == NULL) { + fprintf(stderr,"dpf_ax_open: failed to open usb device '%s'!\n", dev); + free(dpf); + return NULL; + } + + if (usb_claim_interface(u, 0) < 0) { + fprintf(stderr,"dpf_ax_open: failed to claim usb device!\n"); + usb_close(u); + free(dpf); + return NULL; + } + + dpf->udev = u; + + static unsigned char buf[5]; + static unsigned char cmd[16] = { + 0xcd, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + }; + cmd[5] = 2; // get LCD parameters + if (wrap_scsi(dpf, cmd, sizeof(cmd), DIR_IN, buf, 5) == 0) { + dpf->width = (buf[0]) | (buf[1] << 8); + dpf->height = (buf[2]) | (buf[3] << 8); + fprintf(stderr, "dpf_ax_open: got LCD dimensions: %dx%d\n", dpf->width, dpf->height); + } + else { + fprintf(stderr, "dpf_ax_open: error reading LCD dimensions!\n"); + dpf_ax_close(dpf); + return NULL; + } + return (DPFAXHANDLE) dpf; +} + +/** + * Close DPF device + */ + +void dpf_ax_close(DPFAXHANDLE h) +{ + DPFContext *dpf = (DPFContext *) h; + + usb_release_interface(dpf->udev, 0); + usb_close(dpf->udev); + free(dpf); +} + +/** Get screen width. + * + * \return width in pixel + */ +int dpf_ax_getwidth(DPFAXHANDLE h) +{ + return ((DPFContext *) h)->width; +} + +/** Get screen height. + * + * \return height in pixel + */ +int dpf_ax_getheight(DPFAXHANDLE h) +{ + return ((DPFContext *) h)->height; +} + +static +unsigned char g_excmd[16] = { + 0xcd, 0, 0, 0, + 0, 6, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 }; + +/** Blit data to screen. + * + * \param buf buffer to 16 bpp RGB 565 image data + * \param rect rectangle tuple: [x0, y0, x1, y1] + */ +void dpf_ax_screen_blit(DPFAXHANDLE 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; + + 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; + + wrap_scsi((DPFContext *) h, cmd, sizeof(g_excmd), DIR_OUT, (unsigned char*) buf, len); +} + +/** Set backlight + * + * \param value Backlight value 0..7 (0 = off, 7 = max brightness) + */ +void dpf_ax_setbacklight(DPFAXHANDLE h, int b) +{ + unsigned char *cmd = g_excmd; + + if (b < 0) b = 0; + if (b > 7) b = 7; + + cmd[6] = USBCMD_SETPROPERTY; + cmd[7] = 0x01; // PROPERTY_BRIGHTNESS + cmd[8] = 0x00; //PROPERTY_BRIGHTNESS >> 8; + cmd[9] = b; + cmd[10] = b >> 8; + + wrap_scsi((DPFContext *) h, cmd, sizeof(g_excmd), DIR_OUT, NULL, 0); +} + + +static unsigned 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, +}; + +#define ENDPT_OUT 1 +#define ENDPT_IN 0x81 + +static int wrap_scsi(DPFContext *h, 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(h->udev, ENDPT_OUT, (const char *)g_buf, sizeof(g_buf), 1000); + if (ret < 0) return ret; + + if (out == DIR_OUT) { + if (data) { + ret = usb_bulk_write(h->udev, ENDPT_OUT, (const char* )data, block_len, 3000); + if (ret != (int) block_len) { + fprintf(stderr, "dpf_ax ERROR: bulk write.\n"); + return ret; + } + } + } else if (data) { + ret = usb_bulk_read(h->udev, ENDPT_IN, (char *) data, block_len, 4000); + if (ret != (int) block_len) { + fprintf(stderr, "dpf_ax ERROR: bulk read.\n"); + return ret; + } + } + // get ACK: + len = sizeof(ansbuf); + int retry = 0; + int timeout = 0; + do { + timeout = 0; + ret = usb_bulk_read(h->udev, ENDPT_IN, (char *) ansbuf, len, 5000); + if (ret != len) { + fprintf(stderr, "dpf_ax ERROR: bulk ACK read.\n"); + timeout = 1; + } + retry++; + } while (timeout && retry < 5); + if (strncmp((char *) ansbuf, "USBS", 4)) { + fprintf(stderr, "dpf_ax ERROR: got invalid reply\n."); + return -1; + } + // pass back return code set by peer: + return ansbuf[12]; +} + +//################################################################### +// End dpfcore4driver.c +//################################################################### -- cgit v1.2.3