summaryrefslogtreecommitdiff
path: root/usr/src/dkms_source_tree/hid-mosart.c
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2010-11-01 21:03:10 +0100
committerHenrik Rydberg <rydberg@euromail.se>2010-11-01 21:03:10 +0100
commit7c462d8bee333fd8f7d35e8e2c865dd5ea63b44f (patch)
treea7a6e80421ad2212c6159e53fc4e05f462ae5d74 /usr/src/dkms_source_tree/hid-mosart.c
initial load of mosart driver
Signed-off-by: Henrik Rydberg <rydberg@bitmath.org>
Diffstat (limited to 'usr/src/dkms_source_tree/hid-mosart.c')
-rw-r--r--usr/src/dkms_source_tree/hid-mosart.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/usr/src/dkms_source_tree/hid-mosart.c b/usr/src/dkms_source_tree/hid-mosart.c
new file mode 100644
index 0000000..3ac9be6
--- /dev/null
+++ b/usr/src/dkms_source_tree/hid-mosart.c
@@ -0,0 +1,277 @@
1/*
2 * HID driver for the multitouch panel on the ASUS EeePC T91MT
3 *
4 * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
5 * Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.com>
6 *
7 */
8
9/*
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 */
15
16#include <linux/device.h>
17#include <linux/hid.h>
18#include <linux/module.h>
19#include <linux/slab.h>
20#include <linux/usb.h>
21
22MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
23MODULE_DESCRIPTION("MosArt dual-touch panel");
24MODULE_LICENSE("GPL");
25
26#include "hid-ids.h"
27
28void usbhid_submit_report
29(struct hid_device *hid, struct hid_report *report, unsigned char dir);
30
31struct mosart_data {
32 __u16 x, y;
33 __u8 id;
34 bool valid; /* valid finger data, or just placeholder? */
35 bool first; /* is this the first finger in this frame? */
36 bool activity_now; /* at least one active finger in this frame? */
37 bool activity; /* at least one active finger previously? */
38};
39
40static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
41 struct hid_field *field, struct hid_usage *usage,
42 unsigned long **bit, int *max)
43{
44 switch (usage->hid & HID_USAGE_PAGE) {
45
46 case HID_UP_GENDESK:
47 switch (usage->hid) {
48 case HID_GD_X:
49 hid_map_usage(hi, usage, bit, max,
50 EV_ABS, ABS_MT_POSITION_X);
51 /* touchscreen emulation */
52 input_set_abs_params(hi->input, ABS_X,
53 field->logical_minimum,
54 field->logical_maximum, 0, 0);
55 return 1;
56 case HID_GD_Y:
57 hid_map_usage(hi, usage, bit, max,
58 EV_ABS, ABS_MT_POSITION_Y);
59 /* touchscreen emulation */
60 input_set_abs_params(hi->input, ABS_Y,
61 field->logical_minimum,
62 field->logical_maximum, 0, 0);
63 return 1;
64 }
65 return 0;
66
67 case HID_UP_DIGITIZER:
68 switch (usage->hid) {
69 case HID_DG_CONFIDENCE:
70 case HID_DG_TIPSWITCH:
71 case HID_DG_INPUTMODE:
72 case HID_DG_DEVICEINDEX:
73 case HID_DG_CONTACTCOUNT:
74 case HID_DG_CONTACTMAX:
75 case HID_DG_TIPPRESSURE:
76 case HID_DG_WIDTH:
77 case HID_DG_HEIGHT:
78 return -1;
79 case HID_DG_INRANGE:
80 /* touchscreen emulation */
81 hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
82 return 1;
83
84 case HID_DG_CONTACTID:
85 hid_map_usage(hi, usage, bit, max,
86 EV_ABS, ABS_MT_TRACKING_ID);
87 return 1;
88
89 }
90 return 0;
91
92 case 0xff000000:
93 /* ignore HID features */
94 return -1;
95 }
96
97 return 0;
98}
99
100static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi,
101 struct hid_field *field, struct hid_usage *usage,
102 unsigned long **bit, int *max)
103{
104 if (usage->type == EV_KEY || usage->type == EV_ABS)
105 clear_bit(usage->code, *bit);
106
107 return 0;
108}
109
110/*
111 * this function is called when a whole finger has been parsed,
112 * so that it can decide what to send to the input layer.
113 */
114static void mosart_filter_event(struct mosart_data *td, struct input_dev *input)
115{
116 td->first = !td->first; /* touchscreen emulation */
117
118 if (!td->valid) {
119 /*
120 * touchscreen emulation: if no finger in this frame is valid
121 * and there previously was finger activity, this is a release
122 */
123 if (!td->first && !td->activity_now && td->activity) {
124 input_event(input, EV_KEY, BTN_TOUCH, 0);
125 td->activity = false;
126 }
127 return;
128 }
129
130 input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
131 input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
132 input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
133
134 input_mt_sync(input);
135 td->valid = false;
136
137 /* touchscreen emulation: if first active finger in this frame... */
138 if (!td->activity_now) {
139 /* if there was no previous activity, emit touch event */
140 if (!td->activity) {
141 input_event(input, EV_KEY, BTN_TOUCH, 1);
142 td->activity = true;
143 }
144 td->activity_now = true;
145 /* and in any case this is our preferred finger */
146 input_event(input, EV_ABS, ABS_X, td->x);
147 input_event(input, EV_ABS, ABS_Y, td->y);
148 }
149}
150
151
152static int mosart_event(struct hid_device *hid, struct hid_field *field,
153 struct hid_usage *usage, __s32 value)
154{
155 struct mosart_data *td = hid_get_drvdata(hid);
156
157 if (hid->claimed & HID_CLAIMED_INPUT) {
158 struct input_dev *input = field->hidinput->input;
159 switch (usage->hid) {
160 case HID_DG_INRANGE:
161 td->valid = !!value;
162 break;
163 case HID_GD_X:
164 td->x = value;
165 break;
166 case HID_GD_Y:
167 td->y = value;
168 mosart_filter_event(td, input);
169 break;
170 case HID_DG_CONTACTID:
171 td->id = value;
172 break;
173 case HID_DG_CONTACTCOUNT:
174 /* touch emulation: this is the last field in a frame */
175 td->first = false;
176 td->activity_now = false;
177 break;
178 case HID_DG_CONFIDENCE:
179 case HID_DG_TIPSWITCH:
180 /* avoid interference from generic hidinput handling */
181 break;
182
183 default:
184 /* fallback to the generic hidinput handling */
185 return 0;
186 }
187 }
188
189 /* we have handled the hidinput part, now remains hiddev */
190 if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
191 hid->hiddev_hid_event(hid, field, usage, value);
192
193 return 1;
194}
195
196static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
197{
198 int ret;
199 struct mosart_data *td;
200
201
202 td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
203 if (!td) {
204 dev_err(&hdev->dev, "cannot allocate MosArt data\n");
205 return -ENOMEM;
206 }
207 td->valid = false;
208 td->activity = false;
209 td->activity_now = false;
210 td->first = false;
211 hid_set_drvdata(hdev, td);
212
213 /* currently, it's better to have one evdev device only */
214#if 0
215 hdev->quirks |= HID_QUIRK_MULTI_INPUT;
216#endif
217
218 ret = hid_parse(hdev);
219 if (ret == 0)
220 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
221
222 if (ret == 0) {
223 struct hid_report_enum *re = hdev->report_enum
224 + HID_FEATURE_REPORT;
225 struct hid_report *r = re->report_id_hash[7];
226
227 r->field[0]->value[0] = 0x02;
228 usbhid_submit_report(hdev, r, USB_DIR_OUT);
229 } else
230 kfree(td);
231
232 return ret;
233}
234
235static void mosart_remove(struct hid_device *hdev)
236{
237 hid_hw_stop(hdev);
238 kfree(hid_get_drvdata(hdev));
239 hid_set_drvdata(hdev, NULL);
240}
241
242static const struct hid_device_id mosart_devices[] = {
243 { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
244 { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
245 { }
246};
247MODULE_DEVICE_TABLE(hid, mosart_devices);
248
249static const struct hid_usage_id mosart_grabbed_usages[] = {
250 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
251 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
252};
253
254static struct hid_driver mosart_driver = {
255 .name = "mosart",
256 .id_table = mosart_devices,
257 .probe = mosart_probe,
258 .remove = mosart_remove,
259 .input_mapping = mosart_input_mapping,
260 .input_mapped = mosart_input_mapped,
261 .usage_table = mosart_grabbed_usages,
262 .event = mosart_event,
263};
264
265static int __init mosart_init(void)
266{
267 return hid_register_driver(&mosart_driver);
268}
269
270static void __exit mosart_exit(void)
271{
272 hid_unregister_driver(&mosart_driver);
273}
274
275module_init(mosart_init);
276module_exit(mosart_exit);
277