From 943ed464f3722de0569cf41ba6ec094768ac046d Mon Sep 17 00:00:00 2001 From: Rafi Rubin Date: Thu, 11 Feb 2010 22:14:05 -0500 Subject: HID: hid-ntrig add multi input quirk and clean up Added a quirk to enable distinct input devices. The digitizer utilizes three inputs to represent pen, multitouch and a normal touch screen. With the Pen partitioned, it behaves well and does not need special handling. Also, I set names to the input devices to clarify the functions of the various inputs. Signed-off-by: Rafi Rubin Signed-off-by: Jiri Kosina --- drivers/hid/hid-ntrig.c | 69 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 11 deletions(-) (limited to 'drivers/hid/hid-ntrig.c') diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 49ce69d7bba7..38b2364c8867 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -26,10 +26,10 @@ struct ntrig_data { __s32 x, y, id, w, h; - char reading_a_point, found_contact_id; - char pen_active; - char finger_active; - char inverted; + bool reading_a_point, found_contact_id; + bool pen_active; + bool finger_active; + bool inverted; }; /* @@ -42,6 +42,10 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { + /* No special mappings needed for the pen */ + if (field->application == HID_DG_PEN) + return 0; + switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_GENDESK: @@ -104,6 +108,9 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { + /* No special mappings needed for the pen */ + if (field->application == HID_DG_PEN) + return 0; if (usage->type == EV_KEY || usage->type == EV_REL || usage->type == EV_ABS) clear_bit(usage->code, *bit); @@ -123,6 +130,10 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, struct input_dev *input = field->hidinput->input; struct ntrig_data *nd = hid_get_drvdata(hid); + /* No special handling needed for the pen */ + if (field->application == HID_DG_PEN) + return 0; + if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { @@ -231,8 +242,8 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, } /* we have handled the hidinput part, now remains hiddev */ - if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) - hid->hiddev_hid_event(hid, field, usage, value); + if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); return 1; } @@ -241,6 +252,11 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; struct ntrig_data *nd; + struct hid_input *hidinput; + struct input_dev *input; + + if (id->driver_data) + hdev->quirks |= HID_QUIRK_MULTI_INPUT; nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL); if (!nd) { @@ -252,12 +268,43 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) hid_set_drvdata(hdev, nd); ret = hid_parse(hdev); - if (!ret) - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } - if (ret) - kfree (nd); + list_for_each_entry(hidinput, &hdev->inputs, list) { + input = hidinput->input; + switch (hidinput->report->field[0]->application) { + case HID_DG_PEN: + input->name = "N-Trig Pen"; + break; + case HID_DG_TOUCHSCREEN: + /* + * The physical touchscreen (single touch) + * input has a value for physical, whereas + * the multitouch only has logical input + * fields. + */ + input->name = + (hidinput->report->field[0] + ->physical) ? + "N-Trig Touchscreen" : + "N-Trig MultiTouch"; + break; + } + } + + return 0; +err_free: + kfree(nd); return ret; } @@ -276,7 +323,7 @@ MODULE_DEVICE_TABLE(hid, ntrig_devices); static const struct hid_usage_id ntrig_grabbed_usages[] = { { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, - { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 } }; static struct hid_driver ntrig_driver = { -- cgit v1.2.3 From b0549cf1a35a92edf053d94066e60fb0ed02bb71 Mon Sep 17 00:00:00 2001 From: Rafi Rubin Date: Thu, 11 Feb 2010 22:14:06 -0500 Subject: HID: n-trig: remove unnecessary tool switching With the pen and touch split apart, we no longer need to inject additional tool switching events. Signed-off-by: Rafi Rubin Signed-off-by: Jiri Kosina --- drivers/hid/hid-ntrig.c | 41 +---------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) (limited to 'drivers/hid/hid-ntrig.c') diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 38b2364c8867..1bda3a4bd71f 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -27,9 +27,6 @@ struct ntrig_data { __s32 x, y, id, w, h; bool reading_a_point, found_contact_id; - bool pen_active; - bool finger_active; - bool inverted; }; /* @@ -47,7 +44,6 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 0; switch (usage->hid & HID_USAGE_PAGE) { - case HID_UP_GENDESK: switch (usage->hid) { case HID_GD_X: @@ -111,6 +107,7 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi, /* No special mappings needed for the pen */ if (field->application == HID_DG_PEN) return 0; + if (usage->type == EV_KEY || usage->type == EV_REL || usage->type == EV_ABS) clear_bit(usage->code, *bit); @@ -136,18 +133,6 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { - - case HID_DG_INRANGE: - if (field->application & 0x3) - nd->pen_active = (value != 0); - else - nd->finger_active = (value != 0); - return 0; - - case HID_DG_INVERT: - nd->inverted = value; - return 0; - case HID_GD_X: nd->x = value; nd->reading_a_point = 1; @@ -171,32 +156,8 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, * to emit a normal (X, Y) position */ if (!nd->found_contact_id) { - if (nd->pen_active && nd->finger_active) { - input_report_key(input, BTN_TOOL_DOUBLETAP, 0); - input_report_key(input, BTN_TOOL_DOUBLETAP, 1); - } - input_event(input, EV_ABS, ABS_X, nd->x); - input_event(input, EV_ABS, ABS_Y, nd->y); - } - break; - case HID_DG_TIPPRESSURE: - /* - * when in single touch mode, this is the last - * report received in a pen event. We want - * to emit a normal (X, Y) position - */ - if (! nd->found_contact_id) { - if (nd->pen_active && nd->finger_active) { - input_report_key(input, - nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN - , 0); - input_report_key(input, - nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN - , 1); - } input_event(input, EV_ABS, ABS_X, nd->x); input_event(input, EV_ABS, ABS_Y, nd->y); - input_event(input, EV_ABS, ABS_PRESSURE, value); } break; case 0xff000002: -- cgit v1.2.3 From dbf2b17de505d390b5ecf5b5944fc0c88f6d66fe Mon Sep 17 00:00:00 2001 From: Rafi Rubin Date: Fri, 12 Feb 2010 21:13:05 -0500 Subject: HID: hid-ntrig: multitouch cleanup and fix This cleans up the identification of multitouch groups and enables the end of group sync. Taps are now explicitly handled to adjust for the changes in the event stream in multitouch mode. Added triple and quad tap for the benefit of tools that recognize different tap types but do not have full multi touch support. This cleans up the behavior particularly for the latest firmware, which didn't work particularly well with the older version of the driver. In this form, when multitouch is active, both mt and st events will come out of the "N-Trig MultiTouch" device. And when its not st events will come out of "N-Trig Touchscreen". Signed-off-by: Rafi Rubin Signed-off-by: Jiri Kosina --- drivers/hid/hid-ntrig.c | 116 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 22 deletions(-) (limited to 'drivers/hid/hid-ntrig.c') diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 1bda3a4bd71f..f6f882da6267 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -25,8 +25,16 @@ EV_KEY, (c)) struct ntrig_data { - __s32 x, y, id, w, h; - bool reading_a_point, found_contact_id; + /* Incoming raw values for a single contact */ + __u16 x, y, w, h; + __u16 id; + __u8 confidence; + + bool reading_mt; + __u8 first_contact_confidence; + + __u8 mt_footer[4]; + __u8 mt_foot_count; }; /* @@ -39,8 +47,8 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - /* No special mappings needed for the pen */ - if (field->application == HID_DG_PEN) + /* No special mappings needed for the pen and single touch */ + if (field->physical) return 0; switch (usage->hid & HID_USAGE_PAGE) { @@ -66,18 +74,12 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_UP_DIGITIZER: switch (usage->hid) { /* we do not want to map these for now */ - case HID_DG_CONTACTID: /* value is useless */ + case HID_DG_CONTACTID: /* Not trustworthy, squelch for now */ case HID_DG_INPUTMODE: case HID_DG_DEVICEINDEX: - case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTMAX: return -1; - /* original mapping by Rafi Rubin */ - case HID_DG_CONFIDENCE: - nt_map_key_clear(BTN_TOOL_DOUBLETAP); - return 1; - /* width/height mapped on TouchMajor/TouchMinor/Orientation */ case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, @@ -104,8 +106,8 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - /* No special mappings needed for the pen */ - if (field->application == HID_DG_PEN) + /* No special mappings needed for the pen and single touch */ + if (field->physical) return 0; if (usage->type == EV_KEY || usage->type == EV_REL @@ -133,17 +135,24 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { + case 0xff000001: + /* Tag indicating the start of a multitouch group */ + nd->reading_mt = 1; + nd->first_contact_confidence = 0; + break; + case HID_DG_CONFIDENCE: + nd->confidence = value; + break; case HID_GD_X: nd->x = value; - nd->reading_a_point = 1; + /* Clear the contact footer */ + nd->mt_foot_count = 0; break; case HID_GD_Y: nd->y = value; break; case HID_DG_CONTACTID: nd->id = value; - /* we receive this only when in multitouch mode */ - nd->found_contact_id = 1; break; case HID_DG_WIDTH: nd->w = value; @@ -155,7 +164,7 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, * report received in a finger event. We want * to emit a normal (X, Y) position */ - if (!nd->found_contact_id) { + if (!nd->reading_mt) { input_event(input, EV_ABS, ABS_X, nd->x); input_event(input, EV_ABS, ABS_Y, nd->y); } @@ -167,10 +176,34 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, * this usage tells if the contact point is real * or a placeholder */ - if (!nd->reading_a_point || value != 1) + + /* Shouldn't get more than 4 footer packets, so skip */ + if (nd->mt_foot_count >= 4) + break; + + nd->mt_footer[nd->mt_foot_count++] = value; + + /* if the footer isn't complete break */ + if (nd->mt_foot_count != 4) + break; + + /* Pen activity signal, trigger end of touch. */ + if (nd->mt_footer[2]) { + nd->confidence = 0; + break; + } + + /* If the contact was invalid */ + if (!(nd->confidence && nd->mt_footer[0]) + || nd->w <= 250 + || nd->h <= 190) { + nd->confidence = 0; break; + } + /* emit a normal (X, Y) for the first point only */ if (nd->id == 0) { + nd->first_contact_confidence = nd->confidence; input_event(input, EV_ABS, ABS_X, nd->x); input_event(input, EV_ABS, ABS_Y, nd->y); } @@ -192,8 +225,39 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, ABS_MT_TOUCH_MINOR, nd->w); } input_mt_sync(field->hidinput->input); - nd->reading_a_point = 0; - nd->found_contact_id = 0; + break; + + case HID_DG_CONTACTCOUNT: /* End of a multitouch group */ + if (!nd->reading_mt) + break; + + nd->reading_mt = 0; + + if (nd->first_contact_confidence) { + switch (value) { + case 0: /* for single touch devices */ + case 1: + input_report_key(input, + BTN_TOOL_DOUBLETAP, 1); + break; + case 2: + input_report_key(input, + BTN_TOOL_TRIPLETAP, 1); + break; + case 3: + default: + input_report_key(input, + BTN_TOOL_QUADTAP, 1); + } + input_report_key(input, BTN_TOUCH, 1); + } else { + input_report_key(input, + BTN_TOOL_DOUBLETAP, 0); + input_report_key(input, + BTN_TOOL_TRIPLETAP, 0); + input_report_key(input, + BTN_TOOL_QUADTAP, 0); + } break; default: @@ -224,8 +288,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) dev_err(&hdev->dev, "cannot allocate N-Trig data\n"); return -ENOMEM; } - nd->reading_a_point = 0; - nd->found_contact_id = 0; + + nd->reading_mt = 0; hid_set_drvdata(hdev, nd); ret = hid_parse(hdev); @@ -248,6 +312,14 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) input->name = "N-Trig Pen"; break; case HID_DG_TOUCHSCREEN: + __clear_bit(BTN_TOOL_PEN, input->keybit); + /* + * A little something special to enable + * two and three finger taps. + */ + __set_bit(BTN_TOOL_DOUBLETAP, input->keybit); + __set_bit(BTN_TOOL_TRIPLETAP, input->keybit); + __set_bit(BTN_TOOL_QUADTAP, input->keybit); /* * The physical touchscreen (single touch) * input has a value for physical, whereas -- cgit v1.2.3 From ff5cf34c809cd5950579e46e7c10c29bc647aaf1 Mon Sep 17 00:00:00 2001 From: Rafi Rubin Date: Tue, 16 Feb 2010 10:22:11 -0500 Subject: HID: hid-ntrig: Single touch mode tap Add DOUBLETAP to events emitted when in single touch only mode. Users with a single touch firmware report not seeing the DOUBLETAP events; this is a side effect of dropping old mapping for confidence. The confidence mapping may be fine for singletouch mode but causes problems in multitouch mode. Signed-off-by: Rafi Rubin Signed-off-by: Jiri Kosina --- drivers/hid/hid-ntrig.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/hid/hid-ntrig.c') diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index f6f882da6267..3234c729a895 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -165,6 +165,8 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, * to emit a normal (X, Y) position */ if (!nd->reading_mt) { + input_report_key(input, BTN_TOOL_DOUBLETAP, + (nd->confidence != 0)); input_event(input, EV_ABS, ABS_X, nd->x); input_event(input, EV_ABS, ABS_Y, nd->y); } -- cgit v1.2.3