aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2013-11-13 17:35:20 +1000
committerinmarket <andrewh@inmarket.com.au>2013-11-13 17:35:20 +1000
commite1721a922627830e42618e1dd30db8cd418059cc (patch)
tree66daed50c092600f328e87b02da6914a82c0955c /drivers
parentbca78196f544f0548f17afb081eed9dea2b4856b (diff)
downloaduGFX-e1721a922627830e42618e1dd30db8cd418059cc.tar.gz
uGFX-e1721a922627830e42618e1dd30db8cd418059cc.tar.bz2
uGFX-e1721a922627830e42618e1dd30db8cd418059cc.zip
First version of a network display driver (the display is somewhere on the network rather than attached locally).
A remote display application is still to be written (coming soon). Note: the remote display initiates the connection to the headless device rather than the headless device making the connection to the display.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/multiple/uGFXnet/gdisp_lld.mk2
-rw-r--r--drivers/multiple/uGFXnet/gdisp_lld_config.h42
-rw-r--r--drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c509
-rw-r--r--drivers/multiple/uGFXnet/ginput_lld_mouse_config.h50
-rw-r--r--drivers/multiple/uGFXnet/readme.txt19
5 files changed, 622 insertions, 0 deletions
diff --git a/drivers/multiple/uGFXnet/gdisp_lld.mk b/drivers/multiple/uGFXnet/gdisp_lld.mk
new file mode 100644
index 00000000..89bd7cf2
--- /dev/null
+++ b/drivers/multiple/uGFXnet/gdisp_lld.mk
@@ -0,0 +1,2 @@
+GFXINC += $(GFXLIB)/drivers/multiple/uGFXnet
+GFXSRC += $(GFXLIB)/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c
diff --git a/drivers/multiple/uGFXnet/gdisp_lld_config.h b/drivers/multiple/uGFXnet/gdisp_lld_config.h
new file mode 100644
index 00000000..9a09d534
--- /dev/null
+++ b/drivers/multiple/uGFXnet/gdisp_lld_config.h
@@ -0,0 +1,42 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file drivers/multiple/Win32/gdisp_lld_config.h
+ * @brief GDISP Graphic Driver subsystem low level driver header for Win32.
+ *
+ * @addtogroup GDISP
+ * @{
+ */
+
+#ifndef _GDISP_LLD_CONFIG_H
+#define _GDISP_LLD_CONFIG_H
+
+#if GFX_USE_GDISP
+
+/*===========================================================================*/
+/* Driver hardware support. */
+/*===========================================================================*/
+
+// Calling gdispGFlush() is optional for this driver but can be used by the
+// application to force a display update. eg after streaming.
+
+#define GDISP_HARDWARE_FLUSH TRUE
+#define GDISP_HARDWARE_DRAWPIXEL TRUE
+#define GDISP_HARDWARE_FILLS TRUE
+#define GDISP_HARDWARE_BITFILLS TRUE
+#define GDISP_HARDWARE_PIXELREAD TRUE
+#define GDISP_HARDWARE_SCROLL TRUE
+#define GDISP_HARDWARE_CONTROL TRUE
+
+#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565
+
+#endif /* GFX_USE_GDISP */
+
+#endif /* _GDISP_LLD_CONFIG_H */
+/** @} */
+
diff --git a/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c b/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c
new file mode 100644
index 00000000..96bb6d8d
--- /dev/null
+++ b/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c
@@ -0,0 +1,509 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file drivers/multiple/Win32/gdisp_lld.c
+ * @brief GDISP Graphics Driver subsystem low level driver source for uGFX network display.
+ */
+#include "gfx.h"
+
+#if GFX_USE_GDISP
+
+#define GDISP_DRIVER_VMT GDISPVMT_uGFXnet
+#include "../drivers/multiple/uGFXnet/gdisp_lld_config.h"
+#include "gdisp/lld/gdisp_lld.h"
+
+#ifndef GDISP_SCREEN_WIDTH
+ #define GDISP_SCREEN_WIDTH 640
+#endif
+#ifndef GDISP_SCREEN_HEIGHT
+ #define GDISP_SCREEN_HEIGHT 480
+#endif
+#ifndef GDISP_GFXNET_PORT
+ #define GDISP_GFXNET_PORT 13001
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(WIN32) || GFX_USE_OS_WIN32
+ #include <winsock.h>
+#else
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
+
+ #define closesocket(fd) close(fd)
+ #define ioctlsocket(fd,cmd,arg) ioctl(fd,cmd,arg)
+ #ifndef SOCKET
+ #define SOCKET int
+ #endif
+#endif
+
+#define GDISP_FLG_HASMOUSE (GDISP_FLG_DRIVER<<0)
+#define GDISP_FLG_CONNECTED (GDISP_FLG_DRIVER<<1)
+#define GDISP_FLG_HAVEDATA (GDISP_FLG_DRIVER<<2)
+
+#if GINPUT_NEED_MOUSE
+ /* Include mouse support code */
+ #include "ginput/lld/mouse.h"
+#endif
+
+/*===========================================================================*/
+/* Driver local routines . */
+/*===========================================================================*/
+
+// All commands are sent in 16 bit blocks (2 bytes) in network order (BigEndian)
+#define GNETCODE_INIT 0xFFFF // Followed by version,width,height,pixelformat,hasmouse
+#define GNETCODE_FLUSH 0x0000 // No following data
+#define GNETCODE_PIXEL 0x0001 // Followed by x,y,color
+#define GNETCODE_FILL 0x0002 // Followed by x,y,cx,cy,color
+#define GNETCODE_BLIT 0x0003 // Followed by x,y,cx,cy,bits
+#define GNETCODE_READ 0x0004 // Followed by x,y - Response is 0x0004,color
+#define GNETCODE_SCROLL 0x0005 // Followed by x,y,cx,cy,lines
+#define GNETCODE_CONTROL 0x0006 // Followed by what,data - Response is 0x0006,0x0000 (fail) or 0x0006,0x0001 (success)
+#define GNETCODE_MOUSE_X 0x0007 // This is only ever received - never sent. Response is 0x0007,x
+#define GNETCODE_MOUSE_Y 0x0008 // This is only ever received - never sent. Response is 0x0008,y
+#define GNETCODE_MOUSE_B 0x0009 // This is only ever received - never sent. Response is 0x0009,buttons
+
+#define GNETCODE_VERSION 0x0100 // V1.0
+
+typedef struct netPriv {
+ SOCKET netfd; // The current socket
+ unsigned databytes; // How many bytes have been read
+ uint16_t data[2]; // Buffer for storing data read.
+ #if GINPUT_NEED_MOUSE
+ coord_t mousex, mousey;
+ uint16_t mousebuttons;
+ #endif
+} netPriv;
+
+static gfxThreadHandle hThread;
+static GDisplay * mouseDisplay;
+
+static DECLARE_THREAD_STACK(waNetThread, 256);
+static DECLARE_THREAD_FUNCTION(NetThread, param) {
+ SOCKET listenfd, fdmax, i, clientfd;
+ int len;
+ unsigned disp;
+ fd_set master, read_fds;
+ struct sockaddr_in serv_addr;
+ struct sockaddr_in clientaddr;
+ GDisplay * g;
+ netPriv * priv;
+ (void)param;
+
+ /* clear the master and temp sets */
+ FD_ZERO(&master);
+ FD_ZERO(&read_fds);
+
+ if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == (SOCKET)-1)
+ gfxHalt("GDISP: uGFXnet - Socket failed");
+
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_port = htons(GDISP_GFXNET_PORT);
+
+ if (bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
+ gfxHalt("GDISP: uGFXnet - Bind failed");
+
+ if (listen(listenfd, 10) == -1)
+ gfxHalt("GDISP: uGFXnet - Listen failed");
+
+
+ /* add the listener to the master set */
+ FD_SET(listenfd, &master);
+
+ /* keep track of the biggest file descriptor */
+ fdmax = listenfd; /* so far, it's this one*/
+
+ /* loop */
+ for(;;) {
+ /* copy it */
+ read_fds = master;
+ if (select(fdmax+1, &read_fds, 0, 0, 0) == -1)
+ gfxHalt("GDISP: uGFXnet - Select failed");
+
+ // Run through the existing connections looking for data to be read
+ for(i = 0; i <= fdmax; i++) {
+ if(!FD_ISSET(i, &read_fds))
+ continue;
+
+ // Handle new connections
+ if(i == listenfd) {
+ len = sizeof(clientaddr);
+ if((clientfd = accept(listenfd, (struct sockaddr *)&clientaddr, &len)) == (SOCKET)-1)
+ gfxHalt("GDISP: uGFXnet - Accept failed");
+
+ // Look for a display that isn't connected
+ for(disp = 0; disp < GDISP_TOTAL_DISPLAYS; disp++) {
+ if (!(g = gdispGetDisplay(disp)))
+ continue;
+ #if GDISP_TOTAL_CONTROLLERS > 1
+ // Ignore displays for other controllers
+ if (g->vmt != &GDISPVMT_uGFXnet)
+ continue;
+ #endif
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ break;
+ }
+
+ // Was anything found?
+ if (disp >= GDISP_TOTAL_DISPLAYS) {
+ // No Just close the connection
+ closesocket(clientfd);
+ //printf(New connection from %s on socket %d rejected as all displays are already connected\n", inet_ntoa(clientaddr.sin_addr), clientfd);
+ continue;
+ }
+
+ // Save the descriptor
+ FD_SET(clientfd, &master);
+ if (clientfd > fdmax) fdmax = clientfd;
+ priv = g->priv;
+ memset(priv, 0, sizeof(netPriv));
+ priv->netfd = clientfd;
+ g->flags |= GDISP_FLG_CONNECTED;
+ //printf(New connection from %s on socket %d allocated to display %u\n", inet_ntoa(clientaddr.sin_addr), clientfd, disp+1);
+
+ // Send the initialisation data (2 words at a time)
+ priv->data[0] = htons(GNETCODE_INIT);
+ priv->data[1] = htons(GNETCODE_VERSION);
+ send(clientfd, (const char *)priv->data, 4, 0);
+ priv->data[0] = htons(GDISP_SCREEN_WIDTH);
+ priv->data[1] = htons(GDISP_SCREEN_HEIGHT);
+ send(clientfd, (const char *)priv->data, 4, 0);
+ priv->data[0] = htons(GDISP_LLD_PIXELFORMAT);
+ priv->data[1] = htons((g->flags & GDISP_FLG_HASMOUSE) ? 1 : 0);
+ send(clientfd, (const char *)priv->data, 4, 0);
+ continue;
+ }
+
+ // Handle data from a client
+
+ // Look for a display that is connected and the socket descriptor matches
+ for(disp = 0; disp < GDISP_TOTAL_DISPLAYS; disp++) {
+ if (!(g = gdispGetDisplay(disp)))
+ continue;
+ #if GDISP_TOTAL_CONTROLLERS > 1
+ // Ignore displays for other controllers
+ if (g->vmt != &GDISPVMT_uGFXnet)
+ continue;
+ #endif
+ priv = g->priv;
+ if ((g->flags & GDISP_FLG_CONNECTED) && priv->netfd == i)
+ break;
+ }
+ if (disp >= GDISP_TOTAL_DISPLAYS)
+ gfxHalt("GDISP: uGFXnet - Got data from unrecognized connection");
+
+ if ((g->flags & GDISP_FLG_HAVEDATA)) {
+ // The higher level is still processing the previous data.
+ // Give it a chance to run by coming back to this data.
+ gfxSleepMilliseconds(1);
+ continue;
+ }
+
+ /* handle data from a client */
+ if ((len = recv(i, ((char *)priv->data)+priv->databytes, sizeof(priv->data)-priv->databytes, 0)) <= 0) {
+ // Socket closed or in error state
+ g->flags &= ~GDISP_FLG_CONNECTED;
+ memset(priv, 0, sizeof(netPriv));
+ closesocket(i);
+ FD_CLR(i, &master);
+ continue;
+ }
+
+ // Do we have a full reply yet
+ if (priv->databytes < sizeof(priv->data))
+ continue;
+
+ // Process the data received
+ switch(priv->data[0]) {
+ #if GINPUT_NEED_MOUSE
+ case GNETCODE_MOUSE_X: priv->mousex = priv->data[1]; break;
+ case GNETCODE_MOUSE_Y: priv->mousey = priv->data[1]; break;
+ case GNETCODE_MOUSE_B: priv->mousebuttons = priv->data[1]; break;
+ #endif
+ case GNETCODE_CONTROL:
+ case GNETCODE_READ:
+ priv->databytes = 0;
+ g->flags |= GDISP_FLG_HAVEDATA;
+ break;
+ default:
+ // Just ignore unrecognised data
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
+ netPriv * priv;
+
+ // Initialise the receiver thread (if it hasn't been done already)
+ if (!hThread) {
+ hThread = gfxThreadCreate(waNetThread, sizeof(waNetThread), HIGH_PRIORITY, NetThread, 0);
+ gfxThreadClose(hThread);
+ }
+
+ // Only turn on mouse on the first window for now
+ #if GINPUT_NEED_MOUSE
+ if (!g->controllerdisplay) {
+ mouseDisplay = g;
+ g->flags |= GDISP_FLG_HASMOUSE;
+ }
+ #endif
+
+ // Create a private area for this window
+ if (!(priv = (netPriv *)gfxAlloc(sizeof(netPriv))))
+ gfxHalt("GDISP: uGFXnet - Memory allocation failed");
+ memset(priv, 0, sizeof(netPriv));
+ g->priv = priv;
+ g->board = 0; // no board interface for this controller
+
+ // Initialise the GDISP structure
+ g->g.Orientation = GDISP_ROTATE_0;
+ g->g.Powermode = powerOn;
+ g->g.Backlight = 100;
+ g->g.Contrast = 50;
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+
+ return TRUE;
+}
+
+#if GDISP_HARDWARE_FLUSH
+ LLDSPEC void gdisp_lld_flush(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[1];
+
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+
+ priv = g->priv;
+ buf[0] = htons(GNETCODE_FLUSH);
+ send(priv->netfd, (const char *)buf, sizeof(buf), 0);
+ }
+#endif
+
+#if GDISP_HARDWARE_DRAWPIXEL
+ LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[4];
+
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+
+ priv = g->priv;
+ buf[0] = htons(GNETCODE_PIXEL);
+ buf[1] = htons(g->p.x);
+ buf[2] = htons(g->p.y);
+ buf[3] = htons(COLOR2NATIVE(g->p.color));
+ send(priv->netfd, (const char *)buf, sizeof(buf), 0);
+ }
+#endif
+
+/* ---- Optional Routines ---- */
+
+#if GDISP_HARDWARE_FILLS
+ LLDSPEC void gdisp_lld_fill_area(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[6];
+
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+
+ priv = g->priv;
+ buf[0] = htons(GNETCODE_FILL);
+ buf[1] = htons(g->p.x);
+ buf[2] = htons(g->p.y);
+ buf[3] = htons(g->p.cx);
+ buf[4] = htons(g->p.cy);
+ buf[5] = htons(COLOR2NATIVE(g->p.color));
+ send(priv->netfd, (const char *)buf, sizeof(buf), 0);
+ }
+#endif
+
+#if GDISP_HARDWARE_BITFILLS
+ LLDSPEC void gdisp_lld_blit_area(GDisplay *g) {
+ netPriv * priv;
+ pixel_t * buffer;
+ uint16_t buf[5];
+ coord_t x, y;
+
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+
+ // Make everything relative to the start of the line
+ buffer = g->p.ptr;
+ buffer += g->p.x2*g->p.y1;
+
+ priv = g->priv;
+ buf[0] = htons(GNETCODE_BLIT);
+ buf[1] = htons(g->p.x);
+ buf[2] = htons(g->p.y);
+ buf[3] = htons(g->p.cx);
+ buf[4] = htons(g->p.cy);
+ send(priv->netfd, (const char *)buf, sizeof(buf), 0);
+
+ for(y = 0; y < g->p.cy; y++, buffer += g->p.x2 - g->p.cx) {
+ for(x = 0; x < g->p.cx; x++, buffer++) {
+ buf[0] = COLOR2NATIVE(buffer[0]);
+ send(priv->netfd, (const char *)buf, sizeof(buf[0]), 0);
+ }
+ }
+ }
+#endif
+
+#if GDISP_HARDWARE_PIXELREAD
+ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[3];
+ color_t data;
+
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return 0;
+
+ priv = g->priv;
+ buf[0] = htons(GNETCODE_READ);
+ buf[1] = htons(g->p.x);
+ buf[2] = htons(g->p.y);
+ send(priv->netfd, (const char *)buf, sizeof(buf), 0);
+
+ // Now wait for a reply
+ while(!(g->flags & GDISP_FLG_HAVEDATA) || priv->data[0] != GNETCODE_READ)
+ gfxSleepMilliseconds(1);
+
+ data = NATIVE2COLOR(priv->data[1]);
+ g->flags &= ~GDISP_FLG_HAVEDATA;
+
+ return data;
+ }
+#endif
+
+#if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL
+ LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[6];
+
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+
+ priv = g->priv;
+ buf[0] = htons(GNETCODE_FILL);
+ buf[1] = htons(g->p.x);
+ buf[2] = htons(g->p.y);
+ buf[3] = htons(g->p.cx);
+ buf[4] = htons(g->p.cy);
+ buf[5] = htons(g->p.y1);
+ send(priv->netfd, (const char *)buf, sizeof(buf), 0);
+ }
+#endif
+
+#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
+ LLDSPEC void gdisp_lld_control(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[3];
+ bool_t allgood;
+
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+
+ // Check if we might support the code
+ switch(g->p.x) {
+ case GDISP_CONTROL_ORIENTATION:
+ if (g->g.Orientation == (orientation_t)g->p.ptr)
+ return;
+ break;
+ case GDISP_CONTROL_POWER:
+ if (g->g.Powermode == (powermode_t)g->p.ptr)
+ return;
+ break;
+ case GDISP_CONTROL_BACKLIGHT:
+ if (g->g.Backlight == (uint16_t)(int)g->p.ptr)
+ return;
+ if ((uint16_t)(int)g->p.ptr > 100)
+ g->p.ptr = (void *)100;
+ break;
+ default:
+ return;
+ }
+
+ // Send the command
+ priv = g->priv;
+ buf[0] = htons(GNETCODE_CONTROL);
+ buf[1] = htons(g->p.x);
+ buf[2] = htons((uint16_t)(int)g->p.ptr);
+ send(priv->netfd, (const char *)buf, sizeof(buf), 0);
+
+ // Now wait for a reply
+ while(!(g->flags & GDISP_FLG_HAVEDATA) || priv->data[0] != GNETCODE_CONTROL)
+ gfxSleepMilliseconds(1);
+
+ // Extract the return status
+ allgood = priv->data[1] ? TRUE : FALSE;
+ g->flags &= ~GDISP_FLG_HAVEDATA;
+
+ // Do nothing more if the operation failed
+ if (!allgood) return;
+
+ // Update the local stuff
+ switch(g->p.x) {
+ case GDISP_CONTROL_ORIENTATION:
+ switch((orientation_t)g->p.ptr) {
+ case GDISP_ROTATE_0:
+ case GDISP_ROTATE_180:
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+ break;
+ case GDISP_ROTATE_90:
+ case GDISP_ROTATE_270:
+ g->g.Height = GDISP_SCREEN_WIDTH;
+ g->g.Width = GDISP_SCREEN_HEIGHT;
+ break;
+ default:
+ return;
+ }
+ g->g.Orientation = (orientation_t)g->p.ptr;
+ break;
+ case GDISP_CONTROL_POWER:
+ g->g.Powermode = (powermode_t)g->p.ptr;
+ break;
+ case GDISP_CONTROL_BACKLIGHT:
+ g->g.Backlight = (uint16_t)(int)g->p.ptr;
+ break;
+ }
+ }
+#endif
+
+#if GINPUT_NEED_MOUSE
+ void ginput_lld_mouse_init(void) {}
+ void ginput_lld_mouse_get_reading(MouseReading *pt) {
+ GDisplay * g;
+ netPriv * priv;
+
+ g = mouseDisplay;
+ priv = g->priv;
+
+ pt->x = priv->mousex;
+ pt->y = priv->mousey;
+ pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0;
+ pt->buttons = priv->mousebuttons;
+ }
+#endif /* GINPUT_NEED_MOUSE */
+
+#endif /* GFX_USE_GDISP */
+
diff --git a/drivers/multiple/uGFXnet/ginput_lld_mouse_config.h b/drivers/multiple/uGFXnet/ginput_lld_mouse_config.h
new file mode 100644
index 00000000..a58d92d1
--- /dev/null
+++ b/drivers/multiple/uGFXnet/ginput_lld_mouse_config.h
@@ -0,0 +1,50 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file drivers/multiple/Win32/ginput_lld_mouse_config.h
+ * @brief GINPUT LLD header file for mouse/touch driver.
+ *
+ * @defgroup Mouse Mouse
+ * @ingroup GINPUT
+ *
+ * @{
+ */
+
+#ifndef _LLD_GINPUT_MOUSE_CONFIG_H
+#define _LLD_GINPUT_MOUSE_CONFIG_H
+
+// This driver supports being both a mouse or a touch device (we don't actually know which it really is)
+// When operating in mouse mode a long left button click does not generate a context click.
+// When operating in touch mode we allow sloppier clicks etc
+#if 1
+ #define GINPUT_MOUSE_EVENT_TYPE GEVENT_MOUSE
+ #define GINPUT_MOUSE_CLICK_TIME TIME_INFINITE // Long click != Context Click
+ #define GINPUT_MOUSE_NEED_CALIBRATION FALSE
+ #define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE
+ #define GINPUT_MOUSE_READ_CYCLES 1
+ #define GINPUT_MOUSE_MAX_CALIBRATION_ERROR -1
+ #define GINPUT_MOUSE_MAX_CLICK_JITTER 0
+ #define GINPUT_MOUSE_MAX_MOVE_JITTER 0
+#else
+ #define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH
+ #define GINPUT_MOUSE_CLICK_TIME 700 // Long click = Context Click
+ #define GINPUT_MOUSE_NEED_CALIBRATION FALSE // Can be set to TRUE just for testing
+ #define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE
+ #define GINPUT_MOUSE_READ_CYCLES 1
+ #define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 2
+ #define GINPUT_MOUSE_MAX_CLICK_JITTER 2
+ #define GINPUT_MOUSE_MAX_MOVE_JITTER 2
+#endif
+
+// This driver supports both an "interrupt" mode, and a polled mode
+#define GINPUT_MOUSE_POLL_PERIOD TIME_INFINITE // Interrupt driven by the Window thread
+//#define GINPUT_MOUSE_POLL_PERIOD 25 // Poll driven
+
+#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */
+/** @} */
+
diff --git a/drivers/multiple/uGFXnet/readme.txt b/drivers/multiple/uGFXnet/readme.txt
new file mode 100644
index 00000000..e1f7d0a2
--- /dev/null
+++ b/drivers/multiple/uGFXnet/readme.txt
@@ -0,0 +1,19 @@
+To use this driver:
+
+This driver is special in that it implements both the gdisp low level driver
+and a touchscreen driver.
+
+1. Add in your gfxconf.h:
+ a) #define GFX_USE_GDISP TRUE
+ b) Optionally #define GFX_USE_GINPUT TRUE
+ #define GINPUT_USE_MOUSE TRUE
+ c) Any optional high level driver defines (see gdisp.h) eg: GDISP_NEED_MULTITHREAD
+ d) Optionally the following (with appropriate values):
+ #define GDISP_SCREEN_WIDTH 640
+ #define GDISP_SCREEN_HEIGHT 480
+
+2. To your makefile add the following lines:
+ include $(GFXLIB)/gfx.mk
+ include $(GFXLIB)/drivers/multiple/uGFXnet/gdisp_lld.mk
+
+3. Make sure you have networking libraries included.