diff -pNaur qemu-cvs-ts-orig/hw/usb-wacom.c qemu-cvs-ts/hw/usb-wacom.c
--- qemu-cvs-ts-orig/hw/usb-wacom.c	1970-01-01 01:00:00.000000000 +0100
+++ qemu-cvs-ts/hw/usb-wacom.c	2006-09-22 20:44:26.000000000 +0200
@@ -0,0 +1,408 @@
+/*
+ * Wacom PenPartner USB tablet emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ *
+ * Author: Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * Based on hw/usb-hid.c:
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+/* Interface requests */
+#define WACOM_GET_REPORT	0x2101
+#define WACOM_SET_REPORT	0x2109
+
+/* HID interface requests */
+#define HID_GET_REPORT		0xa101
+#define HID_GET_IDLE		0xa102
+#define HID_GET_PROTOCOL	0xa103
+#define HID_SET_IDLE		0x210a
+#define HID_SET_PROTOCOL	0x210b
+
+#define WACOM_MODE_HID		1
+#define WACOM_MODE_WACOM	2
+
+typedef struct USBWacomState {
+    USBDevice dev;
+    int dx, dy, dz, buttons_state;
+    int x, y;
+    int mouse_grabbed;
+    int mode;
+} USBWacomState;
+
+static const uint8_t qemu_wacom_dev_descriptor[] = {
+    0x12,	/*  u8 bLength; */
+    0x01,	/*  u8 bDescriptorType; Device */
+    0x10, 0x10,	/*  u16 bcdUSB; v1.10 */
+
+    0x00,	/*  u8  bDeviceClass; */
+    0x00,	/*  u8  bDeviceSubClass; */
+    0x00,	/*  u8  bDeviceProtocol; [ low/full speeds only ] */
+    0x08,	/*  u8  bMaxPacketSize0; 8 Bytes */
+
+    0x6a, 0x05,	/*  u16 idVendor; */
+    0x00, 0x00,	/*  u16 idProduct; */
+    0x10, 0x42,	/*  u16 bcdDevice */
+
+    0x01,	/*  u8  iManufacturer; */
+    0x02,	/*  u8  iProduct; */
+    0x00,	/*  u8  iSerialNumber; */
+    0x01,	/*  u8  bNumConfigurations; */
+};
+
+static const uint8_t qemu_wacom_config_descriptor[] = {
+    /* one configuration */
+    0x09,	/*  u8  bLength; */
+    0x02,	/*  u8  bDescriptorType; Configuration */
+    0x22, 0x00,	/*  u16 wTotalLength; */
+    0x01,	/*  u8  bNumInterfaces; (1) */
+    0x01,	/*  u8  bConfigurationValue; */
+    0x00,	/*  u8  iConfiguration; */
+    0x80,	/*  u8  bmAttributes; 
+				 Bit 7: must be set,
+				     6: Self-powered,
+				     5: Remote wakeup,
+				     4..0: resvd */
+    40,		/*  u8  MaxPower; */
+
+    /* one interface */
+    0x09,	/*  u8  if_bLength; */
+    0x04,	/*  u8  if_bDescriptorType; Interface */
+    0x00,	/*  u8  if_bInterfaceNumber; */
+    0x00,	/*  u8  if_bAlternateSetting; */
+    0x01,	/*  u8  if_bNumEndpoints; */
+    0x03,	/*  u8  if_bInterfaceClass; HID */
+    0x01,	/*  u8  if_bInterfaceSubClass; Boot */
+    0x02,	/*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+    0x00,	/*  u8  if_iInterface; */
+
+    /* HID descriptor */
+    0x09,	/*  u8  bLength; */
+    0x21,	/*  u8  bDescriptorType; */
+    0x01, 0x10,	/*  u16 HID_class */
+    0x00,	/*  u8  country_code */
+    0x01,	/*  u8  num_descriptors */
+    0x22,	/*  u8  type; Report */
+    0x6e, 0x00,	/*  u16 len */
+
+    /* one endpoint (status change endpoint) */
+    0x07,	/*  u8  ep_bLength; */
+    0x05,	/*  u8  ep_bDescriptorType; Endpoint */
+    0x81,	/*  u8  ep_bEndpointAddress; IN Endpoint 1 */
+    0x03,	/*  u8  ep_bmAttributes; Interrupt */
+    0x08, 0x00,	/*  u16 ep_wMaxPacketSize; */
+    0x0a,	/*  u8  ep_bInterval; */
+};
+
+static void usb_mouse_event(void *opaque,
+                            int dx1, int dy1, int dz1, int buttons_state)
+{
+    USBWacomState *s = opaque;
+
+    s->dx += dx1;
+    s->dy += dy1;
+    s->dz += dz1;
+    s->buttons_state = buttons_state;
+}
+
+static void usb_wacom_event(void *opaque,
+                            int x, int y, int dz, int buttons_state)
+{
+    USBWacomState *s = opaque;
+
+    s->x = x;
+    s->y = y;
+    s->dz += dz;
+    s->buttons_state = buttons_state;
+}
+
+static inline int int_clamp(int val, int vmin, int vmax)
+{
+    if (val < vmin)
+        return vmin;
+    else if (val > vmax)
+        return vmax;
+    else
+        return val;
+}
+
+static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
+{
+    int dx, dy, dz, b, l;
+
+    if (!s->mouse_grabbed) {
+        qemu_add_mouse_event_handler(usb_mouse_event, s, 1);
+        s->mouse_grabbed = 1;
+    }
+
+    dx = int_clamp(s->dx, -128, 127);
+    dy = int_clamp(s->dy, -128, 127);
+    dz = int_clamp(s->dz, -128, 127);
+
+    s->dx -= dx;
+    s->dy -= dy;
+    s->dz -= dz;
+
+    b = 0;
+    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+        b |= 0x01;
+    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+        b |= 0x02;
+    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
+        b |= 0x04;
+
+    buf[0] = b;
+    buf[1] = dx;
+    buf[2] = dy;
+    l = 3;
+    if (len >= 4) {
+        buf[3] = dz;
+        l = 4;
+    }
+    return l;
+}
+
+static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
+{
+    int b;
+
+    if (!s->mouse_grabbed) {
+        qemu_add_mouse_event_handler(usb_wacom_event, s, 1);
+        s->mouse_grabbed = 1;
+    }
+
+    b = 0;
+    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+        b |= 0x01;
+    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+        b |= 0x02;
+    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
+        b |= 0x04;
+
+    if (len < 7)
+        return 0;
+
+    buf[0] = s->mode;
+    buf[1] = s->x & 0xff;
+    buf[2] = s->x >> 8;
+    buf[3] = s->y & 0xff;
+    buf[4] = s->y >> 8;
+    if (b) {
+        buf[5] = 0x40;
+        buf[6] = 0;
+    } else {
+        buf[5] = 0x00;
+        buf[6] = (unsigned char) -120;
+    }
+
+    return 7;
+}
+
+static void usb_wacom_handle_reset(USBDevice *dev)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+
+    s->dx = 0;
+    s->dy = 0;
+    s->dz = 0;
+    s->x = 0;
+    s->y = 0;
+    s->buttons_state = 0;
+    s->mode = WACOM_MODE_HID;
+}
+
+static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
+                                    int index, int length, uint8_t *data)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+    int ret = 0;
+
+    switch (request) {
+    case DeviceRequest | USB_REQ_GET_STATUS:
+        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
+            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
+        data[1] = 0x00;
+        ret = 2;
+        break;
+    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 0;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 1;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        dev->addr = value;
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+        switch (value >> 8) {
+        case USB_DT_DEVICE:
+            memcpy(data, qemu_wacom_dev_descriptor, 
+                   sizeof(qemu_wacom_dev_descriptor));
+            ret = sizeof(qemu_wacom_dev_descriptor);
+            break;
+        case USB_DT_CONFIG:
+       	    memcpy(data, qemu_wacom_config_descriptor, 
+                   sizeof(qemu_wacom_config_descriptor));
+            ret = sizeof(qemu_wacom_config_descriptor);
+            break;
+        case USB_DT_STRING:
+            switch (value & 0xff) {
+            case 0:
+                /* language ids */
+                data[0] = 4;
+                data[1] = 3;
+                data[2] = 0x09;
+                data[3] = 0x04;
+                ret = 4;
+                break;
+            case 1:
+                /* serial number */
+                ret = set_usb_string(data, "1");
+                break;
+            case 2:
+		ret = set_usb_string(data, "Wacom PenPartner");
+                break;
+            case 3:
+                /* vendor description */
+                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
+                break;
+            case 4:
+                ret = set_usb_string(data, "Wacom Tablet");
+                break;
+            case 5:
+                ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
+                break;
+            default:
+                goto fail;
+            }
+            break;
+        default:
+            goto fail;
+        }
+        break;
+    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+        data[0] = 1;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+    case WACOM_SET_REPORT:
+        qemu_add_mouse_event_handler(NULL, NULL, 0);
+	s->mouse_grabbed = 0;
+        s->mode = data[0];
+        ret = 0;
+        break;
+    case WACOM_GET_REPORT:
+        data[0] = 0;
+        data[1] = s->mode;
+        ret = 2;
+        break;
+    /* USB HID requests */
+    case HID_GET_REPORT:
+        if (s->mode == WACOM_MODE_HID)
+            ret = usb_mouse_poll(s, data, length);
+        else if (s->mode == WACOM_MODE_WACOM)
+            ret = usb_wacom_poll(s, data, length);
+        break;
+    case HID_SET_IDLE:
+        ret = 0;
+        break;
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_wacom_handle_data(USBDevice *dev, int pid, 
+                                 uint8_t devep, uint8_t *data, int len)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+    int ret = 0;
+
+    switch (pid) {
+    case USB_TOKEN_IN:
+        if (devep == 1) {
+            if (s->mode == WACOM_MODE_HID)
+                ret = usb_mouse_poll(s, data, len);
+            else if (s->mode == WACOM_MODE_WACOM)
+                ret = usb_wacom_poll(s, data, len);
+            break;
+        }
+        /* Fall through.  */
+    case USB_TOKEN_OUT:
+    default:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static void usb_wacom_handle_destroy(USBDevice *dev)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+
+    qemu_add_mouse_event_handler(NULL, NULL, 0);
+    qemu_free(s);
+}
+
+USBDevice *usb_wacom_init(void)
+{
+    USBWacomState *s;
+
+    s = qemu_mallocz(sizeof(USBWacomState));
+    if (!s)
+        return NULL;
+    s->dev.speed = USB_SPEED_FULL;
+    s->dev.handle_packet = usb_generic_handle_packet;
+
+    s->dev.handle_reset = usb_wacom_handle_reset;
+    s->dev.handle_control = usb_wacom_handle_control;
+    s->dev.handle_data = usb_wacom_handle_data;
+    s->dev.handle_destroy = usb_wacom_handle_destroy;
+
+    pstrcpy(s->dev.devname, sizeof(s->dev.devname),
+            "QEMU PenPartner Tablet");
+
+    return (USBDevice *) s;
+}
diff -pNaur qemu-cvs-ts-orig/hw/usb.h qemu-cvs-ts/hw/usb.h
--- qemu-cvs-ts-orig/hw/usb.h	2006-08-12 03:04:27.000000000 +0200
+++ qemu-cvs-ts/hw/usb.h	2006-09-21 01:40:40.000000000 +0200
@@ -218,3 +218,6 @@ USBDevice *usb_tablet_init(void);
 
 /* usb-msd.c */
 USBDevice *usb_msd_init(const char *filename);
+
+/* usb-wacom.c */
+USBDevice *usb_wacom_init(void);
diff -pNaur qemu-cvs-ts-orig/vl.c qemu-cvs-ts/vl.c
--- qemu-cvs-ts-orig/vl.c	2006-09-10 16:39:54.000000000 +0200
+++ qemu-cvs-ts/vl.c	2006-09-21 01:45:16.000000000 +0200
@@ -3765,6 +3765,8 @@ static int usb_device_add(const char *de
 	dev = usb_tablet_init();
     } else if (strstart(devname, "disk:", &p)) {
         dev = usb_msd_init(p);
+    } else if (!strcmp(devname, "wacom-tablet")) {
+        dev = usb_wacom_init();
     } else {
         return -1;
     }
diff -pNaur qemu-cvs-ts-orig/Makefile.target qemu-cvs-ts/Makefile.target
--- qemu-cvs-ts-orig/Makefile.target	2006-09-18 03:15:29.000000000 +0200
+++ qemu-cvs-ts/Makefile.target	2006-09-21 02:32:19.000000000 +0200
@@ -330,6 +330,7 @@ VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a
 
 # USB layer
 VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
+VL_OBJS+= usb-wacom.o
 
 # PCI network cards
 VL_OBJS+= ne2000.o rtl8139.o pcnet.o