From patchwork Fri Aug 21 10:24:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Mastykin X-Patchwork-Id: 11728763 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0A7BD739 for ; Fri, 21 Aug 2020 10:24:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E4EF320732 for ; Fri, 21 Aug 2020 10:24:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728462AbgHUKYp (ORCPT ); Fri, 21 Aug 2020 06:24:45 -0400 Received: from mail.astralinux.ru ([217.74.38.120]:53899 "EHLO astralinux.ru" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728149AbgHUKYo (ORCPT ); Fri, 21 Aug 2020 06:24:44 -0400 Received: from [46.148.196.138] (account dmastykin@astralinux.ru HELO [192.168.32.67]) by astralinux.ru (CommuniGate Pro SMTP 6.2.7) with ESMTPSA id 2215021 for linux-input@vger.kernel.org; Fri, 21 Aug 2020 13:21:04 +0300 From: Dmitry Mastykin Subject: hid-multitouch: is pen hovering ever possible? To: linux-input@vger.kernel.org Message-ID: <0322c725-9eea-2947-bcf1-89958d91db92@astralinux.ru> Date: Fri, 21 Aug 2020 13:24:40 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.9.0 MIME-Version: 1.0 Content-Language: en-US Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org 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 Date: Fri, 21 Aug 2020 11:45:52 +0300 Subject: temp diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 362805ddf377..b6c593e88fc4 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -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) },