diff --git a/include/wacom-properties.h b/include/wacom-properties.h
index dfa454d..023ab2c 100644
--- a/include/wacom-properties.h
+++ b/include/wacom-properties.h
@@ -89,6 +89,7 @@
    if this button is pressed. If the value is None, no action is performed.
  */
 #define WACOM_PROP_BUTTON_ACTIONS "Wacom Button Actions"
+#define WACOM_PROP_BUTTON_IMAGE "Wacom Button Image"
 
 /* 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
diff --git a/src/wcmUSB.c b/src/wcmUSB.c
index 06f8655..e2acf43 100644
--- a/src/wcmUSB.c
+++ b/src/wcmUSB.c
@@ -26,6 +26,7 @@
 #include <asm/types.h>
 #include <linux/input.h>
 #include <sys/utsname.h>
+#include <sys/stat.h>
 #include <linux/version.h>
 
 #define MAX_USB_EVENTS 32
@@ -127,10 +128,13 @@ static Bool usbDetect(InputInfoPtr pInfo)
 /*****************************************************************************
  * usbStart --
  ****************************************************************************/
+#define FORMAT "/sys/dev/char/%d:%d/../../../../%s"
 static int
 usbStart(InputInfoPtr pInfo)
 {
 	int err;
+	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
+	struct stat stat;
 
 #ifdef EVIOCGRAB
 	/* Try to grab the event device so that data don't leak to /dev/input/mice */
@@ -142,6 +146,21 @@ usbStart(InputInfoPtr pInfo)
 		xf86Msg(X_ERROR, "%s: Wacom X driver can't grab event device (%s)\n",
 				pInfo->name, strerror(errno));
 #endif
+
+	if (fstat(pInfo->fd, &stat) >= 0) {
+		FILE *f;
+		char str[100];
+		snprintf(str, sizeof str, FORMAT,
+			major(stat.st_rdev), minor(stat.st_rdev), "busnum");
+		f = fopen(str, "r");
+		fscanf(f, "%hhd", &priv->usbdev_bus);
+		fclose(f);
+		snprintf(str, sizeof str, FORMAT,
+			major(stat.st_rdev), minor(stat.st_rdev), "devnum");
+		f = fopen(str, "r");
+		fscanf(f, "%hhd", &priv->usbdev_dev);
+		fclose(f);
+	}
 	return Success;
 }
 
diff --git a/src/wcmXCommand.c b/src/wcmXCommand.c
index 4f702b7..4904da0 100644
--- a/src/wcmXCommand.c
+++ b/src/wcmXCommand.c
@@ -25,6 +25,11 @@
 #include "wcmFilter.h"
 #include <exevents.h>
 
+#include <linux/usbdevice_fs.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+
 /*****************************************************************************
 * wcmDevSwitchModeCall --
 *****************************************************************************/
@@ -86,6 +91,7 @@ Atom prop_gesture_param;
 Atom prop_hover;
 Atom prop_tooltype;
 Atom prop_btnactions;
+Atom prop_btn_img;
 #ifdef DEBUG
 Atom prop_debuglevels;
 #endif
@@ -216,6 +222,7 @@ 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);
+	prop_btn_img = InitWcmAtom(pInfo->dev, WACOM_PROP_BUTTON_IMAGE, -32, WCM_MAX_MOUSE_BUTTONS, values);
 
 #ifdef DEBUG
 	values[0] = priv->debugLevel;
@@ -423,6 +430,42 @@ static int wcmSetPropertyButtonActions(DeviceIntPtr dev, Atom property,
 	return Success;
 }
 
