diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-stantum-and-mosart-multitouch-drivers.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-stantum-and-mosart-multitouch-drivers.patch | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-stantum-and-mosart-multitouch-drivers.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-stantum-and-mosart-multitouch-drivers.patch new file mode 100644 index 0000000000..6f8aaca07e --- /dev/null +++ b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-stantum-and-mosart-multitouch-drivers.patch | |||
@@ -0,0 +1,714 @@ | |||
1 | From f7e13f4d9a7a9025244b37a3ad188af7dae841d9 Mon Sep 17 00:00:00 2001 | ||
2 | From: Stephane Chatty <chatty@enac.fr> | ||
3 | Date: Fri, 9 Apr 2010 15:33:54 -0700 | ||
4 | Subject: [PATCH 105/105] Stantum and Mosart multitouch drivers | ||
5 | |||
6 | HID Driver and configs for Stantum and Mosart multitouch panels. | ||
7 | |||
8 | Patch-mainline: 2.6.34 | ||
9 | |||
10 | Signed-off-by: Stephane Chatty <chatty@enac.fr> | ||
11 | Signed-off-by: Jiri Kosina <jkosina@suse.cz> | ||
12 | Signed-off-by: Priya Vijayan <priya.vijayan@intel.com> | ||
13 | --- | ||
14 | drivers/hid/Kconfig | 12 ++ | ||
15 | drivers/hid/Makefile | 3 +- | ||
16 | drivers/hid/hid-core.c | 7 +- | ||
17 | drivers/hid/hid-ids.h | 15 ++- | ||
18 | drivers/hid/hid-mosart.c | 274 +++++++++++++++++++++++++++++++++++++++++++ | ||
19 | drivers/hid/hid-stantum.c | 285 +++++++++++++++++++++++++++++++++++++++++++++ | ||
20 | 6 files changed, 590 insertions(+), 6 deletions(-) | ||
21 | create mode 100644 drivers/hid/hid-mosart.c | ||
22 | create mode 100644 drivers/hid/hid-stantum.c | ||
23 | |||
24 | diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig | ||
25 | index 37fb241..55906bc 100644 | ||
26 | --- a/drivers/hid/Kconfig | ||
27 | +++ b/drivers/hid/Kconfig | ||
28 | @@ -203,6 +203,12 @@ config HID_MONTEREY | ||
29 | ---help--- | ||
30 | Support for Monterey Genius KB29E. | ||
31 | |||
32 | +config HID_MOSART | ||
33 | + tristate "MosArt" | ||
34 | + depends on USB_HID | ||
35 | + ---help--- | ||
36 | + Support for MosArt dual-touch panels. | ||
37 | + | ||
38 | config HID_NTRIG | ||
39 | tristate "NTrig" if EMBEDDED | ||
40 | depends on USB_HID | ||
41 | @@ -247,6 +253,12 @@ config HID_SONY | ||
42 | ---help--- | ||
43 | Support for Sony PS3 controller. | ||
44 | |||
45 | +config HID_STANTUM | ||
46 | + tristate "Stantum" | ||
47 | + depends on USB_HID | ||
48 | + ---help--- | ||
49 | + Support for Stantum multitouch panel. | ||
50 | + | ||
51 | config HID_SUNPLUS | ||
52 | tristate "Sunplus" if EMBEDDED | ||
53 | depends on USB_HID | ||
54 | diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile | ||
55 | index b05f921..bbda0b0 100644 | ||
56 | --- a/drivers/hid/Makefile | ||
57 | +++ b/drivers/hid/Makefile | ||
58 | @@ -34,12 +34,14 @@ obj-$(CONFIG_HID_KYE) += hid-kye.o | ||
59 | obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o | ||
60 | obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o | ||
61 | obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o | ||
62 | +obj-$(CONFIG_HID_MOSART) += hid-mosart.o | ||
63 | obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o | ||
64 | obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o | ||
65 | obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o | ||
66 | obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o | ||
67 | obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o | ||
68 | obj-$(CONFIG_HID_SONY) += hid-sony.o | ||
69 | +obj-$(CONFIG_HID_STANTUM) += hid-stantum.o | ||
70 | obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o | ||
71 | obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o | ||
72 | obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o | ||
73 | @@ -51,4 +53,3 @@ obj-$(CONFIG_HID_WACOM) += hid-wacom.o | ||
74 | obj-$(CONFIG_USB_HID) += usbhid/ | ||
75 | obj-$(CONFIG_USB_MOUSE) += usbhid/ | ||
76 | obj-$(CONFIG_USB_KBD) += usbhid/ | ||
77 | - | ||
78 | diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c | ||
79 | index b126102..fbf6f3e 100644 | ||
80 | --- a/drivers/hid/hid-core.c | ||
81 | +++ b/drivers/hid/hid-core.c | ||
82 | @@ -1342,6 +1342,9 @@ static const struct hid_device_id hid_blacklist[] = { | ||
83 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, | ||
84 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, | ||
85 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, | ||
86 | + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, | ||
87 | + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM2, USB_DEVICE_ID_MTP2) }, | ||
88 | + { HID_USB_DEVICE(USB_VENDOR_ID_STMICRO, USB_DEVICE_ID_STMICRO_MTP1) }, | ||
89 | { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, | ||
90 | { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, | ||
91 | { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, | ||
92 | @@ -1544,8 +1546,9 @@ static const struct hid_device_id hid_ignore_list[] = { | ||
93 | { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) }, | ||
94 | { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) }, | ||
95 | { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) }, | ||
96 | - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)}, | ||
97 | - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)}, | ||
98 | + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)}, | ||
99 | + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, | ||
100 | + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, | ||
101 | { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, | ||
102 | { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) }, | ||
103 | { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) }, | ||
104 | diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h | ||
105 | index 6865ca2..92c8a78 100644 | ||
106 | --- a/drivers/hid/hid-ids.h | ||
107 | +++ b/drivers/hid/hid-ids.h | ||
108 | @@ -96,9 +96,12 @@ | ||
109 | #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 | ||
110 | #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 | ||
111 | |||
112 | -#define USB_VENDOR_ID_ASUS 0x0b05 | ||
113 | -#define USB_DEVICE_ID_ASUS_LCM 0x1726 | ||
114 | -#define USB_DEVICE_ID_ASUS_LCM2 0x175b | ||
115 | +#define USB_VENDOR_ID_ASUS 0x0486 | ||
116 | +#define USB_DEVICE_ID_ASUS_T91MT 0x0185 | ||
117 | + | ||
118 | +#define USB_VENDOR_ID_ASUSTEK 0x0b05 | ||
119 | +#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 | ||
120 | +#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b | ||
121 | |||
122 | #define USB_VENDOR_ID_ATEN 0x0557 | ||
123 | #define USB_DEVICE_ID_ATEN_UC100KM 0x2004 | ||
124 | @@ -399,6 +402,15 @@ | ||
125 | #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 | ||
126 | #define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046 | ||
127 | |||
128 | +#define USB_VENDOR_ID_STANTUM 0x1f87 | ||
129 | +#define USB_DEVICE_ID_MTP 0x0002 | ||
130 | + | ||
131 | +#define USB_VENDOR_ID_STANTUM2 0x1f87 | ||
132 | +#define USB_DEVICE_ID_MTP2 0x0001 | ||
133 | + | ||
134 | +#define USB_VENDOR_ID_STMICRO 0x0483 | ||
135 | +#define USB_DEVICE_ID_STMICRO_MTP1 0x3261 | ||
136 | + | ||
137 | #define USB_VENDOR_ID_SUN 0x0430 | ||
138 | #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab | ||
139 | |||
140 | diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c | ||
141 | new file mode 100644 | ||
142 | index 0000000..e91437c | ||
143 | --- /dev/null | ||
144 | +++ b/drivers/hid/hid-mosart.c | ||
145 | @@ -0,0 +1,274 @@ | ||
146 | +/* | ||
147 | + * HID driver for the multitouch panel on the ASUS EeePC T91MT | ||
148 | + * | ||
149 | + * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> | ||
150 | + * Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.com> | ||
151 | + * | ||
152 | + */ | ||
153 | + | ||
154 | +/* | ||
155 | + * This program is free software; you can redistribute it and/or modify it | ||
156 | + * under the terms of the GNU General Public License as published by the Free | ||
157 | + * Software Foundation; either version 2 of the License, or (at your option) | ||
158 | + * any later version. | ||
159 | + */ | ||
160 | + | ||
161 | +#include <linux/device.h> | ||
162 | +#include <linux/hid.h> | ||
163 | +#include <linux/module.h> | ||
164 | +#include <linux/slab.h> | ||
165 | +#include <linux/usb.h> | ||
166 | +#include "usbhid/usbhid.h" | ||
167 | + | ||
168 | +MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); | ||
169 | +MODULE_DESCRIPTION("MosArt dual-touch panel"); | ||
170 | +MODULE_LICENSE("GPL"); | ||
171 | + | ||
172 | +#include "hid-ids.h" | ||
173 | + | ||
174 | +struct mosart_data { | ||
175 | + __u16 x, y; | ||
176 | + __u8 id; | ||
177 | + bool valid; /* valid finger data, or just placeholder? */ | ||
178 | + bool first; /* is this the first finger in this frame? */ | ||
179 | + bool activity_now; /* at least one active finger in this frame? */ | ||
180 | + bool activity; /* at least one active finger previously? */ | ||
181 | +}; | ||
182 | + | ||
183 | +static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
184 | + struct hid_field *field, struct hid_usage *usage, | ||
185 | + unsigned long **bit, int *max) | ||
186 | +{ | ||
187 | + switch (usage->hid & HID_USAGE_PAGE) { | ||
188 | + | ||
189 | + case HID_UP_GENDESK: | ||
190 | + switch (usage->hid) { | ||
191 | + case HID_GD_X: | ||
192 | + hid_map_usage(hi, usage, bit, max, | ||
193 | + EV_ABS, ABS_MT_POSITION_X); | ||
194 | + /* touchscreen emulation */ | ||
195 | + input_set_abs_params(hi->input, ABS_X, | ||
196 | + field->logical_minimum, | ||
197 | + field->logical_maximum, 0, 0); | ||
198 | + return 1; | ||
199 | + case HID_GD_Y: | ||
200 | + hid_map_usage(hi, usage, bit, max, | ||
201 | + EV_ABS, ABS_MT_POSITION_Y); | ||
202 | + /* touchscreen emulation */ | ||
203 | + input_set_abs_params(hi->input, ABS_Y, | ||
204 | + field->logical_minimum, | ||
205 | + field->logical_maximum, 0, 0); | ||
206 | + return 1; | ||
207 | + } | ||
208 | + return 0; | ||
209 | + | ||
210 | + case HID_UP_DIGITIZER: | ||
211 | + switch (usage->hid) { | ||
212 | + case HID_DG_CONFIDENCE: | ||
213 | + case HID_DG_TIPSWITCH: | ||
214 | + case HID_DG_INPUTMODE: | ||
215 | + case HID_DG_DEVICEINDEX: | ||
216 | + case HID_DG_CONTACTCOUNT: | ||
217 | + case HID_DG_CONTACTMAX: | ||
218 | + case HID_DG_TIPPRESSURE: | ||
219 | + case HID_DG_WIDTH: | ||
220 | + case HID_DG_HEIGHT: | ||
221 | + return -1; | ||
222 | + case HID_DG_INRANGE: | ||
223 | + /* touchscreen emulation */ | ||
224 | + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | ||
225 | + return 1; | ||
226 | + | ||
227 | + case HID_DG_CONTACTID: | ||
228 | + hid_map_usage(hi, usage, bit, max, | ||
229 | + EV_ABS, ABS_MT_TRACKING_ID); | ||
230 | + return 1; | ||
231 | + | ||
232 | + } | ||
233 | + return 0; | ||
234 | + | ||
235 | + case 0xff000000: | ||
236 | + /* ignore HID features */ | ||
237 | + return -1; | ||
238 | + } | ||
239 | + | ||
240 | + return 0; | ||
241 | +} | ||
242 | + | ||
243 | +static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi, | ||
244 | + struct hid_field *field, struct hid_usage *usage, | ||
245 | + unsigned long **bit, int *max) | ||
246 | +{ | ||
247 | + if (usage->type == EV_KEY || usage->type == EV_ABS) | ||
248 | + clear_bit(usage->code, *bit); | ||
249 | + | ||
250 | + return 0; | ||
251 | +} | ||
252 | + | ||
253 | +/* | ||
254 | + * this function is called when a whole finger has been parsed, | ||
255 | + * so that it can decide what to send to the input layer. | ||
256 | + */ | ||
257 | +static void mosart_filter_event(struct mosart_data *td, struct input_dev *input) | ||
258 | +{ | ||
259 | + td->first = !td->first; /* touchscreen emulation */ | ||
260 | + | ||
261 | + if (!td->valid) { | ||
262 | + /* | ||
263 | + * touchscreen emulation: if no finger in this frame is valid | ||
264 | + * and there previously was finger activity, this is a release | ||
265 | + */ | ||
266 | + if (!td->first && !td->activity_now && td->activity) { | ||
267 | + input_event(input, EV_KEY, BTN_TOUCH, 0); | ||
268 | + td->activity = false; | ||
269 | + } | ||
270 | + return; | ||
271 | + } | ||
272 | + | ||
273 | + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); | ||
274 | + input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); | ||
275 | + input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); | ||
276 | + | ||
277 | + input_mt_sync(input); | ||
278 | + td->valid = false; | ||
279 | + | ||
280 | + /* touchscreen emulation: if first active finger in this frame... */ | ||
281 | + if (!td->activity_now) { | ||
282 | + /* if there was no previous activity, emit touch event */ | ||
283 | + if (!td->activity) { | ||
284 | + input_event(input, EV_KEY, BTN_TOUCH, 1); | ||
285 | + td->activity = true; | ||
286 | + } | ||
287 | + td->activity_now = true; | ||
288 | + /* and in any case this is our preferred finger */ | ||
289 | + input_event(input, EV_ABS, ABS_X, td->x); | ||
290 | + input_event(input, EV_ABS, ABS_Y, td->y); | ||
291 | + } | ||
292 | +} | ||
293 | + | ||
294 | + | ||
295 | +static int mosart_event(struct hid_device *hid, struct hid_field *field, | ||
296 | + struct hid_usage *usage, __s32 value) | ||
297 | +{ | ||
298 | + struct mosart_data *td = hid_get_drvdata(hid); | ||
299 | + | ||
300 | + if (hid->claimed & HID_CLAIMED_INPUT) { | ||
301 | + struct input_dev *input = field->hidinput->input; | ||
302 | + switch (usage->hid) { | ||
303 | + case HID_DG_INRANGE: | ||
304 | + td->valid = !!value; | ||
305 | + break; | ||
306 | + case HID_GD_X: | ||
307 | + td->x = value; | ||
308 | + break; | ||
309 | + case HID_GD_Y: | ||
310 | + td->y = value; | ||
311 | + mosart_filter_event(td, input); | ||
312 | + break; | ||
313 | + case HID_DG_CONTACTID: | ||
314 | + td->id = value; | ||
315 | + break; | ||
316 | + case HID_DG_CONTACTCOUNT: | ||
317 | + /* touch emulation: this is the last field in a frame */ | ||
318 | + td->first = false; | ||
319 | + td->activity_now = false; | ||
320 | + break; | ||
321 | + case HID_DG_CONFIDENCE: | ||
322 | + case HID_DG_TIPSWITCH: | ||
323 | + /* avoid interference from generic hidinput handling */ | ||
324 | + break; | ||
325 | + | ||
326 | + default: | ||
327 | + /* fallback to the generic hidinput handling */ | ||
328 | + return 0; | ||
329 | + } | ||
330 | + } | ||
331 | + | ||
332 | + /* we have handled the hidinput part, now remains hiddev */ | ||
333 | + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) | ||
334 | + hid->hiddev_hid_event(hid, field, usage, value); | ||
335 | + | ||
336 | + return 1; | ||
337 | +} | ||
338 | + | ||
339 | +static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id) | ||
340 | +{ | ||
341 | + int ret; | ||
342 | + struct mosart_data *td; | ||
343 | + | ||
344 | + | ||
345 | + td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL); | ||
346 | + if (!td) { | ||
347 | + dev_err(&hdev->dev, "cannot allocate MosArt data\n"); | ||
348 | + return -ENOMEM; | ||
349 | + } | ||
350 | + td->valid = false; | ||
351 | + td->activity = false; | ||
352 | + td->activity_now = false; | ||
353 | + td->first = false; | ||
354 | + hid_set_drvdata(hdev, td); | ||
355 | + | ||
356 | + /* currently, it's better to have one evdev device only */ | ||
357 | +#if 0 | ||
358 | + hdev->quirks |= HID_QUIRK_MULTI_INPUT; | ||
359 | +#endif | ||
360 | + | ||
361 | + ret = hid_parse(hdev); | ||
362 | + if (ret == 0) | ||
363 | + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
364 | + | ||
365 | + if (ret == 0) { | ||
366 | + struct hid_report_enum *re = hdev->report_enum | ||
367 | + + HID_FEATURE_REPORT; | ||
368 | + struct hid_report *r = re->report_id_hash[7]; | ||
369 | + | ||
370 | + r->field[0]->value[0] = 0x02; | ||
371 | + usbhid_submit_report(hdev, r, USB_DIR_OUT); | ||
372 | + } else | ||
373 | + kfree(td); | ||
374 | + | ||
375 | + return ret; | ||
376 | +} | ||
377 | + | ||
378 | +static void mosart_remove(struct hid_device *hdev) | ||
379 | +{ | ||
380 | + hid_hw_stop(hdev); | ||
381 | + kfree(hid_get_drvdata(hdev)); | ||
382 | + hid_set_drvdata(hdev, NULL); | ||
383 | +} | ||
384 | + | ||
385 | +static const struct hid_device_id mosart_devices[] = { | ||
386 | + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, | ||
387 | + { } | ||
388 | +}; | ||
389 | +MODULE_DEVICE_TABLE(hid, mosart_devices); | ||
390 | + | ||
391 | +static const struct hid_usage_id mosart_grabbed_usages[] = { | ||
392 | + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, | ||
393 | + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} | ||
394 | +}; | ||
395 | + | ||
396 | +static struct hid_driver mosart_driver = { | ||
397 | + .name = "mosart", | ||
398 | + .id_table = mosart_devices, | ||
399 | + .probe = mosart_probe, | ||
400 | + .remove = mosart_remove, | ||
401 | + .input_mapping = mosart_input_mapping, | ||
402 | + .input_mapped = mosart_input_mapped, | ||
403 | + .usage_table = mosart_grabbed_usages, | ||
404 | + .event = mosart_event, | ||
405 | +}; | ||
406 | + | ||
407 | +static int __init mosart_init(void) | ||
408 | +{ | ||
409 | + return hid_register_driver(&mosart_driver); | ||
410 | +} | ||
411 | + | ||
412 | +static void __exit mosart_exit(void) | ||
413 | +{ | ||
414 | + hid_unregister_driver(&mosart_driver); | ||
415 | +} | ||
416 | + | ||
417 | +module_init(mosart_init); | ||
418 | +module_exit(mosart_exit); | ||
419 | + | ||
420 | diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c | ||
421 | new file mode 100644 | ||
422 | index 0000000..bb4430f | ||
423 | --- /dev/null | ||
424 | +++ b/drivers/hid/hid-stantum.c | ||
425 | @@ -0,0 +1,286 @@ | ||
426 | +/* | ||
427 | + * HID driver for Stantum multitouch panels | ||
428 | + * | ||
429 | + * Copyright (c) 2009 Stephane Chatty <chatty@enac.fr> | ||
430 | + * | ||
431 | + */ | ||
432 | + | ||
433 | +/* | ||
434 | + * This program is free software; you can redistribute it and/or modify it | ||
435 | + * under the terms of the GNU General Public License as published by the Free | ||
436 | + * Software Foundation; either version 2 of the License, or (at your option) | ||
437 | + * any later version. | ||
438 | + */ | ||
439 | + | ||
440 | +#include <linux/device.h> | ||
441 | +#include <linux/hid.h> | ||
442 | +#include <linux/module.h> | ||
443 | +#include <linux/slab.h> | ||
444 | + | ||
445 | +MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); | ||
446 | +MODULE_DESCRIPTION("Stantum HID multitouch panels"); | ||
447 | +MODULE_LICENSE("GPL"); | ||
448 | + | ||
449 | +#include "hid-ids.h" | ||
450 | + | ||
451 | +struct stantum_data { | ||
452 | + __s32 x, y, z, w, h; /* x, y, pressure, width, height */ | ||
453 | + __u16 id; /* touch id */ | ||
454 | + bool valid; /* valid finger data, or just placeholder? */ | ||
455 | + bool first; /* first finger in the HID packet? */ | ||
456 | + bool activity; /* at least one active finger so far? */ | ||
457 | +}; | ||
458 | + | ||
459 | +static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
460 | + struct hid_field *field, struct hid_usage *usage, | ||
461 | + unsigned long **bit, int *max) | ||
462 | +{ | ||
463 | + switch (usage->hid & HID_USAGE_PAGE) { | ||
464 | + | ||
465 | + case HID_UP_GENDESK: | ||
466 | + switch (usage->hid) { | ||
467 | + case HID_GD_X: | ||
468 | + hid_map_usage(hi, usage, bit, max, | ||
469 | + EV_ABS, ABS_MT_POSITION_X); | ||
470 | + /* touchscreen emulation */ | ||
471 | + input_set_abs_params(hi->input, ABS_X, | ||
472 | + field->logical_minimum, | ||
473 | + field->logical_maximum, 0, 0); | ||
474 | + return 1; | ||
475 | + case HID_GD_Y: | ||
476 | + hid_map_usage(hi, usage, bit, max, | ||
477 | + EV_ABS, ABS_MT_POSITION_Y); | ||
478 | + /* touchscreen emulation */ | ||
479 | + input_set_abs_params(hi->input, ABS_Y, | ||
480 | + field->logical_minimum, | ||
481 | + field->logical_maximum, 0, 0); | ||
482 | + return 1; | ||
483 | + } | ||
484 | + return 0; | ||
485 | + | ||
486 | + case HID_UP_DIGITIZER: | ||
487 | + switch (usage->hid) { | ||
488 | + case HID_DG_INRANGE: | ||
489 | + case HID_DG_CONFIDENCE: | ||
490 | + case HID_DG_INPUTMODE: | ||
491 | + case HID_DG_DEVICEINDEX: | ||
492 | + case HID_DG_CONTACTCOUNT: | ||
493 | + case HID_DG_CONTACTMAX: | ||
494 | + return -1; | ||
495 | + | ||
496 | + case HID_DG_TIPSWITCH: | ||
497 | + /* touchscreen emulation */ | ||
498 | + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | ||
499 | + return 1; | ||
500 | + | ||
501 | + case HID_DG_WIDTH: | ||
502 | + hid_map_usage(hi, usage, bit, max, | ||
503 | + EV_ABS, ABS_MT_TOUCH_MAJOR); | ||
504 | + return 1; | ||
505 | + case HID_DG_HEIGHT: | ||
506 | + hid_map_usage(hi, usage, bit, max, | ||
507 | + EV_ABS, ABS_MT_TOUCH_MINOR); | ||
508 | + input_set_abs_params(hi->input, ABS_MT_ORIENTATION, | ||
509 | + 1, 1, 0, 0); | ||
510 | + return 1; | ||
511 | + case HID_DG_TIPPRESSURE: | ||
512 | + hid_map_usage(hi, usage, bit, max, | ||
513 | + EV_ABS, ABS_MT_PRESSURE); | ||
514 | + return 1; | ||
515 | + | ||
516 | + case HID_DG_CONTACTID: | ||
517 | + hid_map_usage(hi, usage, bit, max, | ||
518 | + EV_ABS, ABS_MT_TRACKING_ID); | ||
519 | + return 1; | ||
520 | + | ||
521 | + } | ||
522 | + return 0; | ||
523 | + | ||
524 | + case 0xff000000: | ||
525 | + /* no input-oriented meaning */ | ||
526 | + return -1; | ||
527 | + } | ||
528 | + | ||
529 | + return 0; | ||
530 | +} | ||
531 | + | ||
532 | +static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi, | ||
533 | + struct hid_field *field, struct hid_usage *usage, | ||
534 | + unsigned long **bit, int *max) | ||
535 | +{ | ||
536 | + if (usage->type == EV_KEY || usage->type == EV_ABS) | ||
537 | + clear_bit(usage->code, *bit); | ||
538 | + | ||
539 | + return 0; | ||
540 | +} | ||
541 | + | ||
542 | +/* | ||
543 | + * this function is called when a whole finger has been parsed, | ||
544 | + * so that it can decide what to send to the input layer. | ||
545 | + */ | ||
546 | +static void stantum_filter_event(struct stantum_data *sd, | ||
547 | + struct input_dev *input) | ||
548 | +{ | ||
549 | + bool wide; | ||
550 | + | ||
551 | + if (!sd->valid) { | ||
552 | + /* | ||
553 | + * touchscreen emulation: if the first finger is not valid and | ||
554 | + * there previously was finger activity, this is a release | ||
555 | + */ | ||
556 | + if (sd->first && sd->activity) { | ||
557 | + input_event(input, EV_KEY, BTN_TOUCH, 0); | ||
558 | + sd->activity = false; | ||
559 | + } | ||
560 | + return; | ||
561 | + } | ||
562 | + | ||
563 | + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id); | ||
564 | + input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x); | ||
565 | + input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y); | ||
566 | + | ||
567 | + wide = (sd->w > sd->h); | ||
568 | + input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); | ||
569 | + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h); | ||
570 | + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w); | ||
571 | + | ||
572 | + input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z); | ||
573 | + | ||
574 | + input_mt_sync(input); | ||
575 | + sd->valid = false; | ||
576 | + | ||
577 | + /* touchscreen emulation */ | ||
578 | + if (sd->first) { | ||
579 | + if (!sd->activity) { | ||
580 | + input_event(input, EV_KEY, BTN_TOUCH, 1); | ||
581 | + sd->activity = true; | ||
582 | + } | ||
583 | + input_event(input, EV_ABS, ABS_X, sd->x); | ||
584 | + input_event(input, EV_ABS, ABS_Y, sd->y); | ||
585 | + } | ||
586 | + sd->first = false; | ||
587 | +} | ||
588 | + | ||
589 | + | ||
590 | +static int stantum_event(struct hid_device *hid, struct hid_field *field, | ||
591 | + struct hid_usage *usage, __s32 value) | ||
592 | +{ | ||
593 | + struct stantum_data *sd = hid_get_drvdata(hid); | ||
594 | + | ||
595 | + if (hid->claimed & HID_CLAIMED_INPUT) { | ||
596 | + struct input_dev *input = field->hidinput->input; | ||
597 | + | ||
598 | + switch (usage->hid) { | ||
599 | + case HID_DG_INRANGE: | ||
600 | + /* this is the last field in a finger */ | ||
601 | + stantum_filter_event(sd, input); | ||
602 | + break; | ||
603 | + case HID_DG_WIDTH: | ||
604 | + sd->w = value; | ||
605 | + break; | ||
606 | + case HID_DG_HEIGHT: | ||
607 | + sd->h = value; | ||
608 | + break; | ||
609 | + case HID_GD_X: | ||
610 | + sd->x = value; | ||
611 | + break; | ||
612 | + case HID_GD_Y: | ||
613 | + sd->y = value; | ||
614 | + break; | ||
615 | + case HID_DG_TIPPRESSURE: | ||
616 | + sd->z = value; | ||
617 | + break; | ||
618 | + case HID_DG_CONTACTID: | ||
619 | + sd->id = value; | ||
620 | + break; | ||
621 | + case HID_DG_CONFIDENCE: | ||
622 | + sd->valid = !!value; | ||
623 | + break; | ||
624 | + case 0xff000002: | ||
625 | + /* this comes only before the first finger */ | ||
626 | + sd->first = true; | ||
627 | + break; | ||
628 | + | ||
629 | + default: | ||
630 | + /* ignore the others */ | ||
631 | + return 1; | ||
632 | + } | ||
633 | + } | ||
634 | + | ||
635 | + /* we have handled the hidinput part, now remains hiddev */ | ||
636 | + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) | ||
637 | + hid->hiddev_hid_event(hid, field, usage, value); | ||
638 | + | ||
639 | + return 1; | ||
640 | +} | ||
641 | + | ||
642 | +static int stantum_probe(struct hid_device *hdev, | ||
643 | + const struct hid_device_id *id) | ||
644 | +{ | ||
645 | + int ret; | ||
646 | + struct stantum_data *sd; | ||
647 | + | ||
648 | + sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL); | ||
649 | + if (!sd) { | ||
650 | + dev_err(&hdev->dev, "cannot allocate Stantum data\n"); | ||
651 | + return -ENOMEM; | ||
652 | + } | ||
653 | + sd->valid = false; | ||
654 | + sd->first = false; | ||
655 | + sd->activity = false; | ||
656 | + hid_set_drvdata(hdev, sd); | ||
657 | + | ||
658 | + ret = hid_parse(hdev); | ||
659 | + if (!ret) | ||
660 | + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
661 | + | ||
662 | + if (ret) | ||
663 | + kfree(sd); | ||
664 | + | ||
665 | + return ret; | ||
666 | +} | ||
667 | + | ||
668 | +static void stantum_remove(struct hid_device *hdev) | ||
669 | +{ | ||
670 | + hid_hw_stop(hdev); | ||
671 | + kfree(hid_get_drvdata(hdev)); | ||
672 | + hid_set_drvdata(hdev, NULL); | ||
673 | +} | ||
674 | + | ||
675 | +static const struct hid_device_id stantum_devices[] = { | ||
676 | + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, | ||
677 | + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM2, USB_DEVICE_ID_MTP2) }, | ||
678 | + { HID_USB_DEVICE(USB_VENDOR_ID_STMICRO, USB_DEVICE_ID_STMICRO_MTP1) }, | ||
679 | + { } | ||
680 | +}; | ||
681 | +MODULE_DEVICE_TABLE(hid, stantum_devices); | ||
682 | + | ||
683 | +static const struct hid_usage_id stantum_grabbed_usages[] = { | ||
684 | + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, | ||
685 | + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} | ||
686 | +}; | ||
687 | + | ||
688 | +static struct hid_driver stantum_driver = { | ||
689 | + .name = "stantum", | ||
690 | + .id_table = stantum_devices, | ||
691 | + .probe = stantum_probe, | ||
692 | + .remove = stantum_remove, | ||
693 | + .input_mapping = stantum_input_mapping, | ||
694 | + .input_mapped = stantum_input_mapped, | ||
695 | + .usage_table = stantum_grabbed_usages, | ||
696 | + .event = stantum_event, | ||
697 | +}; | ||
698 | + | ||
699 | +static int __init stantum_init(void) | ||
700 | +{ | ||
701 | + return hid_register_driver(&stantum_driver); | ||
702 | +} | ||
703 | + | ||
704 | +static void __exit stantum_exit(void) | ||
705 | +{ | ||
706 | + hid_unregister_driver(&stantum_driver); | ||
707 | +} | ||
708 | + | ||
709 | +module_init(stantum_init); | ||
710 | +module_exit(stantum_exit); | ||
711 | + | ||
712 | -- | ||
713 | 1.6.2.2 | ||
714 | |||