summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/hid-3m-pct.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
index d2fda7848f59..3c380e1c5b60 100644
--- a/drivers/hid/hid-3m-pct.c
+++ b/drivers/hid/hid-3m-pct.c
@@ -2,6 +2,8 @@
* HID driver for 3M PCT multitouch panels
*
* Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (c) 2010 Canonical, Ltd.
*
*/
@@ -25,16 +27,24 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
#define MAX_SLOTS 60
-#define MAX_TRKID 59
+#define MAX_TRKID USHRT_MAX
+#define MAX_EVENTS 360
+
+/* estimated signal-to-noise ratios */
+#define SN_MOVE 2048
+#define SN_WIDTH 128
struct mmm_finger {
__s32 x, y, w, h;
+ __u16 id;
__u8 rank;
+ bool prev_touch;
bool touch, valid;
};
struct mmm_data {
struct mmm_finger f[MAX_SLOTS];
+ __u16 id;
__u8 curid, num;
__u8 nexp, nreal;
bool touch, valid;
@@ -44,6 +54,10 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
+ int f1 = field->logical_minimum;
+ int f2 = field->logical_maximum;
+ int df = f2 - f1;
+
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_BUTTON:
@@ -54,18 +68,20 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_GD_X:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
+ input_set_abs_params(hi->input, ABS_MT_POSITION_X,
+ f1, f2, df / SN_MOVE, 0);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
+ f1, f2, df / SN_MOVE, 0);
return 1;
case HID_GD_Y:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
+ input_set_abs_params(hi->input, ABS_MT_POSITION_Y,
+ f1, f2, df / SN_MOVE, 0);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
+ f1, f2, df / SN_MOVE, 0);
return 1;
}
return 0;
@@ -85,14 +101,19 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_TIPSWITCH:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR);
+ input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR,
+ f1, f2, df / SN_WIDTH, 0);
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MINOR);
+ input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR,
+ f1, f2, df / SN_WIDTH, 0);
input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
0, 1, 0, 0);
return 1;
@@ -100,6 +121,11 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->logical_maximum = MAX_TRKID;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
+ input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
+ 0, MAX_TRKID, 0, 0);
+ if (!hi->input->mt)
+ input_mt_create_slots(hi->input, MAX_SLOTS);
+ input_set_events_per_packet(hi->input, MAX_EVENTS);
return 1;
}
/* let hid-input decide for the others */
@@ -117,10 +143,10 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
+ /* tell hid-input to skip setup of these event types */
if (usage->type == EV_KEY || usage->type == EV_ABS)
- clear_bit(usage->code, *bit);
-
- return 0;
+ set_bit(usage->type, hi->input->evbit);
+ return -1;
}
/*
@@ -141,10 +167,15 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
struct mmm_finger *f = &md->f[i];
if (!f->valid) {
/* this finger is just placeholder data, ignore */
- } else if (f->touch) {
+ continue;
+ }
+ input_mt_slot(input, i);
+ if (f->touch) {
/* this finger is on the screen */
int wide = (f->w > f->h);
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i);
+ if (!f->prev_touch)
+ f->id = md->id++;
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
@@ -152,7 +183,6 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
wide ? f->w : f->h);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR,
wide ? f->h : f->w);
- input_mt_sync(input);
/*
* touchscreen emulation: maintain the age rank
* of this finger, decide if we have a press
@@ -181,7 +211,9 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
--(md->num);
if (md->num == 0)
released = true;
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
}
+ f->prev_touch = f->touch;
f->valid = 0;
}