+#define WACOM_SET_LED_IMG _IOW(0x00, 0x00, struct wacom_led_img)
+#define WACOM_SET_LEFT_HANDED _IOW(0x00, 0x01, struct wacom_handedness)
+#define WACOM_SET_LED_MODE _IOW(0x00, 0x02, struct wacom_led_mode)
+
+struct wacom_led_img {
+        char buf[2048];
+        int btn;
+};
+
+static int wcmSetButtonImage(DeviceIntPtr dev, Atom property,
+				       XIPropertyValuePtr prop, BOOL checkonly)
+{
+	InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
+	WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
+	int rv, dev_fd;
+	struct wacom_led_img img;
+	struct usbdevfs_ioctl wrapper;
+	char str[100];
+	unsigned char *data = prop->data;
+	snprintf(str, sizeof str, "/dev/bus/usb/%03d/%03d",
+		priv->usbdev_bus, priv->usbdev_dev);
+	/* TODO: check prop length */
+	dev_fd = open(str, O_RDWR);
+
+	img.btn = data[0];
+	memcpy(img.buf, data+1, sizeof img.buf);
+
+	wrapper.ifno = 0;
+	wrapper.ioctl_code = WACOM_SET_LED_IMG;
+	wrapper.data = &img;
+	rv = ioctl(dev_fd, USBDEVFS_IOCTL, &wrapper);
+
+	close(dev_fd);
+	return Success;
+}
+
 struct wheel_strip_update_t {
 	/* for CARD8 values, points to fields in struct to be updated */
 	int *up1;
@@ -774,6 +817,9 @@ 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_btn_img)
+	{
+		wcmSetButtonImage(dev, property, prop, checkonly);
 	} else
 		wcmSetActionProperties(dev, property, prop, checkonly);
 
diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h
index e80afb0..fb0090f 100644
--- a/src/xf86WacomDefs.h
+++ b/src/xf86WacomDefs.h
@@ -297,6 +297,9 @@ struct _WacomDeviceRec
 	Atom btn_actions[WCM_MAX_BUTTONS];
 	Atom wheel_actions[4];
 	Atom strip_actions[4];
+
+	unsigned char usbdev_bus;
+	unsigned char usbdev_dev;
 };
 
 /******************************************************************************
diff --git a/tools/xsetwacom.c b/tools/xsetwacom.c
index bb120c0..631fca9 100644
--- a/tools/xsetwacom.c
+++ b/tools/xsetwacom.c
@@ -97,6 +97,7 @@ typedef struct _param
 
 /* get_func/set_func calls for special parameters */
 static void map_button(Display *dpy, XDevice *dev, param_t *param, int argc, char **argv);
+static void set_image(Display *dpy, XDevice *dev, param_t *param, int argc, char **argv);
 static void map_wheels(Display *dpy, XDevice *dev, param_t* param, int argc, char **argv);
 static void set_mode(Display *dpy, XDevice *dev, param_t *param, int argc, char **argv);
 static void get_mode(Display *dpy, XDevice *dev, param_t *param, int argc, char **argv);
@@ -128,6 +129,11 @@ static param_t parameters[] =
 		.get_func = get_button,
 	},
 	{
+		.name = "Image",
+		.desc = "button image",
+		.set_func = set_image,
+	},
+	{
 		.name = "ToolDebugLevel",
 		.desc = "Level of debugging trace for individual tools "
 		"(default is 0 [off]). ",
@@ -1301,6 +1307,35 @@ static void map_button(Display *dpy, XDevice *dev, param_t* param, int argc, cha
 		special_map_buttons(dpy, dev, param, button, argc - 1, &argv[1]);
 }
 
+static void set_image(Display *dpy, XDevice *dev, param_t *param, int argc, char **argv)
+{
+	int id, w, h, range, i;
+	Atom prop = None;
+	unsigned char data[2048+1];
+	unsigned char pixel[2];
+	char str[40];
+	FILE *f;
+
+	sscanf(argv[0], "%hhd", data+0);
+	memset(data+1, id, sizeof data-1);
+	f = fopen(argv[1], "r");
+	fgets(str, sizeof str, f);
+	fscanf(f, "%d %d\n", &w, &h);
+	fscanf(f, "%d\n", &range);
+	for (i=1; i<2049; i++) {
+		fread(pixel, 1, sizeof pixel, f);
+		data[i] = pixel[0] >> 4;
+	}
+	fclose(f);
+	prop = XInternAtom(dpy, WACOM_PROP_BUTTON_IMAGE, True);
+	if (!prop)
+	{
+		fprintf(stderr, "WACOM_PROP_BUTTON_IMAGE not available");
+		return;
+	}
+	XChangeDeviceProperty(dpy, dev, prop, XA_INTEGER, 8, PropModeReplace, data, sizeof data);
+}
+
 static void set_xydefault(Display *dpy, XDevice *dev, param_t* param, int argc, char **argv)
 {
 	Atom prop, type;
