The LED extensions in the wacom kernel driver are scheduled for
inclusion into linux-3.2. This commit provides a first
demonstration on how the OLED part of new interface might be
exposed by new wacom xinput device properties.

The mechanisms for passing the OLED images from X11 client to
wacom xinput are two new device properties "Wacom OLED Pixmap"
and "Wacom OLED state". The first contains preallocated pixmaps,
one for each button with OLED display, which can be written like
normal drawables. The contents of the pixmaps propagate to the
tablet for all entries in "Wacom OLED State" which have a value
of '1' during call of XChangeDeviceProperty.

Summary of changes:
* Added new src/wcmLED.c module which contains
        * init function: wcmLedStart
                called by wcmUSB.c:wcmLedStart()
                This tries to locate the wacom_led interface in sysfs using
                libudev. When located, the pathname ist stored in the
                sysfs_led member of WacomDevicePtr.
        * destroy function: wcmLedFree
                called by wcmConfig.c:wcmFree()
                Frees the sysfs_led string.
        * button image set function: wcmSetOLEDProperty
                called by wcmXCommand.c:wcmSetProperty()

* Added set_oled_image function to xsetwacom.c.
        Contains a very simple text renderer using XDrawString.

* Added further fake symbols for "make check"

Usage Example:
Set Button text of Button 3 to 'example'
> xsetwacom --set 'Wacom Intuos4 8x13 pad' Image 3 'example'

TODO:
* Add ability to read images from files
* Add ability for more sophisticated "text layout"
* Add support for non TrueColor mode X Server
* Add function for setting luminance

Signed-off-by: Eduard Hasenleithner <edu...@hasenleithner.at>
---
 include/wacom-properties.h |   22 +++++
 man/xsetwacom.man          |    4 +
 src/common.mk              |    1 +
 src/wcmConfig.c            |    1 +
 src/wcmLED.c               |  193 ++++++++++++++++++++++++++++++++++++++++++++
 src/wcmUSB.c               |    3 +
 src/wcmXCommand.c          |   15 ++++
 src/xf86Wacom.h            |    8 ++
 src/xf86WacomDefs.h        |    8 ++
 test/fake-symbols.c        |   23 +++++
 tools/xsetwacom.c          |   89 ++++++++++++++++++++-
 11 files changed, 366 insertions(+), 1 deletions(-)
 create mode 100644 src/wcmLED.c

diff --git a/include/wacom-properties.h b/include/wacom-properties.h
index 29d5056..c6c9852 100644
--- a/include/wacom-properties.h
+++ b/include/wacom-properties.h
@@ -95,6 +95,28 @@
  */
 #define WACOM_PROP_BUTTON_ACTIONS "Wacom Button Actions"
 
