diff options
-rw-r--r-- | drivers/hid/hid-3m-pct.c | 54 |
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 @@ | |||
2 | * HID driver for 3M PCT multitouch panels | 2 | * HID driver for 3M PCT multitouch panels |
3 | * | 3 | * |
4 | * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> | 4 | * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> |
5 | * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
6 | * Copyright (c) 2010 Canonical, Ltd. | ||
5 | * | 7 | * |
6 | */ | 8 | */ |
7 | 9 | ||
@@ -25,16 +27,24 @@ MODULE_LICENSE("GPL"); | |||
25 | #include "hid-ids.h" | 27 | #include "hid-ids.h" |
26 | 28 | ||
27 | #define MAX_SLOTS 60 | 29 | #define MAX_SLOTS 60 |
28 | #define MAX_TRKID 59 | 30 | #define MAX_TRKID USHRT_MAX |
31 | #define MAX_EVENTS 360 | ||
32 | |||
33 | /* estimated signal-to-noise ratios */ | ||
34 | #define SN_MOVE 2048 | ||
35 | #define SN_WIDTH 128 | ||
29 | 36 | ||
30 | struct mmm_finger { | 37 | struct mmm_finger { |
31 | __s32 x, y, w, h; | 38 | __s32 x, y, w, h; |
39 | __u16 id; | ||
32 | __u8 rank; | 40 | __u8 rank; |
41 | bool prev_touch; | ||
33 | bool touch, valid; | 42 | bool touch, valid; |
34 | }; | 43 | }; |
35 | 44 | ||
36 | struct mmm_data { | 45 | struct mmm_data { |
37 | struct mmm_finger f[MAX_SLOTS]; | 46 | struct mmm_finger f[MAX_SLOTS]; |
47 | __u16 id; | ||
38 | __u8 curid, num; | 48 | __u8 curid, num; |
39 | __u8 nexp, nreal; | 49 | __u8 nexp, nreal; |
40 | bool touch, valid; | 50 | bool touch, valid; |
@@ -44,6 +54,10 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
44 | struct hid_field *field, struct hid_usage *usage, | 54 | struct hid_field *field, struct hid_usage *usage, |
45 | unsigned long **bit, int *max) | 55 | unsigned long **bit, int *max) |
46 | { | 56 | { |
57 | int f1 = field->logical_minimum; | ||
58 | int f2 = field->logical_maximum; | ||
59 | int df = f2 - f1; | ||
60 | |||
47 | switch (usage->hid & HID_USAGE_PAGE) { | 61 | switch (usage->hid & HID_USAGE_PAGE) { |
48 | 62 | ||
49 | case HID_UP_BUTTON: | 63 | case HID_UP_BUTTON: |
@@ -54,18 +68,20 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
54 | case HID_GD_X: | 68 | case HID_GD_X: |
55 | hid_map_usage(hi, usage, bit, max, | 69 | hid_map_usage(hi, usage, bit, max, |
56 | EV_ABS, ABS_MT_POSITION_X); | 70 | EV_ABS, ABS_MT_POSITION_X); |
71 | input_set_abs_params(hi->input, ABS_MT_POSITION_X, | ||
72 | f1, f2, df / SN_MOVE, 0); | ||
57 | /* touchscreen emulation */ | 73 | /* touchscreen emulation */ |
58 | input_set_abs_params(hi->input, ABS_X, | 74 | input_set_abs_params(hi->input, ABS_X, |
59 | field->logical_minimum, | 75 | f1, f2, df / SN_MOVE, 0); |
60 | field->logical_maximum, 0, 0); | ||
61 | return 1; | 76 | return 1; |
62 | case HID_GD_Y: | 77 | case HID_GD_Y: |
63 | hid_map_usage(hi, usage, bit, max, | 78 | hid_map_usage(hi, usage, bit, max, |
64 | EV_ABS, ABS_MT_POSITION_Y); | 79 | EV_ABS, ABS_MT_POSITION_Y); |
80 | input_set_abs_params(hi->input, ABS_MT_POSITION_Y, | ||
81 | f1, f2, df / SN_MOVE, 0); | ||
65 | /* touchscreen emulation */ | 82 | /* touchscreen emulation */ |
66 | input_set_abs_params(hi->input, ABS_Y, | 83 | input_set_abs_params(hi->input, ABS_Y, |
67 | field->logical_minimum, | 84 | f1, f2, df / SN_MOVE, 0); |
68 | field->logical_maximum, 0, 0); | ||
69 | return 1; | 85 | return 1; |
70 | } | 86 | } |
71 | return 0; | 87 | return 0; |
@@ -85,14 +101,19 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
85 | case HID_DG_TIPSWITCH: | 101 | case HID_DG_TIPSWITCH: |
86 | /* touchscreen emulation */ | 102 | /* touchscreen emulation */ |
87 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | 103 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); |
104 | input_set_capability(hi->input, EV_KEY, BTN_TOUCH); | ||
88 | return 1; | 105 | return 1; |
89 | case HID_DG_WIDTH: | 106 | case HID_DG_WIDTH: |
90 | hid_map_usage(hi, usage, bit, max, | 107 | hid_map_usage(hi, usage, bit, max, |
91 | EV_ABS, ABS_MT_TOUCH_MAJOR); | 108 | EV_ABS, ABS_MT_TOUCH_MAJOR); |
109 | input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR, | ||
110 | f1, f2, df / SN_WIDTH, 0); | ||
92 | return 1; | 111 | return 1; |
93 | case HID_DG_HEIGHT: | 112 | case HID_DG_HEIGHT: |
94 | hid_map_usage(hi, usage, bit, max, | 113 | hid_map_usage(hi, usage, bit, max, |
95 | EV_ABS, ABS_MT_TOUCH_MINOR); | 114 | EV_ABS, ABS_MT_TOUCH_MINOR); |
115 | input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR, | ||
116 | f1, f2, df / SN_WIDTH, 0); | ||
96 | input_set_abs_params(hi->input, ABS_MT_ORIENTATION, | 117 | input_set_abs_params(hi->input, ABS_MT_ORIENTATION, |
97 | 0, 1, 0, 0); | 118 | 0, 1, 0, 0); |
98 | return 1; | 119 | return 1; |
@@ -100,6 +121,11 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
100 | field->logical_maximum = MAX_TRKID; | 121 | field->logical_maximum = MAX_TRKID; |
101 | hid_map_usage(hi, usage, bit, max, | 122 | hid_map_usage(hi, usage, bit, max, |
102 | EV_ABS, ABS_MT_TRACKING_ID); | 123 | EV_ABS, ABS_MT_TRACKING_ID); |
124 | input_set_abs_params(hi->input, ABS_MT_TRACKING_ID, | ||
125 | 0, MAX_TRKID, 0, 0); | ||
126 | if (!hi->input->mt) | ||
127 | input_mt_create_slots(hi->input, MAX_SLOTS); | ||
128 | input_set_events_per_packet(hi->input, MAX_EVENTS); | ||
103 | return 1; | 129 | return 1; |
104 | } | 130 | } |
105 | /* let hid-input decide for the others */ | 131 | /* let hid-input decide for the others */ |
@@ -117,10 +143,10 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
117 | struct hid_field *field, struct hid_usage *usage, | 143 | struct hid_field *field, struct hid_usage *usage, |
118 | unsigned long **bit, int *max) | 144 | unsigned long **bit, int *max) |
119 | { | 145 | { |
146 | /* tell hid-input to skip setup of these event types */ | ||
120 | if (usage->type == EV_KEY || usage->type == EV_ABS) | 147 | if (usage->type == EV_KEY || usage->type == EV_ABS) |
121 | clear_bit(usage->code, *bit); | 148 | set_bit(usage->type, hi->input->evbit); |
122 | 149 | return -1; | |
123 | return 0; | ||
124 | } | 150 | } |
125 | 151 | ||
126 | /* | 152 | /* |
@@ -141,10 +167,15 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) | |||
141 | struct mmm_finger *f = &md->f[i]; | 167 | struct mmm_finger *f = &md->f[i]; |
142 | if (!f->valid) { | 168 | if (!f->valid) { |
143 | /* this finger is just placeholder data, ignore */ | 169 | /* this finger is just placeholder data, ignore */ |
144 | } else if (f->touch) { | 170 | continue; |
171 | } | ||
172 | input_mt_slot(input, i); | ||
173 | if (f->touch) { | ||
145 | /* this finger is on the screen */ | 174 | /* this finger is on the screen */ |
146 | int wide = (f->w > f->h); | 175 | int wide = (f->w > f->h); |
147 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i); | 176 | if (!f->prev_touch) |
177 | f->id = md->id++; | ||
178 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id); | ||
148 | input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); | 179 | input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); |
149 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); | 180 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); |
150 | input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); | 181 | 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) | |||
152 | wide ? f->w : f->h); | 183 | wide ? f->w : f->h); |
153 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, | 184 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, |
154 | wide ? f->h : f->w); | 185 | wide ? f->h : f->w); |
155 | input_mt_sync(input); | ||
156 | /* | 186 | /* |
157 | * touchscreen emulation: maintain the age rank | 187 | * touchscreen emulation: maintain the age rank |
158 | * of this finger, decide if we have a press | 188 | * 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) | |||
181 | --(md->num); | 211 | --(md->num); |
182 | if (md->num == 0) | 212 | if (md->num == 0) |
183 | released = true; | 213 | released = true; |
214 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1); | ||
184 | } | 215 | } |
216 | f->prev_touch = f->touch; | ||
185 | f->valid = 0; | 217 | f->valid = 0; |
186 | } | 218 | } |
187 | 219 | ||