summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2010-10-12 10:40:31 +0200
committerHenrik Rydberg <rydberg@euromail.se>2010-10-12 10:40:31 +0200
commit09a1cadbf817f4db57c80687465ff98de84b3476 (patch)
treed63a27f525c201419c737d737fc1276752ab6e47 /usr/src
parent8871a76c8669087236435465abe88fc6c4e4b05c (diff)
New version based on patch series and testing on both devices
This version works both devices supported by the driver, and is based on a patch set scheduled for upstream. Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/dkms_source_tree/hid-egalax.c183
1 files changed, 91 insertions, 92 deletions
diff --git a/usr/src/dkms_source_tree/hid-egalax.c b/usr/src/dkms_source_tree/hid-egalax.c
index c060dfa..1afc3a5 100644
--- a/usr/src/dkms_source_tree/hid-egalax.c
+++ b/usr/src/dkms_source_tree/hid-egalax.c
@@ -2,6 +2,8 @@
2 * HID driver for eGalax dual-touch panels 2 * HID driver for eGalax dual-touch panels
3 * 3 *
4 * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> 4 * Copyright (c) 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
@@ -29,59 +31,59 @@ void usbhid_submit_report
29 31
30#define MAX_SLOTS 2 32#define MAX_SLOTS 2
31#define MAX_TRKID USHRT_MAX 33#define MAX_TRKID USHRT_MAX
32#define MAX_EVENTS 360 34#define MAX_EVENTS 120
33 35
34/* estimated signal-to-noise ratios */ 36/* estimated signal-to-noise ratios */
35#define SN_MOVE 1024 37#define SN_MOVE 1024
36#define SN_PRESSURE 32 38#define SN_PRESSURE 32
37 39
38struct egalax_contact { 40struct egalax_contact {
39 int id; 41 int touch;
40 int x, y, z; 42 int x, y, z;
41}; 43};
42 44
43struct egalax_data { 45struct egalax_data {
44 struct egalax_contact contact[MAX_SLOTS]; 46 struct egalax_contact contact[MAX_SLOTS];
45 int down, valid; 47 struct egalax_contact single, tmp;
46 int x, y, z; 48 int valid;
47 int slot; 49 int slot;
48 int mask;
49 int trkid; 50 int trkid;
50}; 51};
51 52
53static void set_abs(struct input_dev *input, unsigned int code,
54 struct hid_field *field, int snratio)
55{
56 int fmin = field->logical_minimum;
57 int fmax = field->logical_maximum;
58 int fuzz = snratio ? (fmax - fmin) / snratio : 0;
59 input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
60}
61
52static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, 62static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
53 struct hid_field *field, struct hid_usage *usage, 63 struct hid_field *field, struct hid_usage *usage,
54 unsigned long **bit, int *max) 64 unsigned long **bit, int *max)
55{ 65{
56 int f1 = field->logical_minimum; 66 struct input_dev *input = hi->input;
57 int f2 = field->logical_maximum;
58 int df = f2 - f1;
59 67
60 switch (usage->hid & HID_USAGE_PAGE) { 68 switch (usage->hid & HID_USAGE_PAGE) {
61 69
62 case HID_UP_GENDESK: 70 case HID_UP_GENDESK:
63 switch (usage->hid) { 71 switch (usage->hid) {
64 case HID_GD_X: 72 case HID_GD_X:
65 f1 = 0; 73 field->logical_maximum <<= 3;
66 f2 = 32768;
67 df = f2 - f1;
68 hid_map_usage(hi, usage, bit, max, 74 hid_map_usage(hi, usage, bit, max,
69 EV_ABS, ABS_MT_POSITION_X); 75 EV_ABS, ABS_MT_POSITION_X);
70 input_set_abs_params(hi->input, ABS_MT_POSITION_X, 76 set_abs(input, ABS_MT_POSITION_X, field, SN_MOVE);
71 f1, f2, df / SN_MOVE, 0); 77 /* touchscreen emulation */
72 input_set_abs_params(hi->input, ABS_X, 78 set_abs(input, ABS_X, field, SN_MOVE);
73 f1, f2, df / SN_MOVE, 0);
74 return 1; 79 return 1;
75 case HID_GD_Y: 80 case HID_GD_Y:
76 f1 = 0; 81 field->logical_maximum <<= 3;
77 f2 = 32768;
78 df = f2 - f1;
79 hid_map_usage(hi, usage, bit, max, 82 hid_map_usage(hi, usage, bit, max,
80 EV_ABS, ABS_MT_POSITION_Y); 83 EV_ABS, ABS_MT_POSITION_Y);
81 input_set_abs_params(hi->input, ABS_MT_POSITION_Y, 84 set_abs(input, ABS_MT_POSITION_Y, field, SN_MOVE);
82 f1, f2, df / SN_MOVE, 0); 85 /* touchscreen emulation */
83 input_set_abs_params(hi->input, ABS_Y, 86 set_abs(input, ABS_Y, field, SN_MOVE);
84 f1, f2, df / SN_MOVE, 0);
85 return 1; 87 return 1;
86 } 88 }
87 return 0; 89 return 0;
@@ -91,7 +93,7 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
91 case HID_DG_TIPSWITCH: 93 case HID_DG_TIPSWITCH:
92 /* touchscreen emulation */ 94 /* touchscreen emulation */
93 hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); 95 hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
94 input_set_capability(hi->input, EV_KEY, BTN_TOUCH); 96 input_set_capability(input, EV_KEY, BTN_TOUCH);
95 return 1; 97 return 1;
96 case HID_DG_INRANGE: 98 case HID_DG_INRANGE:
97 case HID_DG_CONFIDENCE: 99 case HID_DG_CONFIDENCE:
@@ -102,19 +104,17 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
102 field->logical_maximum = MAX_TRKID; 104 field->logical_maximum = MAX_TRKID;
103 hid_map_usage(hi, usage, bit, max, 105 hid_map_usage(hi, usage, bit, max,
104 EV_ABS, ABS_MT_TRACKING_ID); 106 EV_ABS, ABS_MT_TRACKING_ID);
105 input_set_abs_params(hi->input, ABS_MT_TRACKING_ID, 107 set_abs(input, ABS_MT_TRACKING_ID, field, 0);
106 0, MAX_TRKID, 0, 0); 108 input_set_events_per_packet(input, MAX_EVENTS);
107 if (!hi->input->mt) 109 if (!input->mt)
108 input_mt_create_slots(hi->input, MAX_SLOTS); 110 input_mt_create_slots(input, MAX_SLOTS);
109 input_set_events_per_packet(hi->input, MAX_EVENTS);
110 return 1; 111 return 1;
111 case HID_DG_TIPPRESSURE: 112 case HID_DG_TIPPRESSURE:
113 field->logical_minimum = 0;
112 hid_map_usage(hi, usage, bit, max, 114 hid_map_usage(hi, usage, bit, max,
113 EV_ABS, ABS_PRESSURE); 115 EV_ABS, ABS_MT_PRESSURE);
114 input_set_abs_params(hi->input, ABS_MT_PRESSURE, 116 set_abs(input, ABS_MT_PRESSURE, field, SN_PRESSURE);
115 f1, f2, df / SN_PRESSURE, 0); 117 set_abs(input, ABS_PRESSURE, field, SN_PRESSURE);
116 input_set_abs_params(hi->input, ABS_PRESSURE,
117 f1, f2, df / SN_PRESSURE, 0);
118 return 1; 118 return 1;
119 } 119 }
120 return 0; 120 return 0;
@@ -134,43 +134,59 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
134 return -1; 134 return -1;
135} 135}
136 136
137static void report_contact(struct egalax_data *td, struct input_dev *input) 137static void emulate_pointer(struct egalax_data *td, struct input_dev *input)
138{ 138{
139 struct egalax_contact *f = &td->contact[td->slot]; 139 struct egalax_contact *s = &td->single;
140 struct egalax_contact *oldest = 0; 140 struct egalax_contact *best = 0;
141 int i; 141 int dbest, i;
142
143 if (!td->down)
144 f->id = -1;
145 else if (f->id < 0)
146 f->id = td->trkid++ & MAX_TRKID;
147 f->x = td->x;
148 f->y = td->y;
149 f->z = td->z;
150 142
151 for (i = 0; i < MAX_SLOTS; i++) { 143 for (i = 0; i < MAX_SLOTS; i++) {
152 f = &td->contact[i]; 144 struct egalax_contact *f = &td->contact[i];
153 input_mt_slot(input, i); 145 if (f->touch) {
154 input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id); 146 int d = abs(f->x - s->x) + abs(f->y - s->y);
155 if (f->id < 0) 147 if (!best || d < dbest) {
156 continue; 148 best = f;
157 input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); 149 dbest = d;
158 input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); 150 }
159 input_event(input, EV_ABS, ABS_MT_PRESSURE, f->z); 151 }
160 if (!oldest)
161 oldest = f;
162 } 152 }
163 153
164 if (oldest) { 154 if (best) {
165 input_event(input, EV_KEY, BTN_TOUCH, 1); 155 input_event(input, EV_KEY, BTN_TOUCH, 1);
166 input_event(input, EV_ABS, ABS_X, oldest->x); 156 input_event(input, EV_ABS, ABS_X, best->x);
167 input_event(input, EV_ABS, ABS_Y, oldest->y); 157 input_event(input, EV_ABS, ABS_Y, best->y);
168 input_event(input, EV_ABS, ABS_PRESSURE, oldest->z); 158 input_event(input, EV_ABS, ABS_PRESSURE, best->z);
159 *s = *best;
169 } else { 160 } else {
170 input_event(input, EV_KEY, BTN_TOUCH, 0); 161 input_event(input, EV_KEY, BTN_TOUCH, 0);
171 } 162 }
163}
164
172 165
173 input_sync(input); 166/*
167 * this function is called when a whole finger has been parsed,
168 * so that it can decide what to send to the input layer.
169 */
170static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
171{
172 struct egalax_contact *old = &td->contact[td->slot];
173 struct egalax_contact *f = &td->tmp;
174
175 input_mt_slot(input, td->slot);
176 if (f->touch) {
177 if (!old->touch) {
178 int id = td->trkid++ & MAX_TRKID;
179 input_event(input, EV_ABS, ABS_MT_TRACKING_ID, id);
180 }
181 input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
182 input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
183 input_event(input, EV_ABS, ABS_MT_PRESSURE, f->z);
184 } else {
185 input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
186 }
187 *old = *f;
188
189 emulate_pointer(td, input);
174} 190}
175 191
176static int egalax_event(struct hid_device *hid, struct hid_field *field, 192static int egalax_event(struct hid_device *hid, struct hid_field *field,
@@ -182,55 +198,43 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
182 * uses a standard parallel multitouch protocol (product ID == 198 * uses a standard parallel multitouch protocol (product ID ==
183 * 48xx). The second is capacitive and uses an unusual "serial" 199 * 48xx). The second is capacitive and uses an unusual "serial"
184 * protocol with a different message for each multitouch finger 200 * protocol with a different message for each multitouch finger
185 * (product ID == 72xx). We do not yet generate a correct event 201 * (product ID == 72xx).
186 * sequence for the capacitive/serial protocol.
187 */ 202 */
188 if (hid->claimed & HID_CLAIMED_INPUT) { 203 if (hid->claimed & HID_CLAIMED_INPUT) {
189 struct input_dev *input = field->hidinput->input; 204 struct input_dev *input = field->hidinput->input;
190 205
191 //printk(KERN_INFO "CHECK: %08x %d", usage->hid, value);
192 //return 1;
193
194 switch (usage->hid) { 206 switch (usage->hid) {
207 case HID_DG_INRANGE:
208 td->valid = value;
209 break;
195 case HID_DG_CONFIDENCE: 210 case HID_DG_CONFIDENCE:
196 case HID_DG_CONTACTCOUNT: 211 /* avoid interference from generic hidinput handling */
197 break; 212 break;
198 213 case HID_DG_TIPSWITCH:
199 case HID_DG_TIPSWITCH: 214 td->tmp.touch = value;
200 td->down = value;
201 td->mask |= 0x01;
202 break; 215 break;
203 case HID_DG_INRANGE: 216 case HID_DG_TIPPRESSURE:
204 td->valid = value; 217 td->tmp.z = value;
205 td->mask |= 0x02;
206 break; 218 break;
207 case HID_DG_CONTACTID: 219 case HID_DG_CONTACTID:
208 td->slot = clamp_val(value, 0, MAX_SLOTS - 1); 220 td->slot = clamp_val(value, 0, MAX_SLOTS - 1);
209 td->mask |= 0x04;
210 break; 221 break;
211 case HID_GD_X: 222 case HID_GD_X:
212 td->x = value; 223 td->tmp.x = value;
213 td->mask |= 0x08;
214 break; 224 break;
215 case HID_GD_Y: 225 case HID_GD_Y:
216 td->y = value; 226 td->tmp.y = value;
217 td->mask |= 0x10; 227 /* this is the last field in a finger */
228 egalax_filter_event(td, input);
218 break; 229 break;
219 case HID_DG_TIPPRESSURE: 230 case HID_DG_CONTACTCOUNT:
220 td->z = value; 231 /* touch emulation: this is the last field in a frame */
221 td->mask |= 0x20;
222 break; 232 break;
223 233
224 default: 234 default:
225 /* fallback to the generic hidinput handling */ 235 /* fallback to the generic hidinput handling */
226 return 0; 236 return 0;
227 } 237 }
228
229 if (td->mask == 0x3f) {
230 td->mask = 0;
231 if (td->valid)
232 report_contact(td, input);
233 }
234 } 238 }
235 239
236 /* we have handled the hidinput part, now remains hiddev */ 240 /* we have handled the hidinput part, now remains hiddev */
@@ -245,17 +249,12 @@ static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id)
245 int ret; 249 int ret;
246 struct egalax_data *td; 250 struct egalax_data *td;
247 struct hid_report *report; 251 struct hid_report *report;
248 int i;
249
250 hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
251 252
252 td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL); 253 td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL);
253 if (!td) { 254 if (!td) {
254 dev_err(&hdev->dev, "cannot allocate eGalax data\n"); 255 dev_err(&hdev->dev, "cannot allocate eGalax data\n");
255 return -ENOMEM; 256 return -ENOMEM;
256 } 257 }
257 for (i = 0; i < MAX_SLOTS; i++)
258 td->contact[i].id = -1;
259 hid_set_drvdata(hdev, td); 258 hid_set_drvdata(hdev, td);
260 259
261 ret = hid_parse(hdev); 260 ret = hid_parse(hdev);