+/* 8 bit, 8 values
+ * Image state for each of the 8 OLED images.
+ *  -1: Image not yet set (i.e. Pixmap content not initialized)
+ *   0: Image set once or more (i.e. Pixmap content is valid)
+ *   1: Image to be updated (this value will not appear in XGetDeviceProperty)
+ * When calling XChangeDeviceProperty, all images which are to be updated
+ * are to be marked with '1' in the state property. Within
+ * XChangeDeviceProperty the driver will immediately, set the state to '0'
+ * so that the images are not updated again on the next call to
+ * XChangeDeviceProperty.
+ */
+#define WACOM_PROP_OLED_STATE "Wacom OLED State"
+
+/* Pixmap, array of 8 Button Image IDs (PIXMAP IDs)
+ * Preallocated Pixmaps, which contain the OLED images for each of
+ * the buttons. A pixmap within this property is only valid if their
+ * respective entry in the OLED_STATE property has a value >= 0.
+ * This property is read-only! The Pixmaps must not be deleted!
+ * (The Pixmaps are writable, of course)
+ */
+#define WACOM_PROP_OLED_PIXMAP "Wacom OLED Pixmap"
+
 /* 8 bit, 2 values, priv->debugLevel and common->debugLevel. This property
  * is for use in the driver only and only enabled if --enable-debug is
  * given. No client may rely on this property being present or working.
diff --git a/man/xsetwacom.man b/man/xsetwacom.man
index dc0995f..9d2c9d2 100644
--- a/man/xsetwacom.man
+++ b/man/xsetwacom.man
@@ -208,6 +208,10 @@ tip, eraser, or touch.  The pressure levels of all tablets 
are normalized to
 parameter is independent of the PressureCurve parameter.  Default:  27,
 range of 0 to 2047.
 .TP
+\fBImage\fR button-id text
+Set the button image for button-id (0-7) to the specified text.
+Only available on the Intuos4 M, L, or XL tablets.
+.TP
 \fBToolDebugLevel\fR level
 Set the debug level for this tool to the given level. This only affects
 code paths that are specific to a given tool. A higher level means more
diff --git a/src/common.mk b/src/common.mk
index fae8d9f..464e4bd 100644
--- a/src/common.mk
+++ b/src/common.mk
@@ -10,6 +10,7 @@ DRIVER_SOURCES= \
        $(top_srcdir)/src/wcmFilter.h \
        $(top_srcdir)/src/xf86WacomDefs.h \
        $(top_srcdir)/src/wcmUSB.c \
+       $(top_srcdir)/src/wcmLED.c \
        $(top_srcdir)/src/wcmXCommand.c \
        $(top_srcdir)/src/wcmValidateDevice.c \
        $(top_srcdir)/src/wcmTouchFilter.c
diff --git a/src/wcmConfig.c b/src/wcmConfig.c
index 94b188d..bd101dc 100644
--- a/src/wcmConfig.c
+++ b/src/wcmConfig.c
@@ -125,6 +125,7 @@ static void wcmFree(InputInfoPtr pInfo)
        TimerFree(priv->serial_timer);
        free(priv->tool);
        wcmFreeCommon(&priv->common);
+       wcmLedFree(priv);
        free(priv);
 
        pInfo->private = NULL;
diff --git a/src/wcmLED.c b/src/wcmLED.c
new file mode 100644
index 0000000..dace711
--- /dev/null
+++ b/src/wcmLED.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2011 by Eduard Hasenleithner <edu...@hasenleithner.at>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <servermd.h>
+#include <libudev.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "xf86Wacom.h"
+
+static const char wacom_led_path[] = "/wacom_led";
+
+void wcmLedInitPixmap(WacomDevicePtr priv, int *values, int count)
+{
+       int i;
+       ScreenPtr pScreen = screenInfo.screens[0];
+
+       for (i = 0; i < count; i++) {
+               PixmapPtr pMap;
+               XID id;
+
+               pMap = pScreen->CreatePixmap(pScreen, 64, 32, 
pScreen->rootDepth, 0);
+               id = FakeClientID(0);
+               pMap->drawable.id = id;
+               AddResource(id, RT_PIXMAP, pMap);
+
+               values[i] = id;
+       }
+}
+
+void wcmLedStart(WacomDevicePtr priv)
+{
+       struct stat s;
+       struct udev *udev;
+       struct udev_device *device, *parent;
+
+       if (fstat(priv->pInfo->fd, &s) < 0)
+               return;
+
+       udev = udev_new();
+       device = udev_device_new_from_devnum(udev, 'c', s.st_rdev);
+       if (device)
+       {
+               parent = udev_device_get_parent_with_subsystem_devtype(
+                       device, "usb", NULL);
+               if (parent)
+               {
+                       const char *sysfs_usbdev = 
udev_device_get_syspath(parent);
+                       char *tmp;
+
+                       Xasprintf(&tmp, "%s%s", sysfs_usbdev, wacom_led_path);
+                       strcpy(tmp, sysfs_usbdev);
+                       strcat(tmp, wacom_led_path);
+                       if (stat(tmp, &s)>=0 && S_ISDIR(s.st_mode))
+                               priv->sysfs_led = tmp;
+                       else
+                               free(tmp);
+               }
+               udev_device_unref(device);
+       }
+       udev_unref(udev);
+}
+
+void wcmLedFree(WacomDevicePtr priv)
+{
+       free(priv->sysfs_led);
+       priv->sysfs_led = NULL;
+}
+
+static int led_surface_put(char *sysfs_path, int id,
+       unsigned char *src, int stride)
+{
+       char *str;
+       unsigned char img[1024];
+       int x, y, i = 0;
+       int fd;
+       int r = -1;
+
+       for (y = 0; y < 16; y++)
+       {
+               unsigned char *pixel1 = src + (1+2*y)*stride;
+               unsigned char *pixel2 = pixel1 + stride;
+
+               for (x = 0; x < 64; x++)
+               {
+                       int lum1, lum2;
+                       pixel1 -= 4;
+                       pixel2 -= 4;
+                       lum1 = pixel1[0]+pixel1[1]+pixel1[2];
+                       lum2 = pixel2[0]+pixel2[1]+pixel2[2];
+                       lum1 /= 3*16; lum2 /= 3*16;
+                       img[i++] = (lum1&0xf) | (lum2<<4);
+               }
+       }
+
+       Xasprintf(&str, "%s/button%d_rawimg", sysfs_path, id);
+       fd = open(str, O_WRONLY);
+       if (fd >= 0)
+       {
+               r = write(fd, img, sizeof(img));
+               close(fd);
+       }
+
+       free(str);
+       return r;
+}
+
+int wcmSetOLEDProperty(DeviceIntPtr dev, Atom property,
+                      XIPropertyValuePtr prop, BOOL checkonly,
+                      XIPropertyValuePtr pixmaps)
+{
+       InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
+       WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
+       DrawablePtr pDraw;
+       void *img;
+       int i, rc;
+       int stride;
+       int img_size;
+       XID *pixmap = pixmaps->data;
+       char *state = prop->data;
+
+       if (!serverClient)
+               return BadImplementation;
+       if (!priv->sysfs_led)
+               return BadAtom;
+       if (prop->type != XA_INTEGER || prop->format != 8)
+               return BadAtom;
+       if (prop->size != WCM_MAX_LED_IMAGES)
+               return BadLength;
+
+       /* ideally, 'pixmaps->type' would be 'XA_PIXMAP'.
+        * The problem is that InitWcmAtom can ony create either
+        * XA_INTEGER or XA_ATOM properties. For now, XA_ATOM
+        * has been chosen */
+       if (pixmaps->type != XA_ATOM || pixmaps->format != 32)
+               return BadPixmap;
+       if (pixmaps->size != WCM_MAX_LED_IMAGES)
+               return BadLength;
+
+       for (i = 0; i < prop->size; i++)
+       {
+               if (!pixmap[i])
+                       return BadImplementation;
+               rc = dixLookupDrawable(&pDraw, pixmap[i], serverClient, 0, 0);
+               if (rc != Success)
+                       return rc;
+               if (pDraw->width != 64 || pDraw->height != 32)
+                       return BadImplementation;
+               if (BitsPerPixel(pDraw->depth) != 32)
+                       return BadImplementation;
+       }
+       if (checkonly)
+               return Success;
+
+       stride = PixmapBytePad(pDraw->width, pDraw->depth);
+       img_size = stride * pDraw->height;
+       img = malloc(img_size);
+       for (i = 0; i < prop->size; i++)
+       {
+               /* only update images with state >= 1 */
+               if (state[i] < 1)
+                       continue;
+
+               dixLookupDrawable(&pDraw, pixmap[i], serverClient, 0, 0);
+               pDraw->pScreen->GetImage(pDraw, 0, 0, 64, 32, ZPixmap, -1, img);
+               led_surface_put(priv->sysfs_led, i, img, stride);
+               /* Set state to written */
+               state[i] = 0;
+       }
+       free(img);
+       return Success;
+}
+
+/* vim: set noexpandtab tabstop=8 shiftwidth=8: */
diff --git a/src/wcmUSB.c b/src/wcmUSB.c
index 14de990..7dd2908 100644
--- a/src/wcmUSB.c
+++ b/src/wcmUSB.c
@@ -133,6 +133,7 @@ static int
 usbStart(InputInfoPtr pInfo)
 {
        int err;
+       WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
 
 #ifdef EVIOCGRAB
        /* Try to grab the event device so that data don't leak to 
/dev/input/mice */
@@ -144,6 +145,8 @@ usbStart(InputInfoPtr pInfo)
                xf86Msg(X_ERROR, "%s: Wacom X driver can't grab event device 
(%s)\n",
                                pInfo->name, strerror(errno));
 #endif
+
+       wcmLedStart(priv);
        return Success;
 }
 
