mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-29 23:53:32 +00:00
HID: wacom: implement the finger part of the HID generic handling
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Acked-by: Jason Gerecke <killertofu@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
parent
7704ac9373
commit
5ae6e89f74
3 changed files with 164 additions and 3 deletions
|
@ -109,6 +109,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
|
|||
{
|
||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||
struct wacom_features *features = &wacom->wacom_wac.features;
|
||||
struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
|
||||
u8 *data;
|
||||
int ret;
|
||||
|
||||
|
@ -128,6 +129,16 @@ static void wacom_feature_mapping(struct hid_device *hdev,
|
|||
kfree(data);
|
||||
}
|
||||
break;
|
||||
case HID_DG_INPUTMODE:
|
||||
/* Ignore if value index is out of bounds. */
|
||||
if (usage->usage_index >= field->report_count) {
|
||||
dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
|
||||
break;
|
||||
}
|
||||
|
||||
hid_data->inputmode = field->report->id;
|
||||
hid_data->inputmode_index = usage->usage_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,6 +266,25 @@ static void wacom_parse_hid(struct hid_device *hdev,
|
|||
}
|
||||
}
|
||||
|
||||
static int wacom_hid_set_device_mode(struct hid_device *hdev)
|
||||
{
|
||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||
struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
|
||||
struct hid_report *r;
|
||||
struct hid_report_enum *re;
|
||||
|
||||
if (hid_data->inputmode < 0)
|
||||
return 0;
|
||||
|
||||
re = &(hdev->report_enum[HID_FEATURE_REPORT]);
|
||||
r = re->report_id_hash[hid_data->inputmode];
|
||||
if (r) {
|
||||
r->field[0]->value[hid_data->inputmode_index] = 2;
|
||||
hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
|
||||
int length, int mode)
|
||||
{
|
||||
|
@ -347,6 +377,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
|
|||
if (hdev->bus == BUS_BLUETOOTH)
|
||||
return wacom_bt_query_tablet_data(hdev, 1, features);
|
||||
|
||||
if (features->type == HID_GENERIC)
|
||||
return wacom_hid_set_device_mode(hdev);
|
||||
|
||||
if (features->device_type == BTN_TOOL_FINGER) {
|
||||
if (features->type > TABLETPC) {
|
||||
/* MT Tablet PC touch */
|
||||
|
@ -1451,9 +1484,6 @@ static int wacom_probe(struct hid_device *hdev,
|
|||
error);
|
||||
}
|
||||
|
||||
/* Note that if query fails it is not a hard failure */
|
||||
wacom_query_tablet_data(hdev, features);
|
||||
|
||||
if (features->type == HID_GENERIC)
|
||||
connect_mask |= HID_CONNECT_DRIVER;
|
||||
|
||||
|
@ -1464,6 +1494,9 @@ static int wacom_probe(struct hid_device *hdev,
|
|||
goto fail_hw_start;
|
||||
}
|
||||
|
||||
/* Note that if query fails it is not a hard failure */
|
||||
wacom_query_tablet_data(hdev, features);
|
||||
|
||||
if (features->quirks & WACOM_QUIRK_MONITOR)
|
||||
error = hid_hw_open(hdev);
|
||||
|
||||
|
|
|
@ -1372,6 +1372,117 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
|
|||
}
|
||||
}
|
||||
|
||||
static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
|
||||
struct hid_field *field, struct hid_usage *usage)
|
||||
{
|
||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||
struct input_dev *input = wacom_wac->input;
|
||||
unsigned touch_max = wacom_wac->features.touch_max;
|
||||
|
||||
switch (usage->hid) {
|
||||
case HID_GD_X:
|
||||
if (touch_max == 1)
|
||||
wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4);
|
||||
else
|
||||
wacom_map_usage(wacom, usage, field, EV_ABS,
|
||||
ABS_MT_POSITION_X, 4);
|
||||
break;
|
||||
case HID_GD_Y:
|
||||
if (touch_max == 1)
|
||||
wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4);
|
||||
else
|
||||
wacom_map_usage(wacom, usage, field, EV_ABS,
|
||||
ABS_MT_POSITION_Y, 4);
|
||||
break;
|
||||
case HID_DG_CONTACTID:
|
||||
input_mt_init_slots(input, wacom_wac->features.touch_max,
|
||||
INPUT_MT_DIRECT);
|
||||
break;
|
||||
case HID_DG_INRANGE:
|
||||
break;
|
||||
case HID_DG_INVERT:
|
||||
break;
|
||||
case HID_DG_TIPSWITCH:
|
||||
wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int wacom_wac_finger_event(struct hid_device *hdev,
|
||||
struct hid_field *field, struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||
|
||||
switch (usage->hid) {
|
||||
case HID_GD_X:
|
||||
wacom_wac->hid_data.x = value;
|
||||
break;
|
||||
case HID_GD_Y:
|
||||
wacom_wac->hid_data.y = value;
|
||||
break;
|
||||
case HID_DG_CONTACTID:
|
||||
wacom_wac->hid_data.id = value;
|
||||
break;
|
||||
case HID_DG_TIPSWITCH:
|
||||
wacom_wac->hid_data.tipswitch = value;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wacom_wac_finger_mt_report(struct wacom_wac *wacom_wac,
|
||||
struct input_dev *input, bool touch)
|
||||
{
|
||||
int slot;
|
||||
struct hid_data *hid_data = &wacom_wac->hid_data;
|
||||
|
||||
slot = input_mt_get_slot_by_key(input, hid_data->id);
|
||||
|
||||
input_mt_slot(input, slot);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
|
||||
if (touch) {
|
||||
input_report_abs(input, ABS_MT_POSITION_X, hid_data->x);
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, hid_data->y);
|
||||
}
|
||||
input_mt_sync_frame(input);
|
||||
}
|
||||
|
||||
static void wacom_wac_finger_single_touch_report(struct wacom_wac *wacom_wac,
|
||||
struct input_dev *input, bool touch)
|
||||
{
|
||||
struct hid_data *hid_data = &wacom_wac->hid_data;
|
||||
|
||||
if (touch) {
|
||||
input_report_abs(input, ABS_X, hid_data->x);
|
||||
input_report_abs(input, ABS_Y, hid_data->y);
|
||||
}
|
||||
input_report_key(input, BTN_TOUCH, touch);
|
||||
}
|
||||
|
||||
static void wacom_wac_finger_report(struct hid_device *hdev,
|
||||
struct hid_report *report)
|
||||
{
|
||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||
struct input_dev *input = wacom_wac->input;
|
||||
bool touch = wacom_wac->hid_data.tipswitch &&
|
||||
!wacom_wac->shared->stylus_in_proximity;
|
||||
unsigned touch_max = wacom_wac->features.touch_max;
|
||||
|
||||
if (touch_max > 1)
|
||||
wacom_wac_finger_mt_report(wacom_wac, input, touch);
|
||||
else
|
||||
wacom_wac_finger_single_touch_report(wacom_wac, input, touch);
|
||||
input_sync(input);
|
||||
|
||||
/* keep touch state for pen event */
|
||||
wacom_wac->shared->touch_down = touch;
|
||||
}
|
||||
|
||||
#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
|
||||
((f)->physical == HID_DG_STYLUS))
|
||||
#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \
|
||||
|
@ -1389,6 +1500,9 @@ void wacom_wac_usage_mapping(struct hid_device *hdev,
|
|||
|
||||
if (WACOM_PEN_FIELD(field))
|
||||
return wacom_wac_pen_usage_mapping(hdev, field, usage);
|
||||
|
||||
if (WACOM_FINGER_FIELD(field))
|
||||
return wacom_wac_finger_usage_mapping(hdev, field, usage);
|
||||
}
|
||||
|
||||
int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
|
||||
|
@ -1402,6 +1516,9 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
|
|||
if (WACOM_PEN_FIELD(field))
|
||||
return wacom_wac_pen_event(hdev, field, usage, value);
|
||||
|
||||
if (WACOM_FINGER_FIELD(field))
|
||||
return wacom_wac_finger_event(hdev, field, usage, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1416,6 +1533,9 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
|
|||
|
||||
if (WACOM_PEN_FIELD(field))
|
||||
return wacom_wac_pen_report(hdev, report);
|
||||
|
||||
if (WACOM_FINGER_FIELD(field))
|
||||
return wacom_wac_finger_report(hdev, report);
|
||||
}
|
||||
|
||||
static int wacom_bpt_touch(struct wacom_wac *wacom)
|
||||
|
|
|
@ -156,9 +156,17 @@ struct wacom_shared {
|
|||
};
|
||||
|
||||
struct hid_data {
|
||||
__s16 inputmode; /* InputMode HID feature, -1 if non-existent */
|
||||
__s16 inputmode_index; /* InputMode HID feature index in the report */
|
||||
bool inrange_state;
|
||||
bool invert_state;
|
||||
bool tipswitch;
|
||||
int x;
|
||||
int y;
|
||||
int pressure;
|
||||
int width;
|
||||
int height;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct wacom_wac {
|
||||
|
|
Loading…
Reference in a new issue