summaryrefslogtreecommitdiff
path: root/usr/src/dkms_source_tree/hid-ntrig.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/dkms_source_tree/hid-ntrig.c')
-rw-r--r--usr/src/dkms_source_tree/hid-ntrig.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/usr/src/dkms_source_tree/hid-ntrig.c b/usr/src/dkms_source_tree/hid-ntrig.c
new file mode 100644
index 0000000..7bc1a5e
--- /dev/null
+++ b/usr/src/dkms_source_tree/hid-ntrig.c
@@ -0,0 +1,362 @@
1/*
2 * HID driver for N-Trig touchscreens
3 *
4 * Copyright (c) 2008-2010 Rafi Rubin
5 * Copyright (c) 2009-2010 Stephane Chatty
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/usb.h>
19#include <linux/module.h>
20#include <linux/slab.h>
21
22#include "hid-ids.h"
23
24void usbhid_submit_report
25(struct hid_device *hid, struct hid_report *report, unsigned char dir);
26
27#define NTRIG_DUPLICATE_USAGES 0x001
28
29struct mt_data {
30 int x, y, w, h;
31 int tipswitch;
32 int confidence;
33 int in_range;
34 int foot[4];
35 unsigned int nfoot;
36};
37
38struct ntrig_data {
39 unsigned int id;
40 struct mt_data data[16];
41 int contactcount;
42};
43
44#define SN_MOVE 100
45#define SN_SIZE 50
46
47/*
48 * this driver is aimed at two firmware versions in circulation:
49 * - dual pen/finger single touch
50 * - finger multitouch, pen not working
51 */
52
53static int ntrig_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 delta = field->logical_maximum - field->logical_minimum;
58
59 /* No special mappings needed for the pen and single touch */
60 if (field->physical)
61 return 0;
62
63 switch (usage->hid & HID_USAGE_PAGE) {
64 case HID_UP_GENDESK:
65 switch (usage->hid) {
66 case HID_GD_X:
67 hid_map_usage(hi, usage, bit, max,
68 EV_ABS, ABS_MT_POSITION_X);
69 input_set_abs_params(hi->input, ABS_MT_POSITION_X,
70 field->logical_minimum,
71 field->logical_maximum,
72 delta / SN_MOVE, 0);
73 input_set_abs_params(hi->input, ABS_X,
74 field->logical_minimum,
75 field->logical_maximum,
76 delta / SN_MOVE, 0);
77 return 1;
78 case HID_GD_Y:
79 hid_map_usage(hi, usage, bit, max,
80 EV_ABS, ABS_MT_POSITION_Y);
81 input_set_abs_params(hi->input, ABS_MT_POSITION_Y,
82 field->logical_minimum,
83 field->logical_maximum,
84 delta / SN_MOVE, 0);
85 input_set_abs_params(hi->input, ABS_Y,
86 field->logical_minimum,
87 field->logical_maximum,
88 delta / SN_MOVE, 0);
89 return 1;
90 }
91 return 0;
92
93 case HID_UP_DIGITIZER:
94 switch (usage->hid) {
95 /* we do not want to map these for now */
96 case HID_DG_CONTACTID: /* Not trustworthy, squelch for now */
97 case HID_DG_INPUTMODE:
98 case HID_DG_DEVICEINDEX:
99 case HID_DG_CONTACTMAX:
100 return -1;
101
102 /* width/height mapped on TouchMajor/TouchMinor/Orientation */
103 case HID_DG_WIDTH:
104 hid_map_usage(hi, usage, bit, max,
105 EV_ABS, ABS_MT_TOUCH_MAJOR);
106 input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR,
107 field->logical_minimum,
108 field->logical_maximum,
109 delta / SN_SIZE, 0);
110 return 1;
111 case HID_DG_HEIGHT:
112 hid_map_usage(hi, usage, bit, max,
113 EV_ABS, ABS_MT_TOUCH_MINOR);
114 input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR,
115 field->logical_minimum,
116 field->logical_maximum,
117 delta / SN_SIZE, 0);
118 input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
119 0, 1, 0, 0);
120 return 1;
121 }
122 return 0;
123
124 case 0xff000000:
125 /* we do not want to map these: no input-oriented meaning */
126 return -1;
127 }
128
129 return 0;
130}
131
132static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
133 struct hid_field *field, struct hid_usage *usage,
134 unsigned long **bit, int *max)
135{
136 /* No special mappings needed for the pen and single touch */
137 if (field->physical)
138 return 0;
139
140 if (usage->type == EV_KEY || usage->type == EV_REL
141 || usage->type == EV_ABS)
142 clear_bit(usage->code, *bit);
143
144 return 0;
145}
146
147/*
148 * this function is called upon all reports
149 * so that we can filter contact point information,
150 * decide whether we are in multi or single touch mode
151 * and call input_mt_sync after each point if necessary
152 */
153static int ntrig_event (struct hid_device *hid, struct hid_field *field,
154 struct hid_usage *usage, __s32 value)
155{
156 struct input_dev *input = field->hidinput->input;
157 struct ntrig_data *nd = hid_get_drvdata(hid);
158 struct mt_data *p = &nd->data[nd->id];
159 int i, count;
160
161 /* No special handling needed for the pen */
162 if (field->application == HID_DG_PEN)
163 return 0;
164
165 if (hid->claimed & HID_CLAIMED_INPUT) {
166 switch (usage->hid) {
167 case HID_DG_INRANGE:
168 p->in_range = value;
169 break;
170 /* new mt packet */
171 case 0xff000001:
172 count = nd->contactcount;
173 for (i = 0; i < count; i++) {
174 p = &nd->data[i];
175 input_report_abs(input, ABS_MT_POSITION_X, p->x);
176 input_report_abs(input, ABS_MT_POSITION_Y, p->y);
177 input_report_abs(input, ABS_MT_TOUCH_MINOR, p->h);
178 input_report_abs(input, ABS_MT_TOUCH_MAJOR, p->w);
179 input_report_abs(input, ABS_MT_ORIENTATION, p->w > p->h);
180 input_mt_sync(field->hidinput->input);
181 }
182
183 input_mt_sync(input);
184 input_report_key(input, BTN_TOUCH, count > 0);
185 if (count > 0) {
186 p = &nd->data[0];
187 input_report_abs(input, ABS_X, p->x);
188 input_report_abs(input, ABS_Y, p->y);
189 }
190 //input_sync(input);
191
192 p = &nd->data[nd->id = 0];
193 memset(p, 0, sizeof(*p));
194 break;
195 case HID_DG_TIPSWITCH:
196 p->tipswitch = value;
197 break;
198 case HID_DG_CONFIDENCE:
199 p->confidence = value;
200 break;
201 case HID_DG_CONTACTID:
202 if (value >= 6)
203 break;
204 p = &nd->data[nd->id = value];
205 memset(p, 0, sizeof(*p));
206 break;
207 case HID_GD_X:
208 p->x = value;
209 break;
210 case HID_GD_Y:
211 p->y = value;
212 break;
213 case HID_DG_WIDTH:
214 p->w = value;
215 break;
216 case HID_DG_HEIGHT:
217 p->h = value;
218 break;
219 case 0xff000002:
220 if (p->nfoot < 4)
221 p->foot[p->nfoot++] = value;
222 else
223 printk(KERN_INFO "NTRIG: lots %d\n", value);
224 break;
225
226 case HID_DG_CONTACTCOUNT:
227 nd->contactcount = value;
228 break;
229
230 default:
231 return 0;
232 }
233 }
234
235 /* we have handled the hidinput part, now remains hiddev */
236 if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event)
237 hid->hiddev_hid_event(hid, field, usage, value);
238
239 return 1;
240}
241
242static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
243{
244 int ret;
245 struct ntrig_data *nd;
246 struct hid_input *hidinput;
247 struct input_dev *input;
248 struct hid_report *report;
249
250 if (id->driver_data & NTRIG_DUPLICATE_USAGES)
251 hdev->quirks |= HID_QUIRK_MULTI_INPUT;
252 //hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
253
254 nd = kzalloc(sizeof(struct ntrig_data), GFP_KERNEL);
255 if (!nd) {
256 dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
257 return -ENOMEM;
258 }
259
260 hid_set_drvdata(hdev, nd);
261
262 ret = hid_parse(hdev);
263 if (ret) {
264 dev_err(&hdev->dev, "parse failed\n");
265 goto err_free;
266 }
267
268 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
269 if (ret) {
270 dev_err(&hdev->dev, "hw start failed\n");
271 goto err_free;
272 }
273
274
275 list_for_each_entry(hidinput, &hdev->inputs, list) {
276 if (hidinput->report->maxfield < 1)
277
278 continue;
279
280 input = hidinput->input;
281 switch (hidinput->report->field[0]->application) {
282 case HID_DG_PEN:
283 input->name = "N-Trig Pen";
284 break;
285 case HID_DG_TOUCHSCREEN:
286 /* These keys are redundant for fingers, clear them
287 * to prevent incorrect identification */
288 __clear_bit(BTN_TOOL_PEN, input->keybit);
289 __clear_bit(BTN_TOOL_FINGER, input->keybit);
290 __clear_bit(BTN_0, input->keybit);
291 __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
292 /*
293 * The physical touchscreen (single touch)
294 * input has a value for physical, whereas
295 * the multitouch only has logical input
296 * fields.
297 */
298 input->name =
299 (hidinput->report->field[0]
300 ->physical) ?
301 "N-Trig Touchscreen" :
302 "N-Trig MultiTouch";
303 break;
304 }
305 }
306
307 /* This is needed for devices with more recent firmware versions */
308 report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0x0a];
309 if (report)
310 usbhid_submit_report(hdev, report, USB_DIR_OUT);
311
312 return 0;
313err_free:
314 kfree(nd);
315 return ret;
316}
317
318static void ntrig_remove(struct hid_device *hdev)
319{
320 hid_hw_stop(hdev);
321 kfree(hid_get_drvdata(hdev));
322}
323
324#define NTRIG_DEVICE(id) \
325 { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, id), \
326 .driver_data = NTRIG_DUPLICATE_USAGES }
327
328static const struct hid_device_id ntrig_devices[] = {
329 NTRIG_DEVICE(0x0001),
330 { }
331};
332MODULE_DEVICE_TABLE(hid, ntrig_devices);
333
334static const struct hid_usage_id ntrig_grabbed_usages[] = {
335 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
336 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
337};
338
339static struct hid_driver ntrig_driver = {
340 .name = "ntrig",
341 .id_table = ntrig_devices,
342 .probe = ntrig_probe,
343 .remove = ntrig_remove,
344 .input_mapping = ntrig_input_mapping,
345 .input_mapped = ntrig_input_mapped,
346 .usage_table = ntrig_grabbed_usages,
347 .event = ntrig_event,
348};
349
350static int __init ntrig_init(void)
351{
352 return hid_register_driver(&ntrig_driver);
353}
354
355static void __exit ntrig_exit(void)
356{
357 hid_unregister_driver(&ntrig_driver);
358}
359
360module_init(ntrig_init);
361module_exit(ntrig_exit);
362MODULE_LICENSE("GPL");