diff --git a/src/wcmXCommand.c b/src/wcmXCommand.c
index fe71bd1..71fa2cc 100644
--- a/src/wcmXCommand.c
+++ b/src/wcmXCommand.c
@@ -97,6 +97,8 @@ Atom prop_gesture_param;
 Atom prop_hover;
 Atom prop_tooltype;
 Atom prop_btnactions;
+Atom prop_oled_pixmap;
+Atom prop_oled_state;
 Atom prop_product_id;
 #ifdef DEBUG
 Atom prop_debuglevels;
@@ -220,6 +222,12 @@ void InitWcmDeviceProperties(InputInfoPtr pInfo)
        /* default to no actions */
        memset(values, 0, sizeof(values));
        prop_btnactions = InitWcmAtom(pInfo->dev, WACOM_PROP_BUTTON_ACTIONS, 
-32, WCM_MAX_MOUSE_BUTTONS, values);
+       wcmLedInitPixmap(priv, values, WCM_MAX_LED_IMAGES);
+       prop_oled_pixmap = InitWcmAtom(pInfo->dev, WACOM_PROP_OLED_PIXMAP, -32,
+                                      WCM_MAX_LED_IMAGES, values);
+       memset(values, -1, sizeof(values));
+       prop_oled_state = InitWcmAtom(pInfo->dev, WACOM_PROP_OLED_STATE, 8,
+                                     WCM_MAX_LED_IMAGES, values);
 
        if (IsPad(priv)) {
                memset(values, 0, sizeof(values));
@@ -828,6 +836,13 @@ int wcmSetProperty(DeviceIntPtr dev, Atom property, 
XIPropertyValuePtr prop,
                if (prop->size != WCM_MAX_MOUSE_BUTTONS)
                        return BadMatch;
                wcmSetPropertyButtonActions(dev, property, prop, checkonly);
+       } else if (property == prop_oled_pixmap) {
+               return BadAccess;
+       } else if (property == prop_oled_state)
+       {
+               XIPropertyValuePtr pixmaps;
+               XIGetDeviceProperty(dev, prop_oled_pixmap, &pixmaps);
+               wcmSetOLEDProperty(dev, property, prop, checkonly, pixmaps);
        } else
                wcmSetActionProperties(dev, property, prop, checkonly);
 
diff --git a/src/xf86Wacom.h b/src/xf86Wacom.h
index c1b55c9..3b58572 100644
--- a/src/xf86Wacom.h
+++ b/src/xf86Wacom.h
@@ -184,6 +184,14 @@ enum WacomSuppressMode {
        SUPPRESS_NON_MOTION     /* Supress all events but x/y motion */
 };
 
+/* LED functions */
+extern void wcmLedInitPixmap(WacomDevicePtr priv, int *values, int count);
+extern void wcmLedStart(WacomDevicePtr priv);
+extern void wcmLedFree(WacomDevicePtr priv);
+int wcmSetOLEDProperty(DeviceIntPtr dev, Atom property,
+                      XIPropertyValuePtr prop, BOOL checkonly,
+                      XIPropertyValuePtr pixmaps);
+
 /****************************************************************************/
 #endif /* __XF86WACOM_H */
 
diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h
index cf16648..4296a2b 100644
--- a/src/xf86WacomDefs.h
+++ b/src/xf86WacomDefs.h
@@ -189,6 +189,8 @@ struct _WacomModel
                                         * tablet buttons besides the strips are
                                         * treated as buttons */
 
+#define WCM_MAX_LED_IMAGES 8
+
 /* get/set/property */
 typedef struct _PROPINFO PROPINFO;
 
@@ -296,6 +298,12 @@ struct _WacomDeviceRec
        Atom strip_actions[4];
 
        OsTimerPtr serial_timer; /* timer used for serial number property 
update */
+
+       /* path to the sysfs directory for (O)LED control;
+        * NULL means that the sysfs interface is not present
+        * (either due to missing driver,
+        *   or device has no (O)LEDs) */
+       char *sysfs_led;
 };
 
 /******************************************************************************
diff --git a/test/fake-symbols.c b/test/fake-symbols.c
index bba10e4..4e354a2 100644
--- a/test/fake-symbols.c
+++ b/test/fake-symbols.c
@@ -1,4 +1,5 @@
 #include "fake-symbols.h"
+#include <servermd.h>
 
 _X_EXPORT
 int xf86ReadSerial (int fd, void *buf, int count)
@@ -461,3 +462,25 @@ void
 xf86UnblockSIGIO (int wasset)
 {
 }
+
+int
+dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client,
+                 Mask type, Mask access)
+{
+       return 0;
+}
+
+XID
+FakeClientID(int client)
+{
+       return 0;
+}
+
+Bool
+AddResource(XID id, RESTYPE type, pointer value)
+{
+       return FALSE;
+}
+
+PaddingInfo PixmapWidthPaddingInfo[33];
+ScreenInfo screenInfo;
diff --git a/tools/xsetwacom.c b/tools/xsetwacom.c
index 2dc0c2b..938eda8 100644
--- a/tools/xsetwacom.c
+++ b/tools/xsetwacom.c
@@ -110,6 +110,7 @@ static void set_xydefault(Display *dpy, XDevice *dev, 
param_t *param, int argc,
 static void get_all(Display *dpy, XDevice *dev, param_t *param, int argc, char 
**argv);
 static void get_param(Display *dpy, XDevice *dev, param_t *param, int argc, 
char **argv);
 static void set_output(Display *dpy, XDevice *dev, param_t *param, int argc, 
char **argv);
+static void set_oled_image(Display *dpy, XDevice *dev, param_t *param, int 
argc, char **argv);
 
 /* NOTE: When removing or changing a parameter name, add to
  * deprecated_parameters.
@@ -411,6 +412,12 @@ static param_t parameters[] =
                .prop_flags = PROP_FLAG_WRITEONLY | PROP_FLAG_OUTPUT,
        },
        {
+               .name = "Image",
+               .desc = "Set the button image. ",
+               .set_func = set_oled_image,
+               .prop_flags = PROP_FLAG_WRITEONLY,
+       },
+       {
                .name = "all",
                .desc = "Get value for all parameters. ",
                .get_func = get_all,
@@ -2350,6 +2357,86 @@ static void set_output(Display *dpy, XDevice *dev, 
param_t *param, int argc, cha
                fprintf(stderr, "Unable to find an output '%s'.\n", argv[0]);
 }
 
+static void set_oled_image(Display *dpy, XDevice *dev, param_t *param, int 
argc, char **argv)
+{
+       int id, w, h, range, i;
+       Atom oled_state = None;
+       Atom oled_pixmap = None;
+       Atom type;
+       GC gc;
+       XGCValues values;
+       int index;
+       int format;
+       int r;
+       long state_nitems;
+       long pixmap_nitems;
+       long after;
+       long *pixmap_ptr;
+       char *state_array;
+       Pixmap pixmap;
+       Bool success;
+
+       oled_state = XInternAtom(dpy, WACOM_PROP_OLED_STATE, True);
+       if (!oled_state)
+       {
+               fprintf(stderr, "WACOM_PROP_OLED_STATE not available\n");
+               return;
+       }
+       oled_pixmap = XInternAtom(dpy, WACOM_PROP_OLED_PIXMAP, True);
+       if (!oled_pixmap)
+       {
+               fprintf(stderr, "WACOM_PROP_OLED_PIXMAP not available\n");
+               return;
+       }
+
+       if (argc < 2)
+       {
+               fprintf(stderr, "too few arguments\n");
+               return;
+       }
+
+       /* Retrieve OLED state array */
+       r = XGetDeviceProperty(dpy, dev, oled_state, 0, 8, 0,
+                              AnyPropertyType, &type, &format,
+                              &state_nitems, &after,
+                              (unsigned char**)&state_array);
+       if (r != Success) {
+               fprintf(stderr, "failed to set image\n");
+               return;
+       }
+
+       success = convert_value_from_user(param, argv[0], &index);
+       if (!success || index < 0 || index >= state_nitems)
+       {
+               fprintf(stderr, "'%s' is not a valid image index\n", argv[0]);
+               return;
+       }
+
+       /* Retrieve Pixmap to be changed */
+       r = XGetDeviceProperty(dpy, dev, oled_pixmap, index, 1, 0,
+                              AnyPropertyType, &type, &format,
+                              &pixmap_nitems, &after,
+                              (unsigned char**)&pixmap_ptr);
+       if (r != Success) {
+               fprintf(stderr, "failed to set image\n");
+               return;
+       }
+
+       values.foreground = BlackPixel(dpy, 0);
+       values.background = BlackPixel(dpy, 0);
+       gc = XCreateGC(dpy, *pixmap_ptr, (GCForeground|GCBackground), &values);
+
+       XFillRectangle(dpy, *pixmap_ptr, gc, 0, 0, 64, 32);
+       XSetForeground(dpy, gc, WhitePixel(dpy, 0));
+       XDrawString(dpy, *pixmap_ptr, gc, 0, 16, argv[1], strlen(argv[1]));
+
+       /* Change state to modify */
+       state_array[index] = 1;
+       XChangeDeviceProperty(dpy, dev, oled_state, XA_INTEGER, 8,
+                             PropModeReplace,
+                             (unsigned char*)state_array, state_nitems);
+}
+
 
 static void get_all(Display *dpy, XDevice *dev, param_t *param, int argc, char 
**argv)
 {
@@ -2669,7 +2756,7 @@ static void test_parameter_number(void)
         * deprecated them.
         * Numbers include trailing NULL entry.
         */
-       assert(ARRAY_SIZE(parameters) == 34);
+       assert(ARRAY_SIZE(parameters) == 35);
        assert(ARRAY_SIZE(deprecated_parameters) == 17);
 }
 
-- 
1.7.5.4


------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2dcopy2
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to