summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Make.config4
-rw-r--r--docs/DRIVER.ax206dpf104
-rw-r--r--glcddrivers/Makefile11
-rw-r--r--glcddrivers/ax206dpf.c724
-rw-r--r--glcddrivers/ax206dpf.h267
-rw-r--r--glcddrivers/drivers.c10
-rw-r--r--glcddrivers/drivers.h3
-rw-r--r--graphlcd.conf39
8 files changed, 1161 insertions, 1 deletions
diff --git a/Make.config b/Make.config
index 692d62c..cd5c6c6 100644
--- a/Make.config
+++ b/Make.config
@@ -37,3 +37,7 @@ HAVE_FREETYPE2=1
# uncomment one of the following two lines if you want either GraphicsMagick/ImageMagick support
#HAVE_IMAGEMAGICK=1
#HAVE_GRAPHICSMAGICK=1
+
+# uncomment this variable if you want to enable the experimental AX 206 based digital photo frame driver
+# Read DRIVER.ax206dpf before use!
+#HAVE_AX206DPF_EXPERIMENTAL=1
diff --git a/docs/DRIVER.ax206dpf b/docs/DRIVER.ax206dpf
new file mode 100644
index 0000000..45c3d40
--- /dev/null
+++ b/docs/DRIVER.ax206dpf
@@ -0,0 +1,104 @@
+---------------------------------------------------------------------
+GraphLCD driver library
+
+The AX 206 digital photoframe driver
+---------------------------------------------------------------------
+
+Description
+-----------
+The ax206dpf driver supports AX 206 based DPFs.
+For more information about these DPFs see:
+http://tech.section5.ch/news/?p=68
+
+The driver was tested with this display:
+http://www.pearl.de/a-PX1184-5618.shtml or http://www.pearl.de/a-HPM1184-5618.shtml
+
+Important Notes
+---------------
+This driver is experimental and not enabled by default.
+To use this driver uncomment the HAVE_AX206DPF_EXPERIMENTAL line in
+Make.config and recompile the library.
+The DPF does not work out of the box with this driver.
+It has to be modified with a custom firmware (see "Hacking your DPF").
+If your DPF is already hacked, there is no need to install the "dpf-ax" package
+described in "Hacking your DPF". All necessary routines to access a hacked
+DPF are included in this driver.
+
+Non-root users
+--------------
+The driver needs write access to /dev/proc/usb. So the calling user
+must be root or you have to modify the access rights for /dev/proc/usb.
+For Debian/Ubuntu this can be done with a custom udev rule like:
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664", GROUP="<user_group>"
+Replace <user_group> with a group the calling user belongs to.
+Put this rule in a new file "nn-usbuser.rules" in /etc/udev/rules.d.
+Replace "nn" by two digits that are lower than any existing usb rule.
+For my Ubuntu 10.04 system I used "/etc/udev/rules.d/35-usbuser.rules".
+
+
+Configuration Parameters
+------------------------
+The driver supports the following parameters in config file:
+
+Device
+ Selects a specific display.
+ 'dpf0' = first detected display, 'dpf1' = second detected display, ...
+ Default value: 'dpf0'
+
+Width
+ Sets the horizontal size of the display. If this parameter is not
+ given, a default value according to the selected DPF is used.
+ Default value: 320 or 240 (see 'Portrait')
+
+Height
+ Sets the vertical size of the display. If this parameter is not
+ given, a default value according to the selected DPF is used.
+ Default value: 240 or 320 (see 'Portrait')
+
+UpsideDown
+ Rotates the display output by 180 degrees. This might be useful, if
+ the LCD is mounted upside-down.
+ Possible values: 'yes', 'no'
+ Default value: 'no'
+
+Portrait
+ Select portrait or landscape mode.
+ Rotate display output by 90 degrees if necessary.
+ Possible values: 'yes' -> default size = 240 x 320
+ 'no' -> default size = 320 x 240
+ Default value: 'no'
+
+Zoom
+ Determines if pixels should be magnified.
+ Possible values: 1, 2, 3, 4
+ Default value: 1
+
+
+Hacking your DPF
+----------------
+For hacking your DPF you need this dpf-ax package:
+http://tech.section5.ch/files/dpfhack-0.12devel.tgz
+
+First of all, let me quote this from the dpf-ax README ((c) 4/2011, hackfin):
+[quote]
+Also note: NO SUPPORT! NO WARRANTY! FRIENDS DON'T MAKE FRIENDS HACK THEIR
+DPF! LET ALONE NON-FRIENDS! (Bottomline: Don't ask me if I can hack your DPF).
+
+If you wish to hack your DPF, please check the sites listed below.
+.
+.
+Find updates and documentation here:
+
+http://tech.section5.ch/news/?p=68
+or here:
+http://picframe.spritesserver.nl/wiki/index.php/DPF_with_AppoTech_AX206
+For our german users, a very good explanation is found here:
+http://geekparadise.de/2011/04/digitaler-bilderrahmen-von-pearl-als-statusdisplay-fur-dockstar/
+[/quote]
+
+So if you are not sure if you have the right DPF or something goes wrong:
+don't ask me ether - I'm like you only a user and not involved in the
+development of the hack!
+
+A guide how to hack the Pearl display can be found here (in german):
+http://www.vdr-portal.de/board1-news/board2-vdr-news/p1015287-announce-graphlcd-base-vdr-plugin-touchcol-branch/#post1015287
diff --git a/glcddrivers/Makefile b/glcddrivers/Makefile
index 72776d8..6327b2b 100644
--- a/glcddrivers/Makefile
+++ b/glcddrivers/Makefile
@@ -25,6 +25,17 @@ LIBS += $(shell pkg-config --libs libhid)
DEFINES += -DHAVE_LIBHID
endif
+
+ifeq ($(shell pkg-config --exists libusb && echo 1), 1)
+ DEFINES += -DHAVE_LIBUSB
+ ifdef HAVE_AX206DPF_EXPERIMENTAL
+ OBJS += ax206dpf.o
+ INCLUDES += $(shell pkg-config --cflags libusb)
+ LIBS += $(shell pkg-config --libs libusb)
+ DEFINES += -DHAVE_AX206DPF_EXPERIMENTAL
+ endif
+endif
+
### Implicit rules:
%.o: %.c
diff --git a/glcddrivers/ax206dpf.c b/glcddrivers/ax206dpf.c
new file mode 100644
index 0000000..708622a
--- /dev/null
+++ b/glcddrivers/ax206dpf.c
@@ -0,0 +1,724 @@
+/*
+ * GraphLCD driver library
+ *
+ * ax206dpf.h - AX206dpf driver class
+ * Output goes to AX 206 based photoframe
+ *
+ * based on:
+ * simlcd device
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ * (c) 2011 Dirk Heiser
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
+ *
+ * includes code from:
+ * http://sourceforge.net/projects/dpf-ax/
+ *
+ * Original copyright:
+ *
+ * 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>
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2011 Lutz Neumann <superelchi AT wolke7.de>
+ *
+ * HISTORY
+ *
+ * v0.1 - 10 Aug 2011 - Inital release
+ *
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <cstring>
+
+#include "common.h"
+#include "config.h"
+
+#include "ax206dpf.h"
+
+
+namespace GLCD
+{
+static LIBDPF::DPFContext *dpfh;
+
+cDriverAX206DPF::cDriverAX206DPF(cDriverConfig * config)
+: config(config)
+{
+ oldConfig = new cDriverConfig(*config);
+}
+
+cDriverAX206DPF::~cDriverAX206DPF()
+{
+ delete oldConfig;
+}
+
+int cDriverAX206DPF::Init(void)
+{
+ zoom = 1;
+ bool forcePortrait = false;
+ for (unsigned int i = 0; i < config->options.size(); i++)
+ {
+ if (config->options[i].name == "Portrait") {
+ forcePortrait = config->options[i].value == "yes";
+ }
+ else if (config->options[i].name == "Zoom") {
+ int z = strtol(config->options[i].value.c_str(), (char **) NULL, 0);
+ if (z > 0 && z <= 4)
+ zoom = z;
+ else
+ syslog(LOG_ERR, "%s error: zoom %d not supported, using default (%d)!\n",config->name.c_str(), z, zoom);
+
+ }
+ }
+
+ // Init display
+
+ int error;
+ char index;
+
+ if (config->device.length() != 4 || config->device.compare(0, 3, "dpf"))
+ index = '0';
+ else
+ index = config->device.at(3);
+
+ char usb_device[5];
+ sprintf(usb_device, "usb%c", index);
+
+ error = dpf_open(usb_device, &dpfh);
+ if (error < 0) {
+ syslog(LOG_INFO, "%s: can not open dpf device number '%c' (error %d).\n", config->name.c_str(), index, error);
+ return -1;
+ }
+
+ // See, if we have to rotate the display
+ isPortrait = dpfh->width < dpfh->height;
+ rotate90 = isPortrait != forcePortrait;
+
+ // Set width / height from display
+ unsigned int vwidth = (!rotate90) ? dpfh->width : dpfh->height;
+ unsigned int vheight = (!rotate90) ? dpfh->height : dpfh->width;
+ width = config->width;
+ if (width <= 0 || width > (int) vwidth)
+ width = (int) vwidth;
+ height = config->height;
+ if (height <= 0 || height > (int) vheight)
+ height = (int) vheight;
+ if (zoom > 1)
+ {
+ height /= zoom;
+ width /= zoom;
+ }
+
+ // setup lcd array
+ LCD = (unsigned char *) malloc(dpfh->height * dpfh->width * dpfh->bpp);
+ ResetMinMax();
+
+ *oldConfig = *config;
+
+ // Set Display Brightness -- NOT WORKING!
+ //SetBrightness(config->brightness ? config->brightness : 100);
+ syslog(LOG_INFO, "%s: AX206DPF initialized (%dx%d).\n", config->name.c_str(), width, height);
+ return 0;
+}
+
+int cDriverAX206DPF::DeInit(void)
+{
+ dpf_close(dpfh);
+
+ // free lcd array
+ if (LCD)
+ {
+ free(LCD);
+ }
+
+ return 0;
+}
+
+void cDriverAX206DPF::ResetMinMax(void)
+{
+ miny = dpfh->height - 1;
+ maxy = 0;
+}
+
+int cDriverAX206DPF::CheckSetup(void)
+{
+ if (config->width != oldConfig->width ||
+ config->height != oldConfig->height)
+ {
+ DeInit();
+ Init();
+ return 0;
+ }
+
+ if (config->brightness != oldConfig->brightness)
+ {
+ oldConfig->brightness = config->brightness;
+ SetBrightness(config->brightness);
+ }
+
+ if (config->upsideDown != oldConfig->upsideDown ||
+ config->invert != oldConfig->invert)
+ {
+ oldConfig->upsideDown = config->upsideDown;
+ oldConfig->invert = config->invert;
+ return 1;
+ }
+ return 0;
+}
+
+void cDriverAX206DPF::Clear(void)
+{
+ memset(LCD, 0, dpfh->height * dpfh->width * dpfh->bpp); //Black
+ miny = 0;
+ maxy = dpfh->height - 1;
+}
+
+#define _RGB565_0(p) \
+ (( ((p >> 16) & 0xf8) ) | (((p >> 8) & 0xe0) >> 5))
+#define _RGB565_1(p) \
+ (( ((p >> 8) & 0x1c) << 3 ) | (((p) & 0xf8) >> 3))
+
+void cDriverAX206DPF::SetPixel(int x, int y, uint32_t data)
+{
+ bool flip = config->upsideDown;
+ if (!isPortrait && rotate90)
+ flip = !flip;
+
+ if (flip)
+ {
+ // upside down orientation
+ x = width - 1 - x;
+ y = height - 1 - y;
+ }
+
+ unsigned int i;
+ if (rotate90)
+ {
+ // wrong Orientation, rotate
+ int xn = y;
+ y = dpfh->height - 1 - x;
+ x = xn;
+ }
+
+ if (x >= ((int) dpfh->width / zoom) || y >= ((int) dpfh->height / zoom))
+ return;
+
+ y *= zoom;
+ if (zoom == 1)
+ {
+ i = (y * dpfh->width + x) * dpfh->bpp;
+ LCD[i] = _RGB565_0(data);
+ LCD[i+1] = _RGB565_1(data);
+ }
+ else
+ {
+ for (int dy = 0; dy < zoom; dy++)
+ {
+ i = ((y + dy) * dpfh->width + (x * zoom)) * dpfh->bpp;
+ for (int dx = 0; dx < zoom * dpfh->bpp; dx += dpfh->bpp)
+ {
+ LCD[i+dx] = _RGB565_0(data);
+ LCD[i+dx+1] = _RGB565_1(data);
+ }
+ }
+ }
+ if (y * zoom < miny) miny = y;
+ if (y * zoom > maxy) maxy = y;
+}
+
+void cDriverAX206DPF::Refresh(bool refreshAll)
+{
+
+ if (CheckSetup() > 0)
+ refreshAll = true;
+
+ short rect[4];
+
+ if (!refreshAll)
+ {
+ rect[0] = 0; rect[1] = miny;
+ rect[2] = dpfh-> width; rect[3] = maxy + 1;
+ }
+ else
+ {
+ rect[0] = 0; rect[1] = 0;
+ rect[2] = dpfh->width; rect[3] = dpfh->height;
+ }
+
+ if (rect[1] > rect[3])
+ return;
+
+ dpf_screen_blit(dpfh, &LCD[rect[1] * dpfh->width * dpfh->bpp], rect);
+ ResetMinMax();
+}
+
+GLCD::cColor cDriverAX206DPF::GetBackgroundColor(void)
+{
+ return GLCD::cColor::Black;
+}
+
+/* NOT WORKING - WILL FREEZE THE DISPLAY FROM TIME TO TIME!
+void cDriverAX206DPF::SetBrightness(unsigned int percent)
+{
+ LIBDPF::DPFValue val;
+ val.type = LIBDPF::TYPE_INTEGER;
+
+ // Brightness can be 0 .. 7
+ if (percent == 0)
+ val.value.integer = 0;
+ else if (percent >= 100)
+ val.value.integer = 7;
+ else
+ val.value.integer = (((percent * 10) + 167) * 6) / 1000;
+ dpf_setproperty(dpfh, PROPERTY_BRIGHTNESS, &val);
+}
+*/
+
+bool cDriverAX206DPF::GetDriverFeature(const std::string & Feature, int & value)
+{
+ if (strcasecmp(Feature.c_str(), "depth") == 0) {
+ value = 16;
+ return true;
+ } else if (strcasecmp(Feature.c_str(), "ismonochrome") == 0) {
+ value = false;
+ return true;
+ } else if (strcasecmp(Feature.c_str(), "isgreyscale") == 0 || strcasecmp(Feature.c_str(), "isgrayscale") == 0) {
+ value = false;
+ return true;
+ } else if (strcasecmp(Feature.c_str(), "iscolour") == 0 || strcasecmp(Feature.c_str(), "iscolor") == 0) {
+ value = true;
+ return true;
+ } else if (strcasecmp(Feature.c_str(), "touch") == 0 || strcasecmp(Feature.c_str(), "touchscreen") == 0) {
+ value = false;
+ return true;
+ }
+ value = 0;
+ return false;
+}
+
+} // end of namespace GLCD
+
+//##########################################################################################
+//
+// ** START OF UGLY HACK ** START OF UGLY HACK ** START OF UGLY HACK ** START OF UGLY HACK *
+//
+// Because I choose NOT to include the static library libdpf.a and/or their header- and
+// source-files from the original dpf-ax hack, I did some creative copy & paste from there
+// to this place. I will delete this stuff when a usable shared library of libpdf exists.
+//
+//##########################################################################################
+
+namespace LIBDPF
+{
+// -------------------------------------------------------------------
+// START SELECTIVE COPY & PASTE "dpflib.c"
+// -------------------------------------------------------------------
+/** 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.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <sys/ioctl.h>
+
+/** 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
+};
+
+int wrap_scsi(DPFContext *h, unsigned char *cmd, int cmdlen, char out,
+ unsigned char *data, unsigned long block_len)
+{
+ int error;
+ //if (h->mode == MODE_USB) {
+ error = emulate_scsi(h->dev.udev, cmd, cmdlen, out, data, block_len);
+ //} else {
+ // error = do_scsi(h->dev.fd, cmd, cmdlen, out, data, block_len);
+ //}
+ return error;
+}
+
+static
+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;
+}
+
+
+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';
+ u = dpf_usb_open(i);
+ if (!u) return DEVERR_OPEN;
+ //i = MODE_USB;
+ } else {
+ return DEVERR_OPEN;
+ }
+ //} 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;
+
+ //if (dpf->mode == MODE_USB) {
+ dpf->dev.udev = u;
+ error = probe(dpf);
+ fprintf(stderr, "Got LCD dimensions: %dx%d\n", dpf->width, dpf->height);
+ //} else {
+ // dpf->dev.fd = fd;
+ //}
+
+ *h = dpf;
+ return error;
+}
+
+void dpf_close(DPFContext *h)
+{
+ //switch (h->mode) {
+ // 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";
+ default: return "Unknown error";
+ }
+}
+
+#define RGB565_0(r, g, b) \
+ (( ((r) & 0xf8) ) | (((g) & 0xe0) >> 5))
+#define RGB565_1(r, g, b) \
+ (( ((g) & 0x1c) << 3 ) | (((b) & 0xf8) >> 3))
+
+int dpf_setcol(DPFContext *h, const unsigned char *rgb)
+{
+ unsigned char *cmd = g_excmd;
+
+ 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;
+
+ 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;
+
+ 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);
+}
+
+// -------------------------------------------------------------------
+// END SELECTIVE COPY & PASTE "dpflib.c"
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+// START SELECTIVE COPY & PASTE "rawusb.c"
+// -------------------------------------------------------------------
+
+/* 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.
+ */
+
+#define ENDPT_OUT 1
+#define ENDPT_IN 0x81
+
+struct known_device {
+ const char *desc;
+ unsigned short vid;
+ unsigned short pid;
+} g_known_devices[] = {
+ { "AX206 DPF", 0x1908, 0x0102 },
+ { 0 , 0, 0 } /* NEVER REMOVE THIS */
+};
+
+int handle_error(const 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("%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 != (int) block_len) {
+ perror("bulk write");
+ return ret;
+ }
+ }
+ } else if (data) {
+ ret = usb_bulk_read(dev, ENDPT_IN, (char *) data, block_len, 4000);
+ if (ret != (int) 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];
+}
+
+usb_dev_handle *dpf_usb_open(int index)
+{
+ struct usb_device *d;
+ usb_dev_handle *usb_dev;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ d = find_dev(index);
+ if (!d) {
+ handle_error("No matching USB device found!");
+ return NULL;
+ }
+
+ usb_dev = usb_open(d);
+ if (usb_dev == NULL) {
+ handle_error("Failed to open usb device!");
+ return NULL;
+ }
+ usb_claim_interface(usb_dev, 0);
+ return usb_dev;
+}
+
+// -------------------------------------------------------------------
+// END SELECTIVE COPY & PASTE "rawusb.c"
+// -------------------------------------------------------------------
+
+
+} // end of namespace LIBDPF
+
+//##########################################################################################
+// ** END OF UGLY HACK ** END OF UGLY HACK ** END OF UGLY HACK ** END OF UGLY HACK *
+//##########################################################################################
diff --git a/glcddrivers/ax206dpf.h b/glcddrivers/ax206dpf.h
new file mode 100644
index 0000000..1446924
--- /dev/null
+++ b/glcddrivers/ax206dpf.h
@@ -0,0 +1,267 @@
+/*
+ * GraphLCD driver library
+ *
+ * ax206dpf.h - AX206dpf driver class
+ * Output goes to AX 206 based photoframe
+ * based on:
+ * simlcd device
+ * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
+ * (c) 2011 Dirk Heiser
+ * (c) 2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
+ *
+ * includes code from:
+ * http://sourceforge.net/projects/dpf-ax/
+ *
+ * Original copyright:
+ *
+ * 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>
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * (c) 2011 Lutz Neumann <superelchi AT wolke7.de>
+ *
+ * HISTORY
+ *
+ * v0.1 - 10 Aug 2011 - Inital release
+ */
+
+#ifndef _GLCDDRIVERS_AX206DPF_H_
+#define _GLCDDRIVERS_AX206DPF_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+
+class cDriverAX206DPF : public cDriver
+{
+private:
+ unsigned char * LCD;
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+
+ int zoom;
+ bool isPortrait;
+ bool rotate90;
+ int miny, maxy;
+
+ int CheckSetup();
+ void ResetMinMax();
+
+public:
+ cDriverAX206DPF(cDriverConfig * config);
+ virtual ~cDriverAX206DPF();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ virtual void SetPixel(int x, int y, uint32_t data);
+ virtual void Refresh(bool refreshAll = false);
+ virtual GLCD::cColor GetBackgroundColor(void);
+ //virtual void SetBrightness(unsigned int);
+ virtual bool GetDriverFeature (const std::string & Feature, int & value);
+};
+
+} // end of namespace GLCD
+
+
+//##########################################################################################
+//
+// ** START OF UGLY HACK ** START OF UGLY HACK ** START OF UGLY HACK ** START OF UGLY HACK *
+//
+// Because I choose NOT to include the static library libdpf.a and/or their header- and
+// source-files from the original dpf-ax hack, I did some creative copy & paste from there
+// to this place. I will delete this stuff when a usable shared library of libpdf exists.
+//
+//##########################################################################################
+
+// -------------------------------------------------------------------
+// START SELECTIVE COPY & PASTE "dpf.h"
+// -------------------------------------------------------------------
+
+/** libdpf header file
+ *
+ * (c) 2010, 2011 <hackfin@section5.ch>
+ *
+ */
+
+// -------------------------------------------------------------------
+// START SELECTIVE COPY & PASTE "usbuser.h"
+// -------------------------------------------------------------------
+
+#include <usb.h>
+
+namespace LIBDPF
+{
+
+/* 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
+
+// -------------------------------------------------------------------
+// END SELECTIVE COPY & PASTE "usbuser.h"
+// -------------------------------------------------------------------
+
+#define ADDR unsigned int
+
+//#define MODE_SG 0x00 ///< generic device mode (original)
+//#define MODE_USB 0x01 ///< libusb operation mode (hacked)
+#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,
+};
+
+/** The DPF context structure */
+
+typedef
+struct dpf_context {
+ unsigned char mode;
+ unsigned char flags;
+ union {
+ usb_dev_handle *udev;
+ int fd;
+ } dev;
+ 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,
+};
+
+#define DPFHANDLE struct dpf_context *
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ 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);
+
+/** 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:
+usb_dev_handle *dpf_usb_open(int index);
+int sgdev_open(const char *portname, int *fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+// 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
+
+// -------------------------------------------------------------------
+// END SELECTIVE COPY & PASTE "dpf.h"
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+// START SELECTIVE COPY & PASTE "sglib.h"
+// -------------------------------------------------------------------
+
+/* generic SCSI device stuff: */
+
+#define DIR_IN 0
+#define DIR_OUT 1
+
+// -------------------------------------------------------------------
+// END SELECTIVE COPY & PASTE "sglib.h"
+// -------------------------------------------------------------------
+
+} // end of namespace LIBDPF_HACK
+
+//##########################################################################################
+// ** END OF UGLY HACK ** END OF UGLY HACK ** END OF UGLY HACK ** END OF UGLY HACK *
+//##########################################################################################
+
+#endif //_GLCDDRIVERS_AX206DPF_H_
diff --git a/glcddrivers/drivers.c b/glcddrivers/drivers.c
index 08149df..a0e5ce0 100644
--- a/glcddrivers/drivers.c
+++ b/glcddrivers/drivers.c
@@ -30,6 +30,9 @@
#include "dm140gink.h"
#include "serdisp.h"
#include "g15daemon.h"
+#ifdef HAVE_AX206DPF_EXPERIMENTAL
+#include "ax206dpf.h"
+#endif
namespace GLCD
{
@@ -54,6 +57,9 @@ tDriver drivers[] =
{"dm140gink", kDriverDM140GINK},
{"serdisp", kDriverSerDisp},
{"g15daemon", kDriverG15daemon},
+#ifdef HAVE_AX206DPF_EXPERIMENTAL
+ {"ax206dpf", kDriverAX206DPF},
+#endif
{"", kDriverUnknown}
};
@@ -112,6 +118,10 @@ cDriver * CreateDriver(int driverID, cDriverConfig * config)
return new cDriverSerDisp(config);
case kDriverG15daemon:
return new cDriverG15daemon(config);
+#ifdef HAVE_AX206DPF_EXPERIMENTAL
+ case kDriverAX206DPF:
+ return new cDriverAX206DPF(config);
+#endif
case kDriverUnknown:
default:
return NULL;
diff --git a/glcddrivers/drivers.h b/glcddrivers/drivers.h
index 08054ec..e93b968 100644
--- a/glcddrivers/drivers.h
+++ b/glcddrivers/drivers.h
@@ -40,6 +40,9 @@ enum eDriver
kDriverNetwork = 14,
kDriverGU126X64D_K610A4 = 15,
kDriverDM140GINK = 16,
+#ifdef HAVE_AX206DPF_EXPERIMENTAL
+ kDriverAX206DPF = 17,
+#endif
kDriverSerDisp = 100,
kDriverG15daemon = 200
};
diff --git a/graphlcd.conf b/graphlcd.conf
index 2b0e784..027e6f4 100644
--- a/graphlcd.conf
+++ b/graphlcd.conf
@@ -76,7 +76,7 @@ WaitPriority=0
# Brightness
# Sets the brightness of your display's backlight if supported by its
# driver.
-# Supported by: gu140x32f, gu256x64-372, gu256x64-3900, gu126x64D-K610A4
+# Supported by: gu140x32f, gu256x64-372, gu256x64-3900, gu126x64D-K610A4, ax206dpf
# Possible values: 0 <= x <= 100)
# Default value: 100
#
@@ -560,3 +560,40 @@ Driver=dm140gink
# USB ID activy 5xx:
#Vendor=0x1509
#Product=0x925d
+########################################################################
+
+[ax206dpf]
+# THIS IS AN EXPERIMENTAL DRIVER!
+# You have to uncomment the variable HAVE_AX206DPF_EXPERIMENTAL
+# in Make.config to use this driver.
+# READ the READDME.ax206dpf before use!
+#
+# ax206dpf driver
+# This is a driver module for an AX 206 based hacked photoframe.
+#
+# Default size: 320 x 240 or 240 x 320 (see "Portrait")
+Driver=ax206dpf
+#Width=320
+#Height=240
+#UpsideDown=no
+#
+#
+# Device
+# Selects a specific display
+# 'dpf0' = first detected display, 'dpf1' = second detected display, ...
+# Default value: 'dpf0'
+#Device=dpf0
+#
+# Portrait
+# Select portrait or landscape mode
+# Rotate display output by 90 degrees if necessary
+# Possible values: 'yes' -> default size = 240 x 320
+# 'no' -> default size = 320 x 240
+# Default value: 'no'
+#Portrait=no
+#
+# Zoom
+# Determines if pixels should be magnified.
+# Possible values: 1, 2, 3, 4
+# Default value: 1
+#Zoom=1