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:
Benjamin Tissoires 2014-09-23 12:08:09 -04:00 committed by Jiri Kosina
parent 7704ac9373
commit 5ae6e89f74
3 changed files with 164 additions and 3 deletions

View file

@ -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);

View file

@ -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)

View file

@ -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 {