-/* $OpenBSD: hid.c,v 1.5 2022/05/20 05:03:45 anton Exp $ */
+/* $OpenBSD: hid.c,v 1.6 2023/08/12 20:47:06 miod Exp $ */
/* $NetBSD: hid.c,v 1.23 2002/07/11 21:14:25 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */
hid_end_parse(hd);
return (0);
}
+
+struct hid_data *
+hid_get_collection_data(const void *desc, int size, int32_t usage,
+ uint32_t collection)
+{
+ struct hid_data *hd;
+ struct hid_item hi;
+
+ hd = hid_start_parse(desc, size, hid_all);
+
+ DPRINTF("%s: usage=0x%x\n", __func__, usage);
+ while (hid_get_item(hd, &hi)) {
+ DPRINTF("%s: kind=%d id=%d usage=0x%x(0x%x)\n", __func__,
+ hi.kind, hi.report_ID, hi.usage, usage);
+ if (hi.kind == hid_collection &&
+ hi.collection == collection && hi.usage == usage) {
+ DPRINTF("%s: found\n", __func__);
+ return hd;
+ }
+ }
+ DPRINTF("%s: not found\n", __func__);
+ hid_end_parse(hd);
+ return NULL;
+}
+
+int
+hid_get_id_of_collection(const void *desc, int size, int32_t usage,
+ uint32_t collection)
+{
+ struct hid_data *hd;
+ struct hid_item hi;
+
+ hd = hid_start_parse(desc, size, hid_all);
+
+ DPRINTF("%s: id=%d usage=0x%x\n", __func__, id, usage);
+ while (hid_get_item(hd, &hi)) {
+ DPRINTF("%s: kind=%d id=%d usage=0x%x(0x%x)\n", __func__,
+ hi.kind, hi.report_ID, hi.usage, usage);
+ if (hi.kind == hid_collection &&
+ hi.collection == collection && hi.usage == usage) {
+ DPRINTF("%s: found\n", __func__);
+ hid_end_parse(hd);
+ return hi.report_ID;
+ }
+ }
+ DPRINTF("%s: not found\n", __func__);
+ hid_end_parse(hd);
+ return -1;
+}
-/* $OpenBSD: hid.h,v 1.10 2022/05/20 05:03:45 anton Exp $ */
+/* $OpenBSD: hid.h,v 1.11 2023/08/12 20:47:06 miod Exp $ */
/* $NetBSD: hid.h,v 1.8 2002/07/11 21:14:25 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/hid.h,v 1.7 1999/11/17 22:33:40 n_hibma Exp $ */
int32_t hid_get_data(const uint8_t *buf, int, struct hid_location *);
uint32_t hid_get_udata(const uint8_t *buf, int, struct hid_location *);
int hid_is_collection(const void *, int, uint8_t, int32_t);
+struct hid_data *hid_get_collection_data(const void *, int, int32_t, uint32_t);
+int hid_get_id_of_collection(const void *, int, int32_t, uint32_t);
#endif /* _KERNEL */
#define HUD_TOUCHSCREEN 0x0004
#define HUD_TOUCHPAD 0x0005
#define HUD_CONFIG 0x000e
+#define HUD_STYLUS 0x0020
#define HUD_FINGER 0x0022
#define HUD_TIP_PRESSURE 0x0030
#define HUD_BARREL_PRESSURE 0x0031
#define HUD_CONTACT_MAX 0x0055
#define HUD_SCAN_TIME 0x0056
#define HUD_BUTTON_TYPE 0x0059
+#define HUD_SECONDARY_BARREL_SWITCH 0x005A
+#define HUD_WACOM_X 0x0130
+#define HUD_WACOM_Y 0x0131
+#define HUD_WACOM_DISTANCE 0x0132
+#define HUD_WACOM_PAD_BUTTONS00 0x0910
+#define HUD_WACOM_BATTERY 0x1013
/* Usages, LED */
#define HUL_NUM_LOCK 0x0001
-/* $OpenBSD: hidms.c,v 1.9 2022/06/16 20:52:38 bru Exp $ */
+/* $OpenBSD: hidms.c,v 1.10 2023/08/12 20:47:06 miod Exp $ */
/* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */
/*
#define MOUSE_FLAGS_MASK (HIO_CONST | HIO_RELATIVE)
#define NOTMOUSE(f) (((f) & MOUSE_FLAGS_MASK) != HIO_RELATIVE)
+void
+hidms_stylus_hid_parse(struct hidms *ms, struct hid_data *d,
+ struct hid_location *loc_stylus_btn)
+{
+ struct hid_item h;
+
+ while (hid_get_item(d, &h)) {
+ if (h.kind == hid_endcollection)
+ break;
+ if (h.kind != hid_input || (h.flags & HIO_CONST) != 0)
+ continue;
+ /* All the possible stylus reported usages go here */
+#ifdef HIDMS_DEBUG
+ printf("stylus usage: 0x%x\n", h.usage);
+#endif
+ switch (h.usage) {
+ /* Buttons */
+ case HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_TIP_SWITCH):
+ DPRINTF("Stylus usage tip set\n");
+ if (ms->sc_num_stylus_buttons >= MAX_BUTTONS)
+ break;
+ loc_stylus_btn[ms->sc_num_stylus_buttons++] = h.loc;
+ ms->sc_flags |= HIDMS_TIP;
+ break;
+ case HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_BARREL_SWITCH):
+ DPRINTF("Stylus usage barrel set\n");
+ if (ms->sc_num_stylus_buttons >= MAX_BUTTONS)
+ break;
+ loc_stylus_btn[ms->sc_num_stylus_buttons++] = h.loc;
+ ms->sc_flags |= HIDMS_BARREL;
+ break;
+ case HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS,
+ HUD_SECONDARY_BARREL_SWITCH):
+ DPRINTF("Stylus usage secondary barrel set\n");
+ if (ms->sc_num_stylus_buttons >= MAX_BUTTONS)
+ break;
+ loc_stylus_btn[ms->sc_num_stylus_buttons++] = h.loc;
+ ms->sc_flags |= HIDMS_SEC_BARREL;
+ break;
+ case HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_IN_RANGE):
+ DPRINTF("Stylus usage in range set\n");
+ if (ms->sc_num_stylus_buttons >= MAX_BUTTONS)
+ break;
+ loc_stylus_btn[ms->sc_num_stylus_buttons++] = h.loc;
+ break;
+ case HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_QUALITY):
+ DPRINTF("Stylus usage quality set\n");
+ if (ms->sc_num_stylus_buttons >= MAX_BUTTONS)
+ break;
+ loc_stylus_btn[ms->sc_num_stylus_buttons++] = h.loc;
+ break;
+ /* Axes */
+ case HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_X):
+ DPRINTF("Stylus usage x set\n");
+ ms->sc_loc_x = h.loc;
+ ms->sc_tsscale.minx = h.logical_minimum;
+ ms->sc_tsscale.maxx = h.logical_maximum;
+ ms->sc_flags |= HIDMS_ABSX;
+ break;
+ case HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_Y):
+ DPRINTF("Stylus usage y set\n");
+ ms->sc_loc_y = h.loc;
+ ms->sc_tsscale.miny = h.logical_minimum;
+ ms->sc_tsscale.maxy = h.logical_maximum;
+ ms->sc_flags |= HIDMS_ABSY;
+ break;
+ case HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_TIP_PRESSURE):
+ DPRINTF("Stylus usage pressure set\n");
+ ms->sc_loc_z = h.loc;
+ ms->sc_tsscale.minz = h.logical_minimum;
+ ms->sc_tsscale.maxz = h.logical_maximum;
+ ms->sc_flags |= HIDMS_Z;
+ break;
+ case HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_DISTANCE):
+ DPRINTF("Stylus usage distance set\n");
+ ms->sc_loc_w = h.loc;
+ ms->sc_tsscale.minw = h.logical_minimum;
+ ms->sc_tsscale.maxw = h.logical_maximum;
+ ms->sc_flags |= HIDMS_W;
+ break;
+ default:
+#ifdef HIDMS_DEBUG
+ printf("Unknown stylus usage: 0x%x\n",
+ h.usage);
+#endif
+ break;
+ }
+ }
+}
+
+void
+hidms_pad_buttons_hid_parse(struct hidms *ms, struct hid_data *d,
+ struct hid_location *loc_pad_btn)
+{
+ struct hid_item h;
+
+ while (hid_get_item(d, &h)) {
+ if (h.kind == hid_endcollection)
+ break;
+ if (h.kind == hid_input && (h.flags & HIO_CONST) != 0 &&
+ h.usage == HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS,
+ HUD_WACOM_PAD_BUTTONS00 | ms->sc_num_pad_buttons)) {
+ if (ms->sc_num_pad_buttons >= MAX_BUTTONS)
+ break;
+ loc_pad_btn[ms->sc_num_pad_buttons++] = h.loc;
+ }
+ }
+}
+
+int
+hidms_wacom_setup(struct device *self, struct hidms *ms, void *desc, int dlen)
+{
+ struct hid_data *hd;
+ int i;
+ struct hid_location loc_pad_btn[MAX_BUTTONS];
+ struct hid_location loc_stylus_btn[MAX_BUTTONS];
+
+ ms->sc_flags = 0;
+
+ /* Set x,y,z and w to zero by default */
+ ms->sc_loc_x.size = 0;
+ ms->sc_loc_y.size = 0;
+ ms->sc_loc_z.size = 0;
+ ms->sc_loc_w.size = 0;
+
+ if ((hd = hid_get_collection_data(desc, dlen,
+ HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_DIGITIZER),
+ HCOLL_APPLICATION))) {
+ DPRINTF("found the global collection\n");
+ hid_end_parse(hd);
+ if ((hd = hid_get_collection_data(desc, dlen,
+ HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_STYLUS),
+ HCOLL_PHYSICAL))) {
+ DPRINTF("found stylus collection\n");
+ hidms_stylus_hid_parse(ms, hd, loc_stylus_btn);
+ hid_end_parse(hd);
+ }
+ if ((hd = hid_get_collection_data(desc, dlen,
+ HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_TABLET_FKEYS),
+ HCOLL_PHYSICAL))) {
+ DPRINTF("found tablet keys collection\n");
+ hidms_pad_buttons_hid_parse(ms, hd, loc_pad_btn);
+ hid_end_parse(hd);
+ }
+#ifdef notyet
+ if ((hd = hid_get_collection_data(desc, dlen,
+ HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_BATTERY),
+ HCOLL_PHYSICAL))) {
+ DPRINTF("found battery collection\n");
+ /* parse and set the battery info */
+ /* not yet used */
+ hid_end_parse(hd);
+ }
+#endif
+ /*
+ * Ignore the device config, it's not really needed;
+ * Ignore the usage 0x10AC which is the debug collection, and
+ * ignore firmware collection and other collections for now.
+ */
+ }
+
+ /* Map the pad and stylus buttons to mouse buttons */
+ for (i = 0; i < ms->sc_num_stylus_buttons; i++)
+ memcpy(&ms->sc_loc_btn[i], &loc_stylus_btn[i],
+ sizeof(struct hid_location));
+ if (ms->sc_num_pad_buttons + ms->sc_num_stylus_buttons >= MAX_BUTTONS)
+ ms->sc_num_pad_buttons =
+ MAX_BUTTONS - ms->sc_num_stylus_buttons;
+ for (; i < ms->sc_num_pad_buttons + ms->sc_num_stylus_buttons; i++)
+ memcpy(&ms->sc_loc_btn[i], &loc_pad_btn[i],
+ sizeof(struct hid_location));
+ ms->sc_num_buttons = i;
+ DPRINTF("Button information\n");
+#ifdef HIDMS_DEBUG
+ for (i = 0; i < ms->sc_num_buttons; i++)
+ printf("size: 0x%x, pos: 0x%x, count: 0x%x\n",
+ ms->sc_loc_btn[i].size, ms->sc_loc_btn[i].pos,
+ ms->sc_loc_btn[i].count);
+#endif
+ return 0;
+}
+
int
hidms_setup(struct device *self, struct hidms *ms, uint32_t quirks,
int id, void *desc, int dlen)
ms->sc_flags = quirks;
+ /* We are setting up a Wacom tablet, not a regular mouse */
+ if (quirks & HIDMS_WACOM_SETUP)
+ return hidms_wacom_setup(self, ms, desc, dlen);
+
if (!hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), id,
hid_input, &ms->sc_loc_x, &flags))
ms->sc_loc_x.size = 0;
- switch(flags & MOUSE_FLAGS_MASK) {
+ switch (flags & MOUSE_FLAGS_MASK) {
case 0:
ms->sc_flags |= HIDMS_ABSX;
break;
break;
ms->sc_num_buttons = i - 1;
- /*
+ /*
* The Kensington Slimblade reports some of its buttons as binary
* inputs in the first vendor usage page (0xff00). Add such inputs
* as buttons if the device has this quirk.
-/* $OpenBSD: hidmsvar.h,v 1.2 2021/01/10 16:32:48 thfr Exp $ */
+/* $OpenBSD: hidmsvar.h,v 1.3 2023/08/12 20:47:06 miod Exp $ */
/* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */
/*
struct tsscale {
int minx, maxx;
int miny, maxy;
+ int minz, maxz;
+ int minw, maxw;
int swapxy;
int resx, resy;
};
struct hidms {
+ struct device *sc_device;
+ struct device *sc_wsmousedev;
+
int sc_enabled;
int sc_flags; /* device configuration */
#define HIDMS_SPUR_BUT_UP 0x0001 /* spurious button up events */
#define HIDMS_LEADINGBYTE 0x0020 /* Unknown leading byte */
#define HIDMS_ABSX 0x0040 /* X-axis is absolute */
#define HIDMS_ABSY 0x0080 /* Y-axis is absolute */
-#define HIDMS_TIP 0x0100 /* Tip switch on a digitiser pen */
+#define HIDMS_TIP 0x0100 /* Tip switch on a digitiser pen */
#define HIDMS_BARREL 0x0200 /* Barrel switch on a digitiser pen */
-#define HIDMS_ERASER 0x0400 /* Eraser switch on a digitiser pen */
+#define HIDMS_ERASER 0x0400 /* Eraser switch on a digitiser pen */
#define HIDMS_MS_BAD_CLASS 0x0800 /* Mouse doesn't identify properly */
#define HIDMS_VENDOR_BUTTONS 0x1000 /* extra buttons in vendor page */
+#define HIDMS_SEC_BARREL 0x2000 /* Secondary Barrel switch on a digitiser pen */
+#define HIDMS_WACOM_SETUP 0x4000 /* Requires Wacom-style setup */
int sc_num_buttons;
u_int32_t sc_buttons; /* mouse button status */
- struct device *sc_device;
- struct device *sc_wsmousedev;
+ /* Wacom-specific fields */
+ int sc_num_pad_buttons;
+ int sc_num_stylus_buttons;
/* locators */
struct hid_location sc_loc_x;
-/* $OpenBSD: uhidev.c,v 1.108 2022/05/20 05:03:45 anton Exp $ */
+/* $OpenBSD: uhidev.c,v 1.109 2023/08/12 20:47:06 miod Exp $ */
/* $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $ */
/*
return (UMATCH_IFACECLASS_GENERIC);
}
+int
+uhidev_attach_repid(struct uhidev_softc *sc, struct uhidev_attach_arg *uha,
+ int repid)
+{
+ struct device *dev;
+
+ /* Could already be assigned by uhidev_set_report_dev(). */
+ if (sc->sc_subdevs[repid] != NULL)
+ return 0;
+
+ uha->reportid = repid;
+ dev = config_found_sm(&sc->sc_dev, uha, uhidevprint, NULL);
+ sc->sc_subdevs[repid] = (struct uhidev *)dev;
+ return 1;
+}
+
void
uhidev_attach(struct device *parent, struct device *self, void *aux)
{
free(uha.claimed, M_TEMP, nrepid);
uha.claimed = NULL;
+ /* Special case for Wacom tablets */
+ if (uha.uaa->vendor == USB_VENDOR_WACOM) {
+ int ndigitizers = 0;
+ /*
+ * Get all the needed collections (only 3 seem to be of
+ * interest currently).
+ */
+ repid = hid_get_id_of_collection(desc, size,
+ HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_STYLUS),
+ HCOLL_PHYSICAL);
+ if (repid >= 0 && repid < nrepid)
+ ndigitizers += uhidev_attach_repid(sc, &uha, repid);
+ repid = hid_get_id_of_collection(desc, size,
+ HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_TABLET_FKEYS),
+ HCOLL_PHYSICAL);
+ if (repid >= 0 && repid < nrepid)
+ ndigitizers += uhidev_attach_repid(sc, &uha, repid);
+#ifdef notyet /* not handled in hidms_wacom_setup() yet */
+ repid = hid_get_id_of_collection(desc, size,
+ HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_BATTERY),
+ HCOLL_PHYSICAL);
+ if (repid >= 0 && repid < nrepid)
+ ndigitizers += uhidev_attach_repid(sc, &uha, repid);
+#endif
+
+ if (ndigitizers != 0)
+ return;
+ }
+
for (repid = 0; repid < nrepid; repid++) {
DPRINTF(("%s: try repid=%d\n", __func__, repid));
if (hid_report_size(desc, size, hid_input, repid) == 0 &&
hid_report_size(desc, size, hid_feature, repid) == 0)
continue;
- /* Could already be assigned by uhidev_set_report_dev(). */
- if (sc->sc_subdevs[repid] != NULL)
- continue;
-
- uha.reportid = repid;
- dev = config_found_sm(self, &uha, uhidevprint, NULL);
- sc->sc_subdevs[repid] = (struct uhidev *)dev;
+ uhidev_attach_repid(sc, &uha, repid);
}
}
-/* $OpenBSD: uwacom.c,v 1.7 2022/10/08 06:53:06 mglocker Exp $ */
+/* $OpenBSD: uwacom.c,v 1.8 2023/08/12 20:47:06 miod Exp $ */
/*
* Copyright (c) 2016 Frank Groeneveld <frank@frankgroeneveld.nl>
struct hidms sc_ms;
struct hid_location sc_loc_tip_press;
int sc_flags;
+ int sc_x, sc_y, sc_z, sc_w;
+ int sc_moved;
};
struct cfdriver uwacom_cd = {
NULL, "uwacom", DV_DULL
};
-
const struct usb_devno uwacom_devs[] = {
{ USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS_DRAW },
{ USB_VENDOR_WACOM, USB_PRODUCT_WACOM_ONE_S },
- { USB_VENDOR_WACOM, USB_PRODUCT_WACOM_ONE_M }
+ { USB_VENDOR_WACOM, USB_PRODUCT_WACOM_ONE_M },
+ { USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS_S }
};
int uwacom_match(struct device *, void *, void *);
void uwacom_attach(struct device *, struct device *, void *);
int uwacom_detach(struct device *, int);
+void uwacom_intr_legacy(struct uhidev *, void *, u_int);
void uwacom_intr(struct uhidev *, void *, u_int);
int uwacom_enable(void *);
void uwacom_disable(void *);
uhidev_get_report_desc(uha->parent, &desc, &size);
+ if (hid_is_collection(desc, size, uha->reportid,
+ HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_DIGITIZER)))
+ return (UMATCH_IFACECLASS);
if (!hid_locate(desc, size, HID_USAGE2(HUP_WACOM, HUG_POINTER),
uha->reportid, hid_input, NULL, NULL))
return (UMATCH_NONE);
struct hidms *ms = &sc->sc_ms;
struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
struct usb_attach_arg *uaa = uha->uaa;
+ static uByte wacom_report_buf[2] = { 0x02, 0x02 };
int size, repid;
void *desc;
- sc->sc_hdev.sc_intr = uwacom_intr;
+ sc->sc_hdev.sc_intr = uwacom_intr_legacy;
sc->sc_hdev.sc_parent = uha->parent;
sc->sc_hdev.sc_udev = uaa->device;
sc->sc_hdev.sc_report_id = uha->reportid;
ms->sc_loc_btn[2].pos = 2;
ms->sc_loc_btn[2].size = 1;
- if (uha->uaa->product == USB_PRODUCT_WACOM_ONE_S) {
- static uByte reportbuf[2] = { 0x02, 0x02 };
- uhidev_set_report(uha->parent, UHID_FEATURE_REPORT, 2,
- &reportbuf, 2);
- ms->sc_tsscale.maxx = 15200;
- ms->sc_tsscale.maxy = 9500;
- }
-
- if (uha->uaa->product == USB_PRODUCT_WACOM_INTUOS_DRAW) {
+ switch (uha->uaa->product) {
+ case USB_PRODUCT_WACOM_ONE_S:
+ case USB_PRODUCT_WACOM_INTUOS_S:
+ uhidev_set_report(uha->parent, UHID_FEATURE_REPORT,
+ sc->sc_hdev.sc_report_id, &wacom_report_buf,
+ sizeof(wacom_report_buf));
+ sc->sc_hdev.sc_intr = uwacom_intr;
+ hidms_setup((struct device *)sc, ms, HIDMS_WACOM_SETUP,
+ repid, desc, size);
+ break;
+ case USB_PRODUCT_WACOM_INTUOS_DRAW:
sc->sc_flags = UWACOM_USE_PRESSURE | UWACOM_BIG_ENDIAN;
sc->sc_loc_tip_press.pos = 43;
sc->sc_loc_tip_press.size = 8;
ms->sc_tsscale.maxx = 7600;
ms->sc_tsscale.maxy = 4750;
+ break;
}
hidms_attach(ms, &uwacom_accessops);
}
void
-uwacom_intr(struct uhidev *addr, void *buf, u_int len)
+uwacom_intr_legacy(struct uhidev *addr, void *buf, u_int len)
{
struct uwacom_softc *sc = (struct uwacom_softc *)addr;
struct hidms *ms = &sc->sc_ms;
for (i = 0; i < ms->sc_num_buttons; i++)
if (hid_get_data(data, len, &ms->sc_loc_btn[i]))
- buttons |= (1 << i);
+ buttons |= 1 << i;
if (sc->sc_flags & UWACOM_USE_PRESSURE) {
pressure = hid_get_data(data, len, &sc->sc_loc_tip_press);
}
}
+void
+uwacom_intr(struct uhidev *addr, void *buf, u_int len)
+{
+ struct uwacom_softc *sc = (struct uwacom_softc *)addr;
+ struct hidms *ms = &sc->sc_ms;
+ u_int32_t buttons = 0;
+ uint8_t *data = (uint8_t *)buf;
+ int i, j, x, y, dx, dy, dz, dw, pressure, distance;
+
+ if (ms->sc_enabled == 0)
+ return;
+
+ x = hid_get_data(data, len, &ms->sc_loc_x);
+ y = hid_get_data(data, len, &ms->sc_loc_y);
+ pressure = hid_get_data(data, len, &ms->sc_loc_z);
+ distance = hid_get_data(data, len, &ms->sc_loc_w);
+
+ if (!sc->sc_moved) {
+ sc->sc_x = x;
+ sc->sc_y = y;
+ sc->sc_z = pressure;
+ sc->sc_w = distance;
+ sc->sc_moved = 1;
+ }
+
+ dx = sc->sc_x - x;
+ dy = sc->sc_y - y;
+ /* Clamp sensitivity to +/-127 */
+ dz = sc->sc_z / 32 - pressure / 32;
+ dw = sc->sc_w - distance;
+
+ sc->sc_x = x;
+ sc->sc_y = y;
+ sc->sc_z = pressure;
+ sc->sc_w = distance;
+
+ if (sc->sc_flags & UWACOM_BIG_ENDIAN) {
+ x = be16toh(x);
+ y = be16toh(y);
+ }
+
+ for (i = 0; i < ms->sc_num_stylus_buttons; i++)
+ if (hid_get_data(data, len, &ms->sc_loc_btn[i]))
+ buttons |= 1 << i;
+
+ for (j = 0; i < ms->sc_num_buttons; i++, j++)
+ if (hid_get_data(data, len, &ms->sc_loc_btn[i]))
+ buttons |= 1 << j;
+
+ if (x != 0 || y != 0 || pressure != 0 || distance != 0 ||
+ buttons != ms->sc_buttons) {
+ wsmouse_motion(ms->sc_wsmousedev, -dx, dy, dz, dw);
+ wsmouse_buttons(ms->sc_wsmousedev, buttons);
+ wsmouse_input_sync(ms->sc_wsmousedev);
+ }
+}
+
int
uwacom_enable(void *v)
{