hid-ntrig.c revision ed7e2ca24bfff5c7a09de8a05c536f68560b34fb
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 "usbhid/usbhid.h"
20#include <linux/module.h>
21#include <linux/slab.h>
22
23#include "hid-ids.h"
24
25#define NTRIG_DUPLICATE_USAGES	0x001
26
27struct ntrig_data {
28	/* Incoming raw values for a single contact */
29	__u16 x, y, w, h;
30	__u16 id;
31
32	bool tipswitch;
33	bool confidence;
34	bool first_contact_touch;
35
36	bool reading_mt;
37
38	__u8 mt_footer[4];
39	__u8 mt_foot_count;
40};
41
42/*
43 * this driver is aimed at two firmware versions in circulation:
44 *  - dual pen/finger single touch
45 *  - finger multitouch, pen not working
46 */
47
48static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
49		struct hid_field *field, struct hid_usage *usage,
50		unsigned long **bit, int *max)
51{
52	/* No special mappings needed for the pen and single touch */
53	if (field->physical)
54		return 0;
55
56	switch (usage->hid & HID_USAGE_PAGE) {
57	case HID_UP_GENDESK:
58		switch (usage->hid) {
59		case HID_GD_X:
60			hid_map_usage(hi, usage, bit, max,
61					EV_ABS, ABS_MT_POSITION_X);
62			input_set_abs_params(hi->input, ABS_X,
63					field->logical_minimum,
64					field->logical_maximum, 0, 0);
65			return 1;
66		case HID_GD_Y:
67			hid_map_usage(hi, usage, bit, max,
68					EV_ABS, ABS_MT_POSITION_Y);
69			input_set_abs_params(hi->input, ABS_Y,
70					field->logical_minimum,
71					field->logical_maximum, 0, 0);
72			return 1;
73		}
74		return 0;
75
76	case HID_UP_DIGITIZER:
77		switch (usage->hid) {
78		/* we do not want to map these for now */
79		case HID_DG_CONTACTID: /* Not trustworthy, squelch for now */
80		case HID_DG_INPUTMODE:
81		case HID_DG_DEVICEINDEX:
82		case HID_DG_CONTACTMAX:
83			return -1;
84
85		/* width/height mapped on TouchMajor/TouchMinor/Orientation */
86		case HID_DG_WIDTH:
87			hid_map_usage(hi, usage, bit, max,
88					EV_ABS, ABS_MT_TOUCH_MAJOR);
89			return 1;
90		case HID_DG_HEIGHT:
91			hid_map_usage(hi, usage, bit, max,
92					EV_ABS, ABS_MT_TOUCH_MINOR);
93			input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
94					0, 1, 0, 0);
95			return 1;
96		}
97		return 0;
98
99	case 0xff000000:
100		/* we do not want to map these: no input-oriented meaning */
101		return -1;
102	}
103
104	return 0;
105}
106
107static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
108		struct hid_field *field, struct hid_usage *usage,
109		unsigned long **bit, int *max)
110{
111	/* No special mappings needed for the pen and single touch */
112	if (field->physical)
113		return 0;
114
115	if (usage->type == EV_KEY || usage->type == EV_REL
116			|| usage->type == EV_ABS)
117		clear_bit(usage->code, *bit);
118
119	return 0;
120}
121
122/*
123 * this function is called upon all reports
124 * so that we can filter contact point information,
125 * decide whether we are in multi or single touch mode
126 * and call input_mt_sync after each point if necessary
127 */
128static int ntrig_event (struct hid_device *hid, struct hid_field *field,
129		                        struct hid_usage *usage, __s32 value)
130{
131	struct input_dev *input = field->hidinput->input;
132	struct ntrig_data *nd = hid_get_drvdata(hid);
133
134	/* No special handling needed for the pen */
135	if (field->application == HID_DG_PEN)
136		return 0;
137
138        if (hid->claimed & HID_CLAIMED_INPUT) {
139		switch (usage->hid) {
140		case 0xff000001:
141			/* Tag indicating the start of a multitouch group */
142			nd->reading_mt = 1;
143			nd->first_contact_touch = 0;
144			break;
145		case HID_DG_TIPSWITCH:
146			nd->tipswitch = value;
147			/* Prevent emission of touch until validated */
148			return 1;
149		case HID_DG_CONFIDENCE:
150			nd->confidence = value;
151			break;
152		case HID_GD_X:
153			nd->x = value;
154			/* Clear the contact footer */
155			nd->mt_foot_count = 0;
156			break;
157		case HID_GD_Y:
158			nd->y = value;
159			break;
160		case HID_DG_CONTACTID:
161			nd->id = value;
162			break;
163		case HID_DG_WIDTH:
164			nd->w = value;
165			break;
166		case HID_DG_HEIGHT:
167			nd->h = value;
168			/*
169			 * when in single touch mode, this is the last
170			 * report received in a finger event. We want
171			 * to emit a normal (X, Y) position
172			 */
173			if (!nd->reading_mt) {
174				/*
175				 * TipSwitch indicates the presence of a
176				 * finger in single touch mode.
177				 */
178				input_report_key(input, BTN_TOUCH,
179						 nd->tipswitch);
180				input_report_key(input, BTN_TOOL_DOUBLETAP,
181						 nd->tipswitch);
182				input_event(input, EV_ABS, ABS_X, nd->x);
183				input_event(input, EV_ABS, ABS_Y, nd->y);
184			}
185			break;
186		case 0xff000002:
187			/*
188			 * we receive this when the device is in multitouch
189			 * mode. The first of the three values tagged with
190			 * this usage tells if the contact point is real
191			 * or a placeholder
192			 */
193
194			/* Shouldn't get more than 4 footer packets, so skip */
195			if (nd->mt_foot_count >= 4)
196				break;
197
198			nd->mt_footer[nd->mt_foot_count++] = value;
199
200			/* if the footer isn't complete break */
201			if (nd->mt_foot_count != 4)
202				break;
203
204			/* Pen activity signal, trigger end of touch. */
205			if (nd->mt_footer[2]) {
206				nd->confidence = 0;
207				break;
208			}
209
210			/* If the contact was invalid */
211			if (!(nd->confidence && nd->mt_footer[0])
212					|| nd->w <= 250
213					|| nd->h <= 190) {
214				nd->confidence = 0;
215				break;
216			}
217
218			/* emit a normal (X, Y) for the first point only */
219			if (nd->id == 0) {
220				/*
221				 * TipSwitch is superfluous in multitouch
222				 * mode.  The footer events tell us
223				 * if there is a finger on the screen or
224				 * not.
225				 */
226				nd->first_contact_touch = nd->confidence;
227				input_event(input, EV_ABS, ABS_X, nd->x);
228				input_event(input, EV_ABS, ABS_Y, nd->y);
229			}
230			input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
231			input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
232			if (nd->w > nd->h) {
233				input_event(input, EV_ABS,
234						ABS_MT_ORIENTATION, 1);
235				input_event(input, EV_ABS,
236						ABS_MT_TOUCH_MAJOR, nd->w);
237				input_event(input, EV_ABS,
238						ABS_MT_TOUCH_MINOR, nd->h);
239			} else {
240				input_event(input, EV_ABS,
241						ABS_MT_ORIENTATION, 0);
242				input_event(input, EV_ABS,
243						ABS_MT_TOUCH_MAJOR, nd->h);
244				input_event(input, EV_ABS,
245						ABS_MT_TOUCH_MINOR, nd->w);
246			}
247			input_mt_sync(field->hidinput->input);
248			break;
249
250		case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
251			if (!nd->reading_mt)
252				break;
253
254			nd->reading_mt = 0;
255
256			if (nd->first_contact_touch) {
257				input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
258				input_report_key(input, BTN_TOUCH, 1);
259			} else {
260				input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
261				input_report_key(input, BTN_TOUCH, 0);
262			}
263			break;
264
265		default:
266			/* fallback to the generic hidinput handling */
267			return 0;
268		}
269	}
270
271	/* we have handled the hidinput part, now remains hiddev */
272	if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event)
273		hid->hiddev_hid_event(hid, field, usage, value);
274
275	return 1;
276}
277
278static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
279{
280	int ret;
281	struct ntrig_data *nd;
282	struct hid_input *hidinput;
283	struct input_dev *input;
284	struct hid_report *report;
285
286	if (id->driver_data)
287		hdev->quirks |= HID_QUIRK_MULTI_INPUT;
288
289	nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
290	if (!nd) {
291		dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
292		return -ENOMEM;
293	}
294
295	nd->reading_mt = 0;
296	hid_set_drvdata(hdev, nd);
297
298	ret = hid_parse(hdev);
299	if (ret) {
300		dev_err(&hdev->dev, "parse failed\n");
301		goto err_free;
302	}
303
304	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
305	if (ret) {
306		dev_err(&hdev->dev, "hw start failed\n");
307		goto err_free;
308	}
309
310
311	list_for_each_entry(hidinput, &hdev->inputs, list) {
312		if (hidinput->report->maxfield < 1)
313			continue;
314
315		input = hidinput->input;
316		switch (hidinput->report->field[0]->application) {
317		case HID_DG_PEN:
318			input->name = "N-Trig Pen";
319			break;
320		case HID_DG_TOUCHSCREEN:
321			/* These keys are redundant for fingers, clear them
322			 * to prevent incorrect identification */
323			__clear_bit(BTN_TOOL_PEN, input->keybit);
324			__clear_bit(BTN_TOOL_FINGER, input->keybit);
325			__clear_bit(BTN_0, input->keybit);
326			__set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
327			/*
328			 * The physical touchscreen (single touch)
329			 * input has a value for physical, whereas
330			 * the multitouch only has logical input
331			 * fields.
332			 */
333			input->name =
334				(hidinput->report->field[0]
335				 ->physical) ?
336				"N-Trig Touchscreen" :
337				"N-Trig MultiTouch";
338			break;
339		}
340	}
341
342	/* This is needed for devices with more recent firmware versions */
343	report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0x0a];
344	if (report)
345		usbhid_submit_report(hdev, report, USB_DIR_OUT);
346
347
348	return 0;
349err_free:
350	kfree(nd);
351	return ret;
352}
353
354static void ntrig_remove(struct hid_device *hdev)
355{
356	hid_hw_stop(hdev);
357	kfree(hid_get_drvdata(hdev));
358}
359
360static const struct hid_device_id ntrig_devices[] = {
361	{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN),
362		.driver_data = NTRIG_DUPLICATE_USAGES },
363	{ }
364};
365MODULE_DEVICE_TABLE(hid, ntrig_devices);
366
367static const struct hid_usage_id ntrig_grabbed_usages[] = {
368	{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
369	{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
370};
371
372static struct hid_driver ntrig_driver = {
373	.name = "ntrig",
374	.id_table = ntrig_devices,
375	.probe = ntrig_probe,
376	.remove = ntrig_remove,
377	.input_mapping = ntrig_input_mapping,
378	.input_mapped = ntrig_input_mapped,
379	.usage_table = ntrig_grabbed_usages,
380	.event = ntrig_event,
381};
382
383static int __init ntrig_init(void)
384{
385	return hid_register_driver(&ntrig_driver);
386}
387
388static void __exit ntrig_exit(void)
389{
390	hid_unregister_driver(&ntrig_driver);
391}
392
393module_init(ntrig_init);
394module_exit(ntrig_exit);
395MODULE_LICENSE("GPL");
396