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 + * Copyright (c) 2010 Henrik Rydberg + * 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; }