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