I hope Vladimir will find the time to complete this answer. As far as Vlad's work goes, he did a presentation last week-end: https://www.lre.epita.fr/news_content/SS_summer_week_pres/Vladimir_Driver_OpenBSD.pptx
(sorry for the medium, fortunately we have libreoffice) In the mean time, here is an updated diff. I removed the Gaomon stuff, which if anything should be a different patch. And I cleaned up the 20+ minor style violations I could find... (tabs instead of +4 spaces for continued lines, a few non-style compliant function declarations and/or code blocks, oh well) plus an extra malloc.h that snuck in and is not at all needed. And some typos in comments. And a C++ style comment. Oh well I would really for some version of this to get in soonish. I can vouch that my tablet "works" with it (well, as good as it can work within the limitations of wscons not allowing it to be easily differentiated from the normal mouse, which is really a pain for programs like gimp) dmesg for the tablet with the diff | uhidev1 at uhub1 port 4 configuration 1 interface 0 "Wacom Co.,Ltd. Intuos S" rev 2.00/1.07 addr 6 | uhidev1: iclass 3/0, 228 report ids | uwacom0 at uhidev1: 9 buttons, Z and W dir, tip, barrel | wsmouse5 at uwacom0 mux 0 | uwacom1 at uhidev1: 9 buttons, Z and W dir, tip, barrel | wsmouse6 at uwacom1 mux 0 | uwacom2 at uhidev1: 9 buttons, Z and W dir, tip, barrel | wsmouse7 at uwacom2 mux 0 as far as I understand, it appears as several mice because the stylus acts as totally different devices depending on the mode/end used (stuff that wscons completely hides from us). Without the patch, that tablet appears as 42 different uhid devices (!) The idea is that the parser for collections was really primitive. The debug stuff can show the details of various collection. There is the actual tablet mechanisms (which becomes one device) including scale, stylus, etc, and some other wacky collections (!): a debug collection that the wacom guys told us "oh some of our hw team needs that, but don't ever touch" and some other stuff we can't support yet (like battery support for some advanced models of stylus) Index: dev/hid/hid.c =================================================================== RCS file: /cvs/src/sys/dev/hid/hid.c,v retrieving revision 1.5 diff -u -p -r1.5 hid.c --- dev/hid/hid.c 20 May 2022 05:03:45 -0000 1.5 +++ dev/hid/hid.c 3 Jul 2023 09:04:50 -0000 @@ -657,3 +657,51 @@ hid_is_collection(const void *desc, int 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__); + return hi.report_ID; + } + } + DPRINTF("%s: not found\n", __func__); + hid_end_parse(hd); + return 0; +} Index: dev/hid/hid.h =================================================================== RCS file: /cvs/src/sys/dev/hid/hid.h,v retrieving revision 1.10 diff -u -p -r1.10 hid.h --- dev/hid/hid.h 20 May 2022 05:03:45 -0000 1.10 +++ dev/hid/hid.h 3 Jul 2023 09:04:50 -0000 @@ -93,6 +93,10 @@ int hid_locate(const void *, int, int32_ 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 *desc, int size, int32_t usage, + uint32_t collection); #endif /* _KERNEL */ @@ -353,6 +357,7 @@ int hid_is_collection(const void *, int, #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 +392,12 @@ int hid_is_collection(const void *, int, #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 Index: dev/hid/hidms.c =================================================================== RCS file: /cvs/src/sys/dev/hid/hidms.c,v retrieving revision 1.9 diff -u -p -r1.9 hidms.c --- dev/hid/hidms.c 16 Jun 2022 20:52:38 -0000 1.9 +++ dev/hid/hidms.c 3 Jul 2023 09:04:50 -0000 @@ -61,6 +61,210 @@ int hidmsdebug = 0; #define MOUSE_FLAGS_MASK (HIO_CONST | HIO_RELATIVE) #define NOTMOUSE(f) (((f) & MOUSE_FLAGS_MASK) != HIO_RELATIVE) + +int +stylus_hid_parse(struct hidms *ms, struct hid_data *d, uint32_t *flags) +{ + /* Define stylus reported usages: (maybe macros?) */ + const uint32_t stylus_usage_tip + = HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_TIP_SWITCH); + const uint32_t stylus_usage_barrel + = HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_BARREL_SWITCH); + const uint32_t stylus_usage_sec_barrel = HID_USAGE2( + HUP_WACOM | HUP_DIGITIZERS, HUD_SECONDARY_BARREL_SWITCH); + const uint32_t stylus_usage_in_range + = HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_IN_RANGE); + const uint32_t stylus_usage_quality + = HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_QUALITY); + const uint32_t stylus_usage_x + = HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_X); + const uint32_t stylus_usage_y + = HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_Y); + const uint32_t stylus_usage_pressure + = HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_TIP_PRESSURE); + const uint32_t stylus_usage_distance + = HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_DISTANCE); + + struct hid_item h; + + while (hid_get_item(d, &h)) { + if (h.kind == hid_input && !(h.flags & HIO_CONST)) { + /* 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 stylus_usage_tip: + DPRINTF("Stylus usage tip set\n"); + ms->sc_loc_stylus_btn + [ms->sc_num_stylus_buttons++] = h.loc; + ms->sc_flags |= HIDMS_TIP; + break; + case stylus_usage_barrel: + DPRINTF("Stylus usage barrel set\n"); + ms->sc_loc_stylus_btn + [ms->sc_num_stylus_buttons++] = h.loc; + ms->sc_flags |= HIDMS_BARREL; + break; + case stylus_usage_sec_barrel: + DPRINTF("Stylus usage secondary barrel set\n"); + ms->sc_loc_stylus_btn + [ms->sc_num_stylus_buttons++] = h.loc; + ms->sc_flags |= HIDMS_SEC_BARREL; + break; + case stylus_usage_in_range: + DPRINTF("Stylus usage in range set\n"); + ms->sc_loc_stylus_btn + [ms->sc_num_stylus_buttons++] = h.loc; + break; + case stylus_usage_quality: + DPRINTF("Stylus usage quality set\n"); + ms->sc_loc_stylus_btn + [ms->sc_num_stylus_buttons++] = h.loc; + break; + /* Axes */ + case stylus_usage_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 stylus_usage_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 stylus_usage_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 stylus_usage_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, please report to the devs!\n", + h.usage); +#endif + break; + } + } + if (h.kind == hid_endcollection) + break; + } + hid_end_parse(d); + if (flags != NULL) + *flags = 0; + return (0); +} + +int +pad_buttons_hid_parser(struct hidms *ms, struct hid_data *d, uint32_t *flags) +{ + struct hid_item h; + + while (hid_get_item(d, &h)) { + if (h.kind == hid_input && !(h.flags & HIO_CONST) + && h.usage == HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, + HUD_WACOM_PAD_BUTTONS00 | ms->sc_num_pad_buttons)) { + ms->sc_loc_pad_btn[ms->sc_num_pad_buttons++] = h.loc; + } + if (h.kind == hid_endcollection) + break; + } + hid_end_parse(d); + if (flags != NULL) + *flags = 0; + return (0); +} + +int +hidms_wacom_setup(struct device *self, struct hidms *ms, uint32_t quirks, + int id, void *desc, int dlen) +{ + struct hid_data *global; + uint32_t flags; + int i; + + quirks = 0; + ms->sc_device = self; + ms->sc_rawmode = 1; + + ms->sc_flags = quirks; + + /* 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 ((global = hid_get_collection_data(desc, dlen, + HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_DIGITIZER), + HCOLL_APPLICATION))) { + hid_end_parse(global); + + struct hid_data *stylus_col; + struct hid_data *tablet_keys_col; + struct hid_data *battery_col; + + DPRINTF("found the global collection\n"); + if ((stylus_col = hid_get_collection_data(desc, dlen, + HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_STYLUS), + HCOLL_PHYSICAL))) { + DPRINTF("found stylus collection\n"); + stylus_hid_parse(ms, stylus_col, &flags); + } + if ((tablet_keys_col = hid_get_collection_data(desc, dlen, + HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_TABLET_FKEYS), + HCOLL_PHYSICAL))) { + DPRINTF("found tablet keys collection\n"); + pad_buttons_hid_parser(ms, tablet_keys_col, &flags); + } + if ((battery_col = 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(battery_col); + } + /* + * 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]), &(ms->sc_loc_stylus_btn[i]), + sizeof(struct hid_location)); + for (; i < ms->sc_num_pad_buttons + ms->sc_num_stylus_buttons; i++) + memcpy(&(ms->sc_loc_btn[i]), &(ms->sc_loc_pad_btn[i]), + sizeof(struct hid_location)); + ms->sc_num_buttons = i; + DPRINTF("Buttons inf\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) @@ -74,6 +278,10 @@ hidms_setup(struct device *self, struct ms->sc_rawmode = 1; ms->sc_flags = quirks; + + /* We are setting up a WACOM tablet, not a mouse */ + if (quirks == HIDMS_WACOM_SETUP) + return hidms_wacom_setup(self, ms, quirks, id, desc, dlen); if (!hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), id, hid_input, &ms->sc_loc_x, &flags)) Index: dev/hid/hidmsvar.h =================================================================== RCS file: /cvs/src/sys/dev/hid/hidmsvar.h,v retrieving revision 1.2 diff -u -p -r1.2 hidmsvar.h --- dev/hid/hidmsvar.h 10 Jan 2021 16:32:48 -0000 1.2 +++ dev/hid/hidmsvar.h 3 Jul 2023 09:04:50 -0000 @@ -36,6 +36,8 @@ struct tsscale { int minx, maxx; int miny, maxy; + int minz, maxz; + int minw, maxw; int swapxy; int resx, resy; }; @@ -56,19 +58,39 @@ struct hidms { #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 0xff0d /*Wacom*/ int sc_num_buttons; u_int32_t sc_buttons; /* mouse button status */ struct device *sc_device; struct device *sc_wsmousedev; + /* Wacom */ + int sc_num_pad_buttons; + u_int32_t sc_pad_buttons; /* left to right, or top to bottom */ + int sc_num_stylus_buttons; + u_int32_t sc_stylus_buttons; /* tip, barrel switch, + * secondary barrel switch, + * ... Add the others in order */ + int sc_in_range; + int sc_quality; + + u_int32_t sc_transducer_id_low; + u_int32_t sc_transducer_id_high; + + u_int16_t sc_tool_type; /* locators */ struct hid_location sc_loc_x; struct hid_location sc_loc_y; struct hid_location sc_loc_z; struct hid_location sc_loc_w; struct hid_location sc_loc_btn[MAX_BUTTONS]; + + /* For WACOM tablets */ + struct hid_location sc_loc_pad_btn[MAX_BUTTONS]; + struct hid_location sc_loc_stylus_btn[MAX_BUTTONS]; struct tsscale sc_tsscale; int sc_rawmode; Index: dev/usb/uhidev.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uhidev.c,v retrieving revision 1.108 diff -u -p -r1.108 uhidev.c --- dev/usb/uhidev.c 20 May 2022 05:03:45 -0000 1.108 +++ dev/usb/uhidev.c 3 Jul 2023 09:04:50 -0000 @@ -283,6 +283,36 @@ uhidev_attach(struct device *parent, str free(uha.claimed, M_TEMP, nrepid); uha.claimed = NULL; + /* Special case for Wacom tablets */ + if (uha.uaa->vendor == USB_VENDOR_WACOM) { + /* + * Get all the needed collections. + * For now only 3 seem to be of interest, + * but more can eventually be added. + */ + int repid_collection_list[3] = { 0 }; + repid_collection_list[0] = hid_get_id_of_collection(desc, size, + HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_STYLUS), + HCOLL_PHYSICAL); + repid_collection_list[1] = hid_get_id_of_collection(desc, size, + HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_TABLET_FKEYS), + HCOLL_PHYSICAL); + repid_collection_list[2] = hid_get_id_of_collection(desc, size, + HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUD_WACOM_BATTERY), + HCOLL_PHYSICAL); + for (size_t i = 0; i < 3; i++) + if (repid_collection_list[i]) { + uha.reportid = repid_collection_list[i]; + dev = config_found_sm(self, &uha, NULL, NULL); + if (dev == NULL) + printf("Nothing found for repid: " + "%d\n", uha.reportid); + sc->sc_subdevs[uha.reportid] + = (struct uhidev *)dev; + } + 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 && Index: dev/usb/usbdevs =================================================================== RCS file: /cvs/src/sys/dev/usb/usbdevs,v retrieving revision 1.757 diff -u -p -r1.757 usbdevs --- dev/usb/usbdevs 12 Jun 2023 11:26:24 -0000 1.757 +++ dev/usb/usbdevs 3 Jul 2023 09:04:50 -0000 @@ -4637,6 +4637,7 @@ product WACOM INTUOS_DRAW 0x033b Intuos product WACOM ONE_S 0x037a One S (CTL-472) product WACOM ONE_M 0x037b One M (CTL-672) product WACOM INTUOS_PRO_S 0x0392 Intuos Pro S +product WACOM INTUOS_S 0x0374 Intuos S (CTL-4100) /* WAGO Kontakttechnik products */ product WAGO SERVICECABLE 0x07a6 Service Cable 750-923 Index: dev/usb/usbdevs.h =================================================================== RCS file: /cvs/src/sys/dev/usb/usbdevs.h,v retrieving revision 1.769 diff -u -p -r1.769 usbdevs.h --- dev/usb/usbdevs.h 12 Jun 2023 11:26:54 -0000 1.769 +++ dev/usb/usbdevs.h 3 Jul 2023 09:04:50 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdevs.h,v 1.769 2023/06/12 11:26:54 jsg Exp $ */ +/* $OpenBSD$ */ /* * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. @@ -2117,6 +2117,8 @@ #define USB_PRODUCT_GARMIN_DAKOTA20 0x23c0 /* Dakota 20 */ #define USB_PRODUCT_GARMIN_GPSMAP62S 0x2459 /* GPSmap 62s */ +/* Gaomon */ + /* GCT Semiconductor products */ #define USB_PRODUCT_GCTSEMICON_INSTALL 0x7f40 /* GDM720x MASS storage mode */ @@ -4644,6 +4646,7 @@ #define USB_PRODUCT_WACOM_ONE_S 0x037a /* One S (CTL-472) */ #define USB_PRODUCT_WACOM_ONE_M 0x037b /* One M (CTL-672) */ #define USB_PRODUCT_WACOM_INTUOS_PRO_S 0x0392 /* Intuos Pro S */ +#define USB_PRODUCT_WACOM_INTUOS_S 0x0374 /* Intuos S (CTL-4100) */ /* WAGO Kontakttechnik products */ #define USB_PRODUCT_WAGO_SERVICECABLE 0x07a6 /* Service Cable 750-923 */ Index: dev/usb/usbdevs_data.h =================================================================== RCS file: /cvs/src/sys/dev/usb/usbdevs_data.h,v retrieving revision 1.763 diff -u -p -r1.763 usbdevs_data.h --- dev/usb/usbdevs_data.h 12 Jun 2023 11:26:54 -0000 1.763 +++ dev/usb/usbdevs_data.h 3 Jul 2023 09:04:50 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdevs_data.h,v 1.763 2023/06/12 11:26:54 jsg Exp $ */ +/* $OpenBSD$ */ /* * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. @@ -11908,6 +11908,10 @@ const struct usb_known_product usb_known { USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS_PRO_S, "Intuos Pro S", + }, + { + USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS_S, + "Intuos S (CTL-4100)", }, { USB_VENDOR_WAGO, USB_PRODUCT_WAGO_SERVICECABLE, Index: dev/usb/uwacom.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uwacom.c,v retrieving revision 1.7 diff -u -p -r1.7 uwacom.c --- dev/usb/uwacom.c 8 Oct 2022 06:53:06 -0000 1.7 +++ dev/usb/uwacom.c 3 Jul 2023 09:04:50 -0000 @@ -38,11 +38,32 @@ #define UWACOM_USE_PRESSURE 0x0001 /* button 0 is flaky, use tip pressure */ #define UWACOM_BIG_ENDIAN 0x0002 /* XY reporting byte order */ + +#ifdef UWACOM_DEBUG +#define UWACOM_PACKET_PRINTF(data, len) do { \ + printf("Ox"); \ + for (int i = 0; i < (len); i++) \ + printf("%02x ",*((data)+i)); \ + printf("\n"); \ +} while(0) +#define UWACOM_BUTTON_EVENT(buttons) do { \ + printf("Current button event: 0x%x\n",buttons); \ +} while (0) +#endif + +#define UWACOM_USE_PRESSURE 0x0001 /* button 0 is flaky, use tip pressure */ +#define UWACOM_BIG_ENDIAN 0x0002 /* xy reporting byte order */ + struct uwacom_softc { struct uhidev sc_hdev; struct hidms sc_ms; struct hid_location sc_loc_tip_press; int sc_flags; + int sc_x; + int sc_y; + int sc_z; + int sc_w; + int sc_moved; }; struct cfdriver uwacom_cd = { @@ -53,7 +74,8 @@ struct cfdriver uwacom_cd = { 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 *); @@ -80,7 +102,10 @@ uwacom_match(struct device *parent, void struct uhidev_attach_arg *uha = aux; int size; void *desc; - +#ifdef UWACOM_DEBUG + printf("Wacom Vendor: 0x%x, Product: 0x%x\n",uha->uaa->vendor, + uha->uaa->product); +#endif if (UHIDEV_CLAIM_MULTIPLE_REPORTID(uha)) return (UMATCH_NONE); @@ -90,6 +115,9 @@ uwacom_match(struct device *parent, void uhidev_get_report_desc(uha->parent, &desc, &size); + if (hid_is_collection(desc, size, uha->reportid, + HID_USAGE2(HUP_WACOM | HUP_DIGITIZERS, HUG_POINTER))) + return UMATCH_IFACECLASS; if (!hid_locate(desc, size, HID_USAGE2(HUP_WACOM, HUG_POINTER), uha->reportid, hid_input, NULL, NULL)) return (UMATCH_NONE); @@ -112,41 +140,27 @@ uwacom_attach(struct device *parent, str sc->sc_hdev.sc_udev = uaa->device; sc->sc_hdev.sc_report_id = uha->reportid; - usbd_set_idle(uha->parent->sc_udev, uha->parent->sc_ifaceno, 0, 0); + usbd_status usbd_req_stat = usbd_set_idle(uha->parent->sc_udev, + uha->parent->sc_ifaceno, 0, 0); + if (USBD_NORMAL_COMPLETION != usbd_req_stat) + printf("0x%x\n", usbd_req_stat); uhidev_get_report_desc(uha->parent, &desc, &size); repid = uha->reportid; - sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid); +#ifdef UWACOM_DEBUG + printf("Wacom packet max size: %d\n",sc->sc_hdev.sc_isize); +#endif sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid); sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid); - - ms->sc_device = self; - ms->sc_rawmode = 1; - ms->sc_flags = HIDMS_ABSX | HIDMS_ABSY; - ms->sc_num_buttons = 3; - - ms->sc_loc_x.pos = 8; - ms->sc_loc_x.size = 16; - ms->sc_loc_y.pos = 24; - ms->sc_loc_y.size = 16; - - ms->sc_tsscale.minx = 0; - ms->sc_tsscale.miny = 0; - - ms->sc_loc_btn[0].pos = 0; - ms->sc_loc_btn[0].size = 1; - ms->sc_loc_btn[1].pos = 1; - ms->sc_loc_btn[1].size = 1; - 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 a more modern tablet */ + if (uha->uaa->product == USB_PRODUCT_WACOM_ONE_S + || uha->uaa->product == USB_PRODUCT_WACOM_INTUOS_S) { + static uByte report_buf[2] = { 0x02, 0x02 }; + uhidev_set_report(uha->parent, UHID_FEATURE_REPORT, + sc->sc_hdev.sc_report_id, &report_buf, sizeof(report_buf)); + hidms_setup((struct device *)sc, ms, HIDMS_WACOM_SETUP, + repid, desc, size); } if (uha->uaa->product == USB_PRODUCT_WACOM_INTUOS_DRAW) { @@ -174,40 +188,64 @@ uwacom_intr(struct uhidev *addr, void *b { struct uwacom_softc *sc = (struct uwacom_softc *)addr; struct hidms *ms = &sc->sc_ms; - u_int32_t buttons = 0; + u_int32_t pad_buttons = 0; + u_int32_t stylus_buttons = 0; uint8_t *data = (uint8_t *)buf; - int i, x, y, pressure; + int x, y, pressure, distance; +#ifdef UWACOM_DEBUG + UWACOM_PACKET_PRINTF(data, len); +#endif if (ms->sc_enabled == 0) return; - /* ignore proximity, it will cause invalid button 2 events */ - if ((data[0] & 0xf0) == 0xc0) - 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; + } + + int dx = sc->sc_x - x; + int dy = sc->sc_y - y; + int dz = sc->sc_z/32 - pressure/32; /* Clamp sensitivity to +/-127 */ + int 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_buttons; i++) - if (hid_get_data(data, len, &ms->sc_loc_btn[i])) - buttons |= (1 << i); - - if (sc->sc_flags & UWACOM_USE_PRESSURE) { - pressure = hid_get_data(data, len, &sc->sc_loc_tip_press); - if (pressure > 10) - buttons |= 1; - else - buttons &= ~1; - } - - if (x != 0 || y != 0 || buttons != ms->sc_buttons) { - wsmouse_position(ms->sc_wsmousedev, x, y); - wsmouse_buttons(ms->sc_wsmousedev, buttons); + + for (int i = 0; i < ms->sc_num_stylus_buttons; i++) + if (hid_get_data(data, len, &ms->sc_loc_stylus_btn[i])) + stylus_buttons |= (1 << i); + + for (int i = 0; i < ms->sc_num_pad_buttons; i++) + if (hid_get_data(data, len, &ms->sc_loc_pad_btn[i])) + pad_buttons |= (1 << i); + +#ifdef UWACOM_DEBUG + UWACOM_BUTTON_EVENT(pad_buttons); + UWACOM_BUTTON_EVENT(stylus_buttons); +#endif + + if (x != 0 || y != 0 || pressure != 0 || distance != 0 + || pad_buttons != ms->sc_buttons + || stylus_buttons != ms->sc_buttons) { + wsmouse_buttons(ms->sc_wsmousedev, + (pad_buttons | stylus_buttons)); + wsmouse_motion(ms->sc_wsmousedev, -dx, dy, dz, dw); wsmouse_input_sync(ms->sc_wsmousedev); } }