aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormichael <michael@3ae390bd-cb1e-0410-b409-cd5a39f66f1f>2013-05-23 03:05:50 +0000
committermichael <michael@3ae390bd-cb1e-0410-b409-cd5a39f66f1f>2013-05-23 03:05:50 +0000
commitab5d1fd17f1892b25299b5dd7ae7de0c5121613e (patch)
treec05ab79104e6cf85b428fa873d7f6a5569124191
parent151f501456f36ffb32e02a4d9b8d232746a40eb3 (diff)
downloadlcd4linux-ab5d1fd17f1892b25299b5dd7ae7de0c5121613e.tar.gz
DPF patch by superelchi
git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@1198 3ae390bd-cb1e-0410-b409-cd5a39f66f1f
-rw-r--r--configure.in3
-rw-r--r--drivers.m412
-rw-r--r--drv_dpf.c644
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 <picframe@spritesmods.com>
* Modified from sample code by:
* Copyright (C) 2005 Michael Reinelt <michael@reinelt.co.at>
* Copyright (C) 2005, 2006, 2007 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
+ *
+ * Mods by <hackfin@section5.ch>
+ * Complete rewrite 05/2013 by superelchi <superelchi AT wolke7.net>
+ *
*
* This file is part of LCD4Linux.
*
@@ -46,8 +47,6 @@
#include <string.h>
#include <errno.h>
-#include <libdpf/libdpf.h>
-
#include "debug.h"
#include "cfg.h"
#include "qprintf.h"
@@ -61,149 +60,309 @@
#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 <usb.h>
+
+#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
+//###################################################################