This adds support for Hybrid mode for Windows Precision Touchpads (ihidev/imt). If yours only works with one finger, this should fix that.
This also changes the way SET_REPORTs are sent to put the touchpad into touchpad mode, now as two bytes. This is needed on the touchpad on my Huawei and matches the bytes that Linux outputs. It also renames the internal hidmt_input struct to avoid conflicting with hidmt_input function. I'd appreciate tests on any machines with ihidev/imt to make sure this doesn't break. (These are three separate commits but are combined in one diff for testing.) Index: sys/dev/hid/hidmt.c =================================================================== RCS file: /cvs/src/sys/dev/hid/hidmt.c,v retrieving revision 1.3 diff -u -p -u -p -r1.3 hidmt.c --- sys/dev/hid/hidmt.c 8 Oct 2017 10:13:42 -0000 1.3 +++ sys/dev/hid/hidmt.c 8 Oct 2017 14:08:09 -0000 @@ -4,6 +4,7 @@ * standard * * https://msdn.microsoft.com/en-us/library/windows/hardware/dn467314%28v=vs.85%29.aspx + * https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/touchscreen-packet-reporting-modes * * Copyright (c) 2016 joshua stein <j...@openbsd.org> * @@ -167,7 +168,7 @@ hidmt_setup(struct device *self, struct hd = hid_start_parse(desc, dlen, hid_input); while (hid_get_item(hd, &h)) { - struct hidmt_input *input; + struct hidmt_data *input; if (h.report_ID != mt->sc_rep_input) continue; @@ -275,16 +276,16 @@ hidmt_detach(struct hidmt *mt, int flags } int -hidmt_set_input_mode(struct hidmt *mt, int mode) +hidmt_set_input_mode(struct hidmt *mt, uint16_t mode) { return mt->hidev_set_report(mt->sc_device, hid_feature, - mt->sc_rep_config, &mode, 1); + mt->sc_rep_config, &mode, 2); } void hidmt_input(struct hidmt *mt, uint8_t *data, u_int len) { - struct hidmt_input *hi; + struct hidmt_data *hi; struct hidmt_contact hc; int32_t d, firstu = 0; int contactcount = 0, seencontacts = 0, tips = 0, i, s, z; @@ -307,8 +308,29 @@ hidmt_input(struct hidmt *mt, uint8_t *d */ SIMPLEQ_FOREACH(hi, &mt->sc_inputs, entry) { if (hi->usage == HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTCOUNT)) - contactcount = hid_get_udata(data, len, - &hi->loc); + contactcount = hid_get_udata(data, len, &hi->loc); + } + + if (contactcount) + mt->sc_cur_contactcount = contactcount; + else { + /* + * "In Hybrid mode, the number of contacts that can be reported + * in one report is less than the maximum number of contacts + * that the device supports. For example, a device that supports + * a maximum of 4 concurrent physical contacts, can set up its + * top-level collection to deliver a maximum of two contacts in + * one report. If four contact points are present, the device + * can break these up into two serial reports that deliver two + * contacts each. + * + * "When a device delivers data in this manner, the Contact + * Count usage value in the first report should reflect the + * total number of contacts that are being delivered in the + * hybrid reports. The other serial reports should have a + * contact count of zero (0)." + */ + contactcount = mt->sc_cur_contactcount; } if (!contactcount) { @@ -373,7 +395,8 @@ hidmt_input(struct hidmt *mt, uint8_t *d /* these will only appear once per report */ case HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTCOUNT): - contactcount = d; + if (d) + contactcount = d; break; case HID_USAGE2(HUP_BUTTON, 0x01): mt->sc_button = (d != 0); Index: sys/dev/hid/hidmtvar.h =================================================================== RCS file: /cvs/src/sys/dev/hid/hidmtvar.h,v retrieving revision 1.2 diff -u -p -u -p -r1.2 hidmtvar.h --- sys/dev/hid/hidmtvar.h 8 Oct 2017 10:13:42 -0000 1.2 +++ sys/dev/hid/hidmtvar.h 8 Oct 2017 14:08:09 -0000 @@ -15,10 +15,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct hidmt_input { +struct hidmt_data { int32_t usage; struct hid_location loc; - SIMPLEQ_ENTRY(hidmt_input) entry; + SIMPLEQ_ENTRY(hidmt_data) entry; }; struct hidmt_contact { @@ -49,7 +49,7 @@ struct hidmt { int sc_rep_config; int sc_rep_cap; - SIMPLEQ_HEAD(, hidmt_input) sc_inputs; + SIMPLEQ_HEAD(, hidmt_data) sc_inputs; struct device *sc_wsmousedev; @@ -61,10 +61,11 @@ struct hidmt { int sc_resx, sc_resy; struct hidmt_contact sc_contacts[HIDMT_MAX_CONTACTS]; + int sc_cur_contactcount; int sc_button; }; -int hidmt_set_input_mode(struct hidmt *, int); +int hidmt_set_input_mode(struct hidmt *, uint16_t); #define HIDMT_INPUT_MODE_MT 0x3 void hidmt_attach(struct hidmt *, const struct wsmouse_accessops *);