Commit ba6b055e authored by Benjamin Tissoires's avatar Benjamin Tissoires Committed by Jiri Kosina

HID: input: enable Totem on the Dell Canvas 27

The Dell Canvas 27 has a tool that can be put on the surface and acts
as a dial. The firmware processes the detection of the tool and forward
regular HID reports with X, Y, Azimuth, rotation, width/height.

The firmware also exports Contact ID, Countact Count which may hint that
several totems can be used at the same time (the FW only supports one).

We can tell that MT_TOOL_DIAL will be reported by setting the min/max
of ABS_MT_TOOL_TYPE to MT_TOOL_DIAL.

This tool is aimed at being used by the system and not the applications,
so the user space processing should not go through the regular touch
inputs.
We set INPUT_PROP_DIRECT which applies ID_INPUT_TOUCHSCREEN to this new
type of devices, but we will counter this for the time being with the
special udev hwdb entry mentioned above.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=1511846Acked-by: default avatarPeter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 01eaac7e
...@@ -1550,6 +1550,9 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid, ...@@ -1550,6 +1550,9 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid,
case HID_GD_WIRELESS_RADIO_CTLS: case HID_GD_WIRELESS_RADIO_CTLS:
suffix = "Wireless Radio Control"; suffix = "Wireless Radio Control";
break; break;
case HID_GD_SYSTEM_MULTIAXIS:
suffix = "System Multi Axis";
break;
default: default:
break; break;
} }
......
...@@ -665,7 +665,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -665,7 +665,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* /*
* Model touchscreens providing buttons as touchpads. * Model touchscreens providing buttons as touchpads.
*/ */
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { if (field->application == HID_DG_TOUCHSCREEN &&
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
app->mt_flags |= INPUT_MT_POINTER; app->mt_flags |= INPUT_MT_POINTER;
td->inputmode_value = MT_INPUTMODE_TOUCHPAD; td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
} }
...@@ -692,6 +693,19 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -692,6 +693,19 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
set_abs(hi->input, code, field, cls->sn_move); set_abs(hi->input, code, field, cls->sn_move);
/*
* A system multi-axis that exports X and Y has a high
* chance of being used directly on a surface
*/
if (field->application == HID_GD_SYSTEM_MULTIAXIS) {
__set_bit(INPUT_PROP_DIRECT,
hi->input->propbit);
input_set_abs_params(hi->input,
ABS_MT_TOOL_TYPE,
MT_TOOL_DIAL,
MT_TOOL_DIAL, 0, 0);
}
return 1; return 1;
case HID_GD_Y: case HID_GD_Y:
if (prev_usage && (prev_usage->hid == usage->hid)) { if (prev_usage && (prev_usage->hid == usage->hid)) {
...@@ -725,7 +739,9 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -725,7 +739,9 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
MT_STORE_FIELD(confidence_state); MT_STORE_FIELD(confidence_state);
return 1; return 1;
case HID_DG_TIPSWITCH: case HID_DG_TIPSWITCH:
input_set_capability(hi->input, EV_KEY, BTN_TOUCH); if (field->application != HID_GD_SYSTEM_MULTIAXIS)
input_set_capability(hi->input,
EV_KEY, BTN_TOUCH);
MT_STORE_FIELD(tip_state); MT_STORE_FIELD(tip_state);
return 1; return 1;
case HID_DG_CONTACTID: case HID_DG_CONTACTID:
...@@ -802,6 +818,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -802,6 +818,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->application == HID_DG_TOUCHPAD && field->application == HID_DG_TOUCHPAD &&
(usage->hid & HID_USAGE) > 1) (usage->hid & HID_USAGE) > 1)
code--; code--;
if (field->application == HID_GD_SYSTEM_MULTIAXIS)
code = BTN_0 + ((usage->hid - 1) & HID_USAGE);
hid_map_usage(hi, usage, bit, max, EV_KEY, code); hid_map_usage(hi, usage, bit, max, EV_KEY, code);
input_set_capability(hi->input, EV_KEY, code); input_set_capability(hi->input, EV_KEY, code);
return 1; return 1;
...@@ -899,6 +919,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, ...@@ -899,6 +919,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
bool inrange_state = false; bool inrange_state = false;
int active; int active;
int slotnum; int slotnum;
int tool = MT_TOOL_FINGER;
if (!slot) if (!slot)
return -EINVAL; return -EINVAL;
...@@ -939,8 +960,11 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, ...@@ -939,8 +960,11 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
active = (*slot->tip_state || inrange_state) && confidence_state; active = (*slot->tip_state || inrange_state) && confidence_state;
if (app->application == HID_GD_SYSTEM_MULTIAXIS)
tool = MT_TOOL_DIAL;
input_mt_slot(input, slotnum); input_mt_slot(input, slotnum);
input_mt_report_slot_state(input, MT_TOOL_FINGER, active); input_mt_report_slot_state(input, tool, active);
if (active) { if (active) {
/* this finger is in proximity of the sensor */ /* this finger is in proximity of the sensor */
int wide = (*slot->w > *slot->h); int wide = (*slot->w > *slot->h);
...@@ -1203,6 +1227,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -1203,6 +1227,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->application != HID_GD_SYSTEM_CONTROL && field->application != HID_GD_SYSTEM_CONTROL &&
field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_CP_CONSUMER_CONTROL &&
field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_WIRELESS_RADIO_CTLS &&
field->application != HID_GD_SYSTEM_MULTIAXIS &&
!(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) application->quirks & MT_QUIRK_ASUS_CUSTOM_UP))
return -1; return -1;
...@@ -1230,9 +1255,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -1230,9 +1255,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1; return 1;
} }
if (rdata->is_mt_collection && if (rdata->is_mt_collection)
(field->application == HID_DG_TOUCHSCREEN ||
field->application == HID_DG_TOUCHPAD))
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
application); application);
...@@ -1244,15 +1267,11 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, ...@@ -1244,15 +1267,11 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage, struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max) unsigned long **bit, int *max)
{ {
/* struct mt_device *td = hid_get_drvdata(hdev);
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" struct mt_report_data *rdata;
* for the stylus.
*/
if (field->physical == HID_DG_STYLUS)
return 0;
if (field->application == HID_DG_TOUCHSCREEN || rdata = mt_find_report_data(td, field->report);
field->application == HID_DG_TOUCHPAD) { if (rdata && rdata->is_mt_collection) {
/* We own these mappings, tell hid-input to ignore them */ /* We own these mappings, tell hid-input to ignore them */
return -1; return -1;
} }
...@@ -1460,6 +1479,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -1460,6 +1479,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
case HID_GD_SYSTEM_CONTROL: case HID_GD_SYSTEM_CONTROL:
case HID_CP_CONSUMER_CONTROL: case HID_CP_CONSUMER_CONTROL:
case HID_GD_WIRELESS_RADIO_CTLS: case HID_GD_WIRELESS_RADIO_CTLS:
case HID_GD_SYSTEM_MULTIAXIS:
/* already handled by hid core */ /* already handled by hid core */
break; break;
case HID_DG_TOUCHSCREEN: case HID_DG_TOUCHSCREEN:
......
...@@ -190,6 +190,12 @@ struct hid_item { ...@@ -190,6 +190,12 @@ struct hid_item {
* http://www.usb.org/developers/hidpage/HUTRR40RadioHIDUsagesFinal.pdf * http://www.usb.org/developers/hidpage/HUTRR40RadioHIDUsagesFinal.pdf
*/ */
#define HID_GD_WIRELESS_RADIO_CTLS 0x0001000c #define HID_GD_WIRELESS_RADIO_CTLS 0x0001000c
/*
* System Multi-Axis, see:
* http://www.usb.org/developers/hidpage/HUTRR62_-_Generic_Desktop_CA_for_System_Multi-Axis_Controllers.txt
*/
#define HID_GD_SYSTEM_MULTIAXIS 0x0001000e
#define HID_GD_X 0x00010030 #define HID_GD_X 0x00010030
#define HID_GD_Y 0x00010031 #define HID_GD_Y 0x00010031
#define HID_GD_Z 0x00010032 #define HID_GD_Z 0x00010032
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment