Good day, I am currently trying to work on an implementation of a driver for the WACOM tablet on openBSD I am therefore submitting this diff so that it could potentially be evaluated. Please if you have a moment, could you have a look at this diff? I have tested it with my Wacom tablet and it seems to work correctly, the coding style is normally respected, but I apologize in advance if my keen eyes have missed out something.
diff --git a/sys/dev/hid/hid.c b/sys/dev/hid/hid.c index c758764f17a..20c0c501e91 100644 --- a/sys/dev/hid/hid.c +++ b/sys/dev/hid/hid.c @@ -657,3 +657,49 @@ 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__); + return hi.report_ID; + } + } + DPRINTF("%s: not found\n", __func__); + hid_end_parse(hd); + return 0; +} diff --git a/sys/dev/hid/hid.h b/sys/dev/hid/hid.h index 7400e920bc2..78bc4c403c5 100644 --- a/sys/dev/hid/hid.h +++ b/sys/dev/hid/hid.h @@ -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 *desc, int size, int32_t usage, uint32_t collection); #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..ec5c8d34d1b 100644 --- a/sys/dev/hid/hidms.c +++ b/sys/dev/hid/hidms.c @@ -37,6 +37,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/kernel.h> #include <sys/device.h> #include <sys/ioctl.h> @@ -61,6 +62,219 @@ 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, its not really needed + * Ignore the usage 0x10AC which is the debug collection, and + * ignore firmware collection and other collections that we + * will omit 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) @@ -75,6 +289,10 @@ hidms_setup(struct device *self, struct hidms *ms, uint32_t quirks, 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)) ms->sc_loc_x.size = 0; diff --git a/sys/dev/hid/hidmsvar.h b/sys/dev/hid/hidmsvar.h index a430b90ddae..55105ec11fa 100644 --- a/sys/dev/hid/hidmsvar.h +++ b/sys/dev/hid/hidmsvar.h @@ -36,6 +36,8 @@ struct tsscale { int minx, maxx; int miny, maxy; + int minz, maxz; + int minw, maxw; int swapxy; int resx, resy; }; @@ -56,13 +58,27 @@ 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; @@ -70,6 +86,10 @@ struct hidms { 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; }; diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c index 26b5b04088d..3c045a26051 100644 --- a/sys/dev/usb/uhidev.c +++ b/sys/dev/usb/uhidev.c @@ -283,6 +283,43 @@ uhidev_attach(struct device *parent, struct device *self, void *aux) free(uha.claimed, M_TEMP, nrepid); uha.claimed = NULL; + /* Secial 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 && diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index edb86ebbf5e..8c7cb13a925 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -637,6 +637,7 @@ vendor ARDUINO 0x2341 Arduino SA vendor TPLINK 0x2357 TP-Link vendor WMR 0x2405 West Mountain Radio vendor TRIPPLITE 0x2478 Tripp-Lite +vendor GAOMON 0x256c Gaomon vendor HAILUCK 0x258a HAILUCK Co., Ltd vendor ARUBA 0x2626 Aruba vendor XIAOMI 0x2717 Xiaomi @@ -2109,6 +2110,9 @@ product GARMIN IQUE3600 0x0004 Ique 3600 product GARMIN DAKOTA20 0x23c0 Dakota 20 product GARMIN GPSMAP62S 0x2459 GPSmap 62s +/* Gaomon */ +product GAOMON M10K 0x006e M10K + /* GCT Semiconductor products */ product GCTSEMICON INSTALL 0x7f40 GDM720x MASS storage mode @@ -4633,6 +4637,7 @@ product WACOM INTUOS_DRAW 0x033b Intuos Draw (CTL-490) 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 diff --git a/sys/dev/usb/usbdevs.h b/sys/dev/usb/usbdevs.h index 022a71013f3..75e938e5614 100644 --- a/sys/dev/usb/usbdevs.h +++ b/sys/dev/usb/usbdevs.h @@ -644,6 +644,7 @@ #define USB_VENDOR_TPLINK 0x2357 /* TP-Link */ #define USB_VENDOR_WMR 0x2405 /* West Mountain Radio */ #define USB_VENDOR_TRIPPLITE 0x2478 /* Tripp-Lite */ +#define USB_VENDOR_GAOMON 0x256c /* Gaomon */ #define USB_VENDOR_HAILUCK 0x258a /* HAILUCK Co., Ltd */ #define USB_VENDOR_ARUBA 0x2626 /* Aruba */ #define USB_VENDOR_XIAOMI 0x2717 /* Xiaomi */ @@ -2116,6 +2117,9 @@ #define USB_PRODUCT_GARMIN_DAKOTA20 0x23c0 /* Dakota 20 */ #define USB_PRODUCT_GARMIN_GPSMAP62S 0x2459 /* GPSmap 62s */ +/* Gaomon */ +#define USB_PRODUCT_GAOMON_M10K 0x006e /* M10K */ + /* GCT Semiconductor products */ #define USB_PRODUCT_GCTSEMICON_INSTALL 0x7f40 /* GDM720x MASS storage mode */ @@ -4640,6 +4644,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 */ diff --git a/sys/dev/usb/usbdevs_data.h b/sys/dev/usb/usbdevs_data.h index 92c80f0cede..20ba8354fa7 100644 --- a/sys/dev/usb/usbdevs_data.h +++ b/sys/dev/usb/usbdevs_data.h @@ -4337,6 +4337,10 @@ const struct usb_known_product usb_known_products[] = { USB_VENDOR_GARMIN, USB_PRODUCT_GARMIN_GPSMAP62S, "GPSmap 62s", }, + { + USB_VENDOR_GAOMON, USB_PRODUCT_GAOMON_M10K, + "M10K", + }, { USB_VENDOR_GCTSEMICON, USB_PRODUCT_GCTSEMICON_INSTALL, "GDM720x MASS storage mode", @@ -11905,6 +11909,10 @@ const struct usb_known_product usb_known_products[] = { 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, "Service Cable 750-923", @@ -14649,6 +14657,10 @@ const struct usb_known_vendor usb_known_vendors[] = { USB_VENDOR_TRIPPLITE, "Tripp-Lite", }, + { + USB_VENDOR_GAOMON, + "Gaomon", + }, { USB_VENDOR_HAILUCK, "HAILUCK Co., Ltd", diff --git a/sys/dev/usb/uwacom.c b/sys/dev/usb/uwacom.c index f9af276a641..fde5b5cecd7 100644 --- a/sys/dev/usb/uwacom.c +++ b/sys/dev/usb/uwacom.c @@ -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,9 @@ uwacom_match(struct device *parent, void *match, void *aux) 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 +114,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, 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 +139,26 @@ uwacom_attach(struct device *parent, struct device *self, void *aux) 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; + sc->sc_hdev.sc_fsize + = hid_report_size(desc, size, hid_feature, repid); + /* 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 +186,64 @@ 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; + 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 the sensetivity to be in the range of -127 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); } }