input: mt: Break out slots handling
[deliverable/linux.git] / drivers / hid / hid-3m-pct.c
1 /*
2 * HID driver for 3M PCT multitouch panels
3 *
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.
7 *
8 */
9
10 /*
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 2 of the License, or (at your option)
14 * any later version.
15 */
16
17 #include <linux/device.h>
18 #include <linux/hid.h>
19 #include <linux/module.h>
20 #include <linux/slab.h>
21 #include <linux/usb.h>
22 #include <linux/input/mt.h>
23
24 MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
25 MODULE_DESCRIPTION("3M PCT multitouch panels");
26 MODULE_LICENSE("GPL");
27
28 #include "hid-ids.h"
29
30 #define MAX_SLOTS 60
31 #define MAX_TRKID USHRT_MAX
32 #define MAX_EVENTS 360
33
34 /* estimated signal-to-noise ratios */
35 #define SN_MOVE 2048
36 #define SN_WIDTH 128
37
38 struct mmm_finger {
39 __s32 x, y, w, h;
40 __u16 id;
41 bool prev_touch;
42 bool touch, valid;
43 };
44
45 struct mmm_data {
46 struct mmm_finger f[MAX_SLOTS];
47 __u16 id;
48 __u8 curid;
49 __u8 nexp, nreal;
50 bool touch, valid;
51 };
52
53 static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
54 struct hid_field *field, struct hid_usage *usage,
55 unsigned long **bit, int *max)
56 {
57 int f1 = field->logical_minimum;
58 int f2 = field->logical_maximum;
59 int df = f2 - f1;
60
61 switch (usage->hid & HID_USAGE_PAGE) {
62
63 case HID_UP_BUTTON:
64 return -1;
65
66 case HID_UP_GENDESK:
67 switch (usage->hid) {
68 case HID_GD_X:
69 hid_map_usage(hi, usage, bit, max,
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);
73 /* touchscreen emulation */
74 input_set_abs_params(hi->input, ABS_X,
75 f1, f2, df / SN_MOVE, 0);
76 return 1;
77 case HID_GD_Y:
78 hid_map_usage(hi, usage, bit, max,
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);
82 /* touchscreen emulation */
83 input_set_abs_params(hi->input, ABS_Y,
84 f1, f2, df / SN_MOVE, 0);
85 return 1;
86 }
87 return 0;
88
89 case HID_UP_DIGITIZER:
90 switch (usage->hid) {
91 /* we do not want to map these: no input-oriented meaning */
92 case 0x14:
93 case 0x23:
94 case HID_DG_INPUTMODE:
95 case HID_DG_DEVICEINDEX:
96 case HID_DG_CONTACTCOUNT:
97 case HID_DG_CONTACTMAX:
98 case HID_DG_INRANGE:
99 case HID_DG_CONFIDENCE:
100 return -1;
101 case HID_DG_TIPSWITCH:
102 /* touchscreen emulation */
103 hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
104 input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
105 return 1;
106 case HID_DG_WIDTH:
107 hid_map_usage(hi, usage, bit, max,
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);
111 return 1;
112 case HID_DG_HEIGHT:
113 hid_map_usage(hi, usage, bit, max,
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);
117 input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
118 0, 1, 0, 0);
119 return 1;
120 case HID_DG_CONTACTID:
121 field->logical_maximum = MAX_TRKID;
122 hid_map_usage(hi, usage, bit, max,
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);
129 return 1;
130 }
131 /* let hid-input decide for the others */
132 return 0;
133
134 case 0xff000000:
135 /* we do not want to map these: no input-oriented meaning */
136 return -1;
137 }
138
139 return 0;
140 }
141
142 static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
143 struct hid_field *field, struct hid_usage *usage,
144 unsigned long **bit, int *max)
145 {
146 /* tell hid-input to skip setup of these event types */
147 if (usage->type == EV_KEY || usage->type == EV_ABS)
148 set_bit(usage->type, hi->input->evbit);
149 return -1;
150 }
151
152 /*
153 * this function is called when a whole packet has been received and processed,
154 * so that it can decide what to send to the input layer.
155 */
156 static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
157 {
158 struct mmm_finger *oldest = 0;
159 int i;
160 for (i = 0; i < MAX_SLOTS; ++i) {
161 struct mmm_finger *f = &md->f[i];
162 if (!f->valid) {
163 /* this finger is just placeholder data, ignore */
164 continue;
165 }
166 input_mt_slot(input, i);
167 if (f->touch) {
168 /* this finger is on the screen */
169 int wide = (f->w > f->h);
170 /* divided by two to match visual scale of touch */
171 int major = max(f->w, f->h) >> 1;
172 int minor = min(f->w, f->h) >> 1;
173
174 if (!f->prev_touch)
175 f->id = md->id++;
176 input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
177 input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
178 input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
179 input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
180 input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
181 input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
182 /* touchscreen emulation: pick the oldest contact */
183 if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
184 oldest = f;
185 } else {
186 /* this finger took off the screen */
187 input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
188 }
189 f->prev_touch = f->touch;
190 f->valid = 0;
191 }
192
193 /* touchscreen emulation */
194 if (oldest) {
195 input_event(input, EV_KEY, BTN_TOUCH, 1);
196 input_event(input, EV_ABS, ABS_X, oldest->x);
197 input_event(input, EV_ABS, ABS_Y, oldest->y);
198 } else {
199 input_event(input, EV_KEY, BTN_TOUCH, 0);
200 }
201 input_sync(input);
202 }
203
204 /*
205 * this function is called upon all reports
206 * so that we can accumulate contact point information,
207 * and call input_mt_sync after each point.
208 */
209 static int mmm_event(struct hid_device *hid, struct hid_field *field,
210 struct hid_usage *usage, __s32 value)
211 {
212 struct mmm_data *md = hid_get_drvdata(hid);
213 /*
214 * strangely, this function can be called before
215 * field->hidinput is initialized!
216 */
217 if (hid->claimed & HID_CLAIMED_INPUT) {
218 struct input_dev *input = field->hidinput->input;
219 switch (usage->hid) {
220 case HID_DG_TIPSWITCH:
221 md->touch = value;
222 break;
223 case HID_DG_CONFIDENCE:
224 md->valid = value;
225 break;
226 case HID_DG_WIDTH:
227 if (md->valid)
228 md->f[md->curid].w = value;
229 break;
230 case HID_DG_HEIGHT:
231 if (md->valid)
232 md->f[md->curid].h = value;
233 break;
234 case HID_DG_CONTACTID:
235 value = clamp_val(value, 0, MAX_SLOTS - 1);
236 if (md->valid) {
237 md->curid = value;
238 md->f[value].touch = md->touch;
239 md->f[value].valid = 1;
240 md->nreal++;
241 }
242 break;
243 case HID_GD_X:
244 if (md->valid)
245 md->f[md->curid].x = value;
246 break;
247 case HID_GD_Y:
248 if (md->valid)
249 md->f[md->curid].y = value;
250 break;
251 case HID_DG_CONTACTCOUNT:
252 if (value)
253 md->nexp = value;
254 if (md->nreal >= md->nexp) {
255 mmm_filter_event(md, input);
256 md->nreal = 0;
257 }
258 break;
259 }
260 }
261
262 /* we have handled the hidinput part, now remains hiddev */
263 if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
264 hid->hiddev_hid_event(hid, field, usage, value);
265
266 return 1;
267 }
268
269 static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
270 {
271 int ret;
272 struct mmm_data *md;
273
274 hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
275
276 md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
277 if (!md) {
278 dev_err(&hdev->dev, "cannot allocate 3M data\n");
279 return -ENOMEM;
280 }
281 hid_set_drvdata(hdev, md);
282
283 ret = hid_parse(hdev);
284 if (!ret)
285 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
286
287 if (ret)
288 kfree(md);
289 return ret;
290 }
291
292 static void mmm_remove(struct hid_device *hdev)
293 {
294 hid_hw_stop(hdev);
295 kfree(hid_get_drvdata(hdev));
296 hid_set_drvdata(hdev, NULL);
297 }
298
299 static const struct hid_device_id mmm_devices[] = {
300 { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
301 { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
302 { }
303 };
304 MODULE_DEVICE_TABLE(hid, mmm_devices);
305
306 static const struct hid_usage_id mmm_grabbed_usages[] = {
307 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
308 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
309 };
310
311 static struct hid_driver mmm_driver = {
312 .name = "3m-pct",
313 .id_table = mmm_devices,
314 .probe = mmm_probe,
315 .remove = mmm_remove,
316 .input_mapping = mmm_input_mapping,
317 .input_mapped = mmm_input_mapped,
318 .usage_table = mmm_grabbed_usages,
319 .event = mmm_event,
320 };
321
322 static int __init mmm_init(void)
323 {
324 return hid_register_driver(&mmm_driver);
325 }
326
327 static void __exit mmm_exit(void)
328 {
329 hid_unregister_driver(&mmm_driver);
330 }
331
332 module_init(mmm_init);
333 module_exit(mmm_exit);
334
This page took 0.0559 seconds and 5 git commands to generate.