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);
        }
 }

Reply via email to