Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/hid/hid-quanta.c
15112 views
1
/*
2
* HID driver for Quanta Optical Touch dual-touch panels
3
*
4
* Copyright (c) 2009-2010 Stephane Chatty <[email protected]>
5
*
6
*/
7
8
/*
9
* This program is free software; you can redistribute it and/or modify it
10
* under the terms of the GNU General Public License as published by the Free
11
* Software Foundation; either version 2 of the License, or (at your option)
12
* any later version.
13
*/
14
15
#include <linux/device.h>
16
#include <linux/hid.h>
17
#include <linux/module.h>
18
#include <linux/slab.h>
19
20
MODULE_AUTHOR("Stephane Chatty <[email protected]>");
21
MODULE_DESCRIPTION("Quanta dual-touch panel");
22
MODULE_LICENSE("GPL");
23
24
#include "hid-ids.h"
25
26
struct quanta_data {
27
__u16 x, y;
28
__u8 id;
29
bool valid; /* valid finger data, or just placeholder? */
30
bool first; /* is this the first finger in this frame? */
31
bool activity_now; /* at least one active finger in this frame? */
32
bool activity; /* at least one active finger previously? */
33
};
34
35
static int quanta_input_mapping(struct hid_device *hdev, struct hid_input *hi,
36
struct hid_field *field, struct hid_usage *usage,
37
unsigned long **bit, int *max)
38
{
39
switch (usage->hid & HID_USAGE_PAGE) {
40
41
case HID_UP_GENDESK:
42
switch (usage->hid) {
43
case HID_GD_X:
44
hid_map_usage(hi, usage, bit, max,
45
EV_ABS, ABS_MT_POSITION_X);
46
/* touchscreen emulation */
47
input_set_abs_params(hi->input, ABS_X,
48
field->logical_minimum,
49
field->logical_maximum, 0, 0);
50
return 1;
51
case HID_GD_Y:
52
hid_map_usage(hi, usage, bit, max,
53
EV_ABS, ABS_MT_POSITION_Y);
54
/* touchscreen emulation */
55
input_set_abs_params(hi->input, ABS_Y,
56
field->logical_minimum,
57
field->logical_maximum, 0, 0);
58
return 1;
59
}
60
return 0;
61
62
case HID_UP_DIGITIZER:
63
switch (usage->hid) {
64
case HID_DG_CONFIDENCE:
65
case HID_DG_TIPSWITCH:
66
case HID_DG_INPUTMODE:
67
case HID_DG_DEVICEINDEX:
68
case HID_DG_CONTACTCOUNT:
69
case HID_DG_CONTACTMAX:
70
case HID_DG_TIPPRESSURE:
71
case HID_DG_WIDTH:
72
case HID_DG_HEIGHT:
73
return -1;
74
case HID_DG_INRANGE:
75
/* touchscreen emulation */
76
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
77
return 1;
78
case HID_DG_CONTACTID:
79
hid_map_usage(hi, usage, bit, max,
80
EV_ABS, ABS_MT_TRACKING_ID);
81
return 1;
82
}
83
return 0;
84
85
case 0xff000000:
86
/* ignore vendor-specific features */
87
return -1;
88
}
89
90
return 0;
91
}
92
93
static int quanta_input_mapped(struct hid_device *hdev, struct hid_input *hi,
94
struct hid_field *field, struct hid_usage *usage,
95
unsigned long **bit, int *max)
96
{
97
if (usage->type == EV_KEY || usage->type == EV_ABS)
98
clear_bit(usage->code, *bit);
99
100
return 0;
101
}
102
103
/*
104
* this function is called when a whole finger has been parsed,
105
* so that it can decide what to send to the input layer.
106
*/
107
static void quanta_filter_event(struct quanta_data *td, struct input_dev *input)
108
{
109
110
td->first = !td->first; /* touchscreen emulation */
111
112
if (!td->valid) {
113
/*
114
* touchscreen emulation: if no finger in this frame is valid
115
* and there previously was finger activity, this is a release
116
*/
117
if (!td->first && !td->activity_now && td->activity) {
118
input_event(input, EV_KEY, BTN_TOUCH, 0);
119
td->activity = false;
120
}
121
return;
122
}
123
124
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
125
input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
126
input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
127
128
input_mt_sync(input);
129
td->valid = false;
130
131
/* touchscreen emulation: if first active finger in this frame... */
132
if (!td->activity_now) {
133
/* if there was no previous activity, emit touch event */
134
if (!td->activity) {
135
input_event(input, EV_KEY, BTN_TOUCH, 1);
136
td->activity = true;
137
}
138
td->activity_now = true;
139
/* and in any case this is our preferred finger */
140
input_event(input, EV_ABS, ABS_X, td->x);
141
input_event(input, EV_ABS, ABS_Y, td->y);
142
}
143
}
144
145
146
static int quanta_event(struct hid_device *hid, struct hid_field *field,
147
struct hid_usage *usage, __s32 value)
148
{
149
struct quanta_data *td = hid_get_drvdata(hid);
150
151
if (hid->claimed & HID_CLAIMED_INPUT) {
152
struct input_dev *input = field->hidinput->input;
153
154
switch (usage->hid) {
155
case HID_DG_INRANGE:
156
td->valid = !!value;
157
break;
158
case HID_GD_X:
159
td->x = value;
160
break;
161
case HID_GD_Y:
162
td->y = value;
163
quanta_filter_event(td, input);
164
break;
165
case HID_DG_CONTACTID:
166
td->id = value;
167
break;
168
case HID_DG_CONTACTCOUNT:
169
/* touch emulation: this is the last field in a frame */
170
td->first = false;
171
td->activity_now = false;
172
break;
173
case HID_DG_CONFIDENCE:
174
case HID_DG_TIPSWITCH:
175
/* avoid interference from generic hidinput handling */
176
break;
177
178
default:
179
/* fallback to the generic hidinput handling */
180
return 0;
181
}
182
}
183
184
/* we have handled the hidinput part, now remains hiddev */
185
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
186
hid->hiddev_hid_event(hid, field, usage, value);
187
188
return 1;
189
}
190
191
static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id)
192
{
193
int ret;
194
struct quanta_data *td;
195
196
td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL);
197
if (!td) {
198
hid_err(hdev, "cannot allocate Quanta Touch data\n");
199
return -ENOMEM;
200
}
201
td->valid = false;
202
td->activity = false;
203
td->activity_now = false;
204
td->first = false;
205
hid_set_drvdata(hdev, td);
206
207
ret = hid_parse(hdev);
208
if (!ret)
209
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
210
211
if (ret)
212
kfree(td);
213
214
return ret;
215
}
216
217
static void quanta_remove(struct hid_device *hdev)
218
{
219
hid_hw_stop(hdev);
220
kfree(hid_get_drvdata(hdev));
221
hid_set_drvdata(hdev, NULL);
222
}
223
224
static const struct hid_device_id quanta_devices[] = {
225
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
226
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
227
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
228
USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
229
{ }
230
};
231
MODULE_DEVICE_TABLE(hid, quanta_devices);
232
233
static const struct hid_usage_id quanta_grabbed_usages[] = {
234
{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
235
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
236
};
237
238
static struct hid_driver quanta_driver = {
239
.name = "quanta-touch",
240
.id_table = quanta_devices,
241
.probe = quanta_probe,
242
.remove = quanta_remove,
243
.input_mapping = quanta_input_mapping,
244
.input_mapped = quanta_input_mapped,
245
.usage_table = quanta_grabbed_usages,
246
.event = quanta_event,
247
};
248
249
static int __init quanta_init(void)
250
{
251
return hid_register_driver(&quanta_driver);
252
}
253
254
static void __exit quanta_exit(void)
255
{
256
hid_unregister_driver(&quanta_driver);
257
}
258
259
module_init(quanta_init);
260
module_exit(quanta_exit);
261
262
263