Commit 00720277 authored by Wei-Ning Huang's avatar Wei-Ning Huang Committed by Jiri Kosina

HID: hid-multitouch: support fine-grain orientation reporting

The current hid-multitouch driver only allow the report of two
orientations, vertical and horizontal. We use the Azimuth orientation
usage 0x3F under the Digitizer usage page to report orientation if the
device supports it.

Changelog:
  v1 -> v2:
   - Fix commit message.
   - Remove resolution reporting for ABS_MT_ORIENTATION.
  v2 -> v3:
   - Fix commit message.
  v3 -> v4:
   - Fix ABS_MT_ORIENTATION ABS param range.
   - Don't set ABS_MT_ORIENTATION in ABS_DG_HEIGHT when it is already
     set by ABS_DG_AZIMUTH.
  v4 -> v5:
   - Improve multi-touch-protocol.rst documentation.
Signed-off-by: default avatarWei-Ning Huang <wnhuang@chromium.org>
Signed-off-by: default avatarWei-Ning Huang <wnhuang@google.com>
Reviewed-by: default avatarDmitry Torokhov <dtor@chromium.org>
Reviewed-by: default avatarHenrik Rydberg <rydberg@bitmath.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 127e71bd
...@@ -269,10 +269,11 @@ ABS_MT_ORIENTATION ...@@ -269,10 +269,11 @@ ABS_MT_ORIENTATION
The orientation of the touching ellipse. The value should describe a signed The orientation of the touching ellipse. The value should describe a signed
quarter of a revolution clockwise around the touch center. The signed value quarter of a revolution clockwise around the touch center. The signed value
range is arbitrary, but zero should be returned for an ellipse aligned with range is arbitrary, but zero should be returned for an ellipse aligned with
the Y axis of the surface, a negative value when the ellipse is turned to the Y axis (north) of the surface, a negative value when the ellipse is
the left, and a positive value when the ellipse is turned to the turned to the left, and a positive value when the ellipse is turned to the
right. When completely aligned with the X axis, the range max should be right. When aligned with the X axis in the positive direction, the range
returned. max should be returned; when aligned with the X axis in the negative
direction, the range -max should be returned.
Touch ellipsis are symmetrical by default. For devices capable of true 360 Touch ellipsis are symmetrical by default. For devices capable of true 360
degree orientation, the reported orientation must exceed the range max to degree orientation, the reported orientation must exceed the range max to
......
...@@ -85,11 +85,12 @@ MODULE_LICENSE("GPL"); ...@@ -85,11 +85,12 @@ MODULE_LICENSE("GPL");
#define MT_IO_FLAGS_PENDING_SLOTS 2 #define MT_IO_FLAGS_PENDING_SLOTS 2
struct mt_slot { struct mt_slot {
__s32 x, y, cx, cy, p, w, h; __s32 x, y, cx, cy, p, w, h, a;
__s32 contactid; /* the device ContactID assigned to this slot */ __s32 contactid; /* the device ContactID assigned to this slot */
bool touch_state; /* is the touch valid? */ bool touch_state; /* is the touch valid? */
bool inrange_state; /* is the finger in proximity of the sensor? */ bool inrange_state; /* is the finger in proximity of the sensor? */
bool confidence_state; /* is the touch made by a finger? */ bool confidence_state; /* is the touch made by a finger? */
bool has_azimuth; /* the contact reports azimuth */
}; };
struct mt_class { struct mt_class {
...@@ -586,8 +587,15 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -586,8 +587,15 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if (!(cls->quirks & MT_QUIRK_NO_AREA)) { if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
cls->sn_height); cls->sn_height);
input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0); /*
* Only set ABS_MT_ORIENTATION if it is not
* already set by the HID_DG_AZIMUTH usage.
*/
if (!test_bit(ABS_MT_ORIENTATION,
hi->input->absbit))
input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0);
} }
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
return 1; return 1;
...@@ -618,6 +626,21 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -618,6 +626,21 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->cc_index = field->index; td->cc_index = field->index;
td->cc_value_index = usage->usage_index; td->cc_value_index = usage->usage_index;
return 1; return 1;
case HID_DG_AZIMUTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_ORIENTATION);
/*
* Azimuth has the range of [0, MAX) representing a full
* revolution. Set ABS_MT_ORIENTATION to a quarter of
* MAX according the definition of ABS_MT_ORIENTATION
*/
input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
-field->logical_maximum / 4,
field->logical_maximum / 4,
cls->sn_move ?
field->logical_maximum / cls->sn_move : 0, 0);
mt_store_field(usage, td, hi);
return 1;
case HID_DG_CONTACTMAX: case HID_DG_CONTACTMAX:
/* we don't set td->last_slot_field as contactcount and /* we don't set td->last_slot_field as contactcount and
* contact max are global to the report */ * contact max are global to the report */
...@@ -710,6 +733,10 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) ...@@ -710,6 +733,10 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
int wide = (s->w > s->h); int wide = (s->w > s->h);
int major = max(s->w, s->h); int major = max(s->w, s->h);
int minor = min(s->w, s->h); int minor = min(s->w, s->h);
int orientation = wide;
if (s->has_azimuth)
orientation = s->a;
/* /*
* divided by two to match visual scale of touch * divided by two to match visual scale of touch
...@@ -726,7 +753,8 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) ...@@ -726,7 +753,8 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy); input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy);
input_event(input, EV_ABS, ABS_MT_DISTANCE, input_event(input, EV_ABS, ABS_MT_DISTANCE,
!s->touch_state); !s->touch_state);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); input_event(input, EV_ABS, ABS_MT_ORIENTATION,
orientation);
input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
...@@ -850,6 +878,22 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, ...@@ -850,6 +878,22 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
break; break;
case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTCOUNT:
break; break;
case HID_DG_AZIMUTH:
/*
* Azimuth is counter-clockwise and ranges from [0, MAX)
* (a full revolution). Convert it to clockwise ranging
* [-MAX/2, MAX/2].
*
* Note that ABS_MT_ORIENTATION require us to report
* the limit of [-MAX/4, MAX/4], but the value can go
* out of range to [-MAX/2, MAX/2] to report an upside
* down ellipsis.
*/
if (value > field->logical_maximum / 2)
value -= field->logical_maximum;
td->curdata.a = -value;
td->curdata.has_azimuth = true;
break;
case HID_DG_TOUCH: case HID_DG_TOUCH:
/* do nothing */ /* do nothing */
break; break;
......
...@@ -281,6 +281,7 @@ struct hid_item { ...@@ -281,6 +281,7 @@ struct hid_item {
#define HID_DG_DEVICECONFIG 0x000d000e #define HID_DG_DEVICECONFIG 0x000d000e
#define HID_DG_DEVICESETTINGS 0x000d0023 #define HID_DG_DEVICESETTINGS 0x000d0023
#define HID_DG_AZIMUTH 0x000d003f
#define HID_DG_CONFIDENCE 0x000d0047 #define HID_DG_CONFIDENCE 0x000d0047
#define HID_DG_WIDTH 0x000d0048 #define HID_DG_WIDTH 0x000d0048
#define HID_DG_HEIGHT 0x000d0049 #define HID_DG_HEIGHT 0x000d0049
......
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