@@ -48,6 +48,9 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
+#define MY(fmt,arg...) printk(KERN_INFO "%s: " fmt "\n", __func__, ##arg)
+// #define MY(fmt,arg...)
+
/* quirks to control the device */
#define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0)
#define MT_QUIRK_SLOT_IS_CONTACTID BIT(1)
@@ -69,6 +72,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_ASUS_CUSTOM_UP BIT(17)
#define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18)
#define MT_QUIRK_SEPARATE_APP_REPORT BIT(19)
+#define MT_QUIRK_NON_MT_PEN BIT(20)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -99,6 +103,9 @@ struct mt_usages {
bool *tip_state; /* is the touch valid? */
bool *inrange_state; /* is the finger in proximity of the sensor? */
bool *confidence_state; /* is the touch made by a finger? */
+ bool *barrel_state;
+ bool *invert_state;
+ bool *eraser_state;
};
struct mt_application {
@@ -152,6 +159,7 @@ struct mt_report_data {
struct hid_report *report;
struct mt_application *application;
bool is_mt_collection;
+ bool non_mt_pen;
};
struct mt_device {
@@ -206,6 +214,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_GOOGLE 0x0111
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
#define MT_CLS_SMART_TECH 0x0113
+#define MT_CLS_NON_MT_PEN 0x0114
#define MT_DEFAULT_MAXCONTACT 10
#define MT_MAX_MAXCONTACT 250
@@ -363,6 +372,9 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_SEPARATE_APP_REPORT,
},
+ { .name = MT_CLS_NON_MT_PEN,
+ .quirks = MT_QUIRK_NON_MT_PEN,
+ },
{ }
};
@@ -512,6 +524,9 @@ static struct mt_usages *mt_allocate_usage(struct hid_device *hdev,
usage->tip_state = DEFAULT_FALSE;
usage->inrange_state = DEFAULT_FALSE;
usage->confidence_state = DEFAULT_TRUE;
+ usage->barrel_state = DEFAULT_FALSE;
+ usage->invert_state = DEFAULT_FALSE;
+ usage->eraser_state = DEFAULT_FALSE;
list_add_tail(&usage->list, &application->mt_usages);
@@ -864,6 +879,67 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0;
}
+static int mt_pen_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max, struct mt_application *app)
+{
+ struct mt_device *td = hid_get_drvdata(hdev);
+ struct mt_class *cls = &td->mtclass;
+
+ MY("application:%s:%x:%x", hdev->name, field->application, usage->hid);
+
+ switch (usage->hid & HID_USAGE_PAGE) {
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ __set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
+ set_abs(hi->input, ABS_X, field, cls->sn_move);
+ MT_STORE_FIELD(x);
+ return 1;
+ case HID_GD_Y:
+ set_abs(hi->input, ABS_Y, field, cls->sn_move);
+ MT_STORE_FIELD(y);
+ return 1;
+ }
+ return -1;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ input_set_capability(hi->input,
+ EV_KEY, BTN_TOOL_PEN);
+ input_set_abs_params(hi->input,
+ ABS_DISTANCE, 0, 1, 0, 0);
+ MT_STORE_FIELD(inrange_state);
+ return 1;
+ case HID_DG_TIPSWITCH:
+ input_set_capability(hi->input,
+ EV_KEY, BTN_TOUCH);
+ MT_STORE_FIELD(tip_state);
+ return 1;
+ case HID_DG_BARRELSWITCH:
+ input_set_capability(hi->input,
+ EV_KEY, BTN_STYLUS2);
+ MT_STORE_FIELD(barrel_state);
+ return 1;
+ case HID_DG_INVERT:
+ MT_STORE_FIELD(invert_state);
+ return 1;
+ case HID_DG_ERASER:
+ MT_STORE_FIELD(eraser_state);
+ return 1;
+ case HID_DG_TIPPRESSURE:
+ set_abs(hi->input, ABS_PRESSURE, field,
+ cls->sn_pressure);
+ MT_STORE_FIELD(p);
+ return 1;
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
struct mt_usages *slot,
struct input_dev *input)
@@ -1229,6 +1305,43 @@ static void mt_touch_report(struct hid_device *hid,
clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
}
+static void mt_pen_report(struct hid_device *hid,
+ struct mt_report_data *rdata)
+{
+ struct mt_application *app = rdata->application;
+ struct mt_usages *usage;
+ struct input_dev *input = rdata->report->field[0]->hidinput->input;
+ bool tip_state;
+ int p;
+
+ if (!(usage = list_first_entry_or_null(&app->mt_usages,
+ struct mt_usages, list)))
+ return;
+
+
+ tip_state = *usage->tip_state;
+ p = *usage->p;
+ // tip_state = tip_state && p > 100;
+ // if (!tip_state)
+ // p = 0;
+
+ MY("inr:tip:tip:bar:inv:era %d:%d:%d:%d:%d:%d",
+ *usage->inrange_state,
+ *usage->tip_state,
+ tip_state,
+ *usage->barrel_state,
+ *usage->invert_state,
+ *usage->eraser_state
+ );
+ input_report_key(input, BTN_TOOL_PEN, *usage->inrange_state);
+ input_report_key(input, BTN_TOUCH, tip_state);
+ input_report_key(input, BTN_STYLUS2, *usage->barrel_state);
+ input_event(input, EV_ABS, ABS_X, *usage->x);
+ input_event(input, EV_ABS, ABS_Y, *usage->y);
+ input_event(input, EV_ABS, ABS_PRESSURE, p);
+ input_event(input, EV_ABS, ABS_DISTANCE, !tip_state);
+}
+
static int mt_touch_input_configured(struct hid_device *hdev,
struct hid_input *hi,
struct mt_application *app)
@@ -1334,6 +1447,14 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
}
+ if (field->application == HID_DG_PEN &&
+ application->quirks & MT_QUIRK_NON_MT_PEN) {
+ rdata->is_mt_collection = false;
+ rdata->non_mt_pen = true;
+ return mt_pen_input_mapping(hdev, hi, field, usage, bit, max,
+ application);
+ }
+
if (rdata->is_mt_collection)
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
application);
@@ -1357,7 +1478,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct mt_report_data *rdata;
rdata = mt_find_report_data(td, field->report);
- if (rdata && rdata->is_mt_collection) {
+ if (rdata && (rdata->is_mt_collection || rdata->non_mt_pen)) {
/* We own these mappings, tell hid-input to ignore them */
return -1;
}
@@ -1391,6 +1512,8 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
rdata = mt_find_report_data(td, report);
if (rdata && rdata->is_mt_collection)
return mt_touch_report(hid, rdata);
+ if (rdata && rdata->non_mt_pen)
+ mt_pen_report(hid, rdata);
if (field && field->hidinput && field->hidinput->input)
input_sync(field->hidinput->input);
@@ -2120,6 +2243,11 @@ static const struct hid_device_id mt_devices[] = {
HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) },
+ { .driver_data = MT_CLS_NON_MT_PEN,
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+ I2C_VENDOR_ID_GOODIX,
+ I2C_DEVICE_ID_GOODIX_0113) },
+
/* Generic MT device */
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
Hello guys, thanks to all of you for your great work! Please, answer, is pen hovering ever possible using hid-multitouch driver? If I remove hid-multitouch - hovering works well with hid-generic. I can't unbind from hid-multitouch and bind to hid-generic: bind fails with "No such device". I tried to modify hid-multitouch, but was not able to get hovering work using multitouch reports. Then I noticed, that wacom uses non-multitouch reports for their pen devices, and added a quirk to hid-multitouch that changes pen's behavior to non-multitouch (patch attached). It works, but the way must be wrong( How should one proceed in right way? Thank you very much! Dmitry Mastykin From 2ae5139e065975d29bab768ce87fc916d3519b48 Mon Sep 17 00:00:00 2001 From: Dmitry Mastykin <dmastykin@astralinux.ru> Date: Fri, 21 Aug 2020 11:45:52 +0300 Subject: temp