From cdf254201b73713dd63037c9e8b9b303393d60a4 Mon Sep 17 00:00:00 2001 From: miod Date: Sat, 12 Aug 2023 20:47:06 +0000 Subject: [PATCH] Better uwacom(4) support for Intuos S and One S tablets; most of the work done by Vladimir Meshcheriakov (first name dot last name at epita somewhere in frogland), thanks! Tested by Peter J. Philipp on Intuos Draw and by espie@ on Intuos S. --- sys/dev/hid/hid.c | 51 ++++++++++- sys/dev/hid/hid.h | 11 ++- sys/dev/hid/hidms.c | 192 ++++++++++++++++++++++++++++++++++++++++- sys/dev/hid/hidmsvar.h | 18 ++-- sys/dev/usb/uhidev.c | 55 ++++++++++-- sys/dev/usb/uwacom.c | 97 +++++++++++++++++---- 6 files changed, 391 insertions(+), 33 deletions(-) diff --git a/sys/dev/hid/hid.c b/sys/dev/hid/hid.c index c758764f17a..435e547d8d6 100644 --- a/sys/dev/hid/hid.c +++ b/sys/dev/hid/hid.c @@ -1,4 +1,4 @@ -/* $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 $ */ @@ -657,3 +657,52 @@ hid_is_collection(const void *desc, int size, uint8_t id, int32_t usage) 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; +} diff --git a/sys/dev/hid/hid.h b/sys/dev/hid/hid.h index 7400e920bc2..3c5cc2ada56 100644 --- a/sys/dev/hid/hid.h +++ b/sys/dev/hid/hid.h @@ -1,4 +1,4 @@ -/* $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 $ */ @@ -93,6 +93,8 @@ int hid_locate(const void *, int, int32_t, uint8_t, enum hid_kind, 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 */ @@ -353,6 +355,7 @@ int hid_is_collection(const void *, int, uint8_t, int32_t); #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 @@ -387,6 +390,12 @@ int hid_is_collection(const void *, int, uint8_t, int32_t); #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 diff --git a/sys/dev/hid/hidms.c b/sys/dev/hid/hidms.c index 622d5d9bc33..aa865757c34 100644 --- a/sys/dev/hid/hidms.c +++ b/sys/dev/hid/hidms.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -61,6 +61,188 @@ int hidmsdebug = 0; #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) @@ -75,11 +257,15 @@ hidms_setup(struct device *self, struct hidms *ms, uint32_t quirks, 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; @@ -189,7 +375,7 @@ hidms_setup(struct device *self, struct hidms *ms, uint32_t quirks, 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. diff --git a/sys/dev/hid/hidmsvar.h b/sys/dev/hid/hidmsvar.h index a430b90ddae..3cd754c898f 100644 --- a/sys/dev/hid/hidmsvar.h +++ b/sys/dev/hid/hidmsvar.h @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -36,11 +36,16 @@ 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 */ @@ -51,17 +56,20 @@ struct hidms { #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; diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c index 26b5b04088d..c0664fbf239 100644 --- a/sys/dev/usb/uhidev.c +++ b/sys/dev/usb/uhidev.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -139,6 +139,22 @@ uhidev_match(struct device *parent, void *match, void *aux) 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) { @@ -283,6 +299,35 @@ 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 && @@ -290,13 +335,7 @@ uhidev_attach(struct device *parent, struct device *self, void *aux) 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); } } diff --git a/sys/dev/usb/uwacom.c b/sys/dev/usb/uwacom.c index f9af276a641..4fbc8f990ee 100644 --- a/sys/dev/usb/uwacom.c +++ b/sys/dev/usb/uwacom.c @@ -1,4 +1,4 @@ -/* $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 @@ -43,22 +43,25 @@ struct uwacom_softc { 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 *); @@ -90,6 +93,9 @@ uwacom_match(struct device *parent, void *match, void *aux) 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); @@ -104,10 +110,11 @@ uwacom_attach(struct device *parent, struct device *self, void *aux) 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; @@ -141,20 +148,23 @@ uwacom_attach(struct device *parent, struct device *self, void *aux) 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); @@ -170,7 +180,7 @@ uwacom_detach(struct device *self, int flags) } 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; @@ -195,7 +205,7 @@ uwacom_intr(struct uhidev *addr, void *buf, u_int len) 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); @@ -212,6 +222,63 @@ uwacom_intr(struct uhidev *addr, void *buf, u_int len) } } +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) { -- 2.20.1