diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-01-07 01:34:59 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-01-07 01:34:59 -0500 |
commit | 554738da71004d96e06fb75f4772dfc3b0f47810 (patch) | |
tree | 149a96ce3727025d3b9260961ec94ba8306db278 /drivers/hid/hid-egalax.c | |
parent | 7b4b30689d688d9ca2e5c3859db6bbe1c35e6014 (diff) | |
parent | a6d38f889750ed6290728a19d9dad577b147c6d0 (diff) |
Merge branch 'next' into for-linus
Conflicts:
include/linux/input.h
Diffstat (limited to 'drivers/hid/hid-egalax.c')
-rw-r--r-- | drivers/hid/hid-egalax.c | 131 |
1 files changed, 57 insertions, 74 deletions
diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c index 54b017ad258d..16566fcc08a3 100644 --- a/drivers/hid/hid-egalax.c +++ b/drivers/hid/hid-egalax.c | |||
@@ -2,6 +2,8 @@ | |||
2 | * HID driver for eGalax dual-touch panels | 2 | * HID driver for eGalax dual-touch panels |
3 | * | 3 | * |
4 | * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> | 4 | * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> |
5 | * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
6 | * Copyright (c) 2010 Canonical, Ltd. | ||
5 | * | 7 | * |
6 | */ | 8 | */ |
7 | 9 | ||
@@ -16,6 +18,7 @@ | |||
16 | #include <linux/hid.h> | 18 | #include <linux/hid.h> |
17 | #include <linux/module.h> | 19 | #include <linux/module.h> |
18 | #include <linux/usb.h> | 20 | #include <linux/usb.h> |
21 | #include <linux/input/mt.h> | ||
19 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
20 | #include "usbhid/usbhid.h" | 23 | #include "usbhid/usbhid.h" |
21 | 24 | ||
@@ -25,38 +28,53 @@ MODULE_LICENSE("GPL"); | |||
25 | 28 | ||
26 | #include "hid-ids.h" | 29 | #include "hid-ids.h" |
27 | 30 | ||
31 | #define MAX_SLOTS 2 | ||
32 | |||
33 | /* estimated signal-to-noise ratios */ | ||
34 | #define SN_MOVE 4096 | ||
35 | #define SN_PRESSURE 32 | ||
36 | |||
28 | struct egalax_data { | 37 | struct egalax_data { |
29 | __u16 x, y, z; | 38 | int valid; |
30 | __u8 id; | 39 | int slot; |
31 | bool first; /* is this the first finger in the frame? */ | 40 | int touch; |
32 | bool valid; /* valid finger data, or just placeholder? */ | 41 | int x, y, z; |
33 | bool activity; /* at least one active finger previously? */ | ||
34 | __u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */ | ||
35 | }; | 42 | }; |
36 | 43 | ||
44 | static void set_abs(struct input_dev *input, unsigned int code, | ||
45 | struct hid_field *field, int snratio) | ||
46 | { | ||
47 | int fmin = field->logical_minimum; | ||
48 | int fmax = field->logical_maximum; | ||
49 | int fuzz = snratio ? (fmax - fmin) / snratio : 0; | ||
50 | input_set_abs_params(input, code, fmin, fmax, fuzz, 0); | ||
51 | } | ||
52 | |||
37 | static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, | 53 | static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, |
38 | struct hid_field *field, struct hid_usage *usage, | 54 | struct hid_field *field, struct hid_usage *usage, |
39 | unsigned long **bit, int *max) | 55 | unsigned long **bit, int *max) |
40 | { | 56 | { |
57 | struct input_dev *input = hi->input; | ||
58 | |||
41 | switch (usage->hid & HID_USAGE_PAGE) { | 59 | switch (usage->hid & HID_USAGE_PAGE) { |
42 | 60 | ||
43 | case HID_UP_GENDESK: | 61 | case HID_UP_GENDESK: |
44 | switch (usage->hid) { | 62 | switch (usage->hid) { |
45 | case HID_GD_X: | 63 | case HID_GD_X: |
64 | field->logical_maximum = 32760; | ||
46 | hid_map_usage(hi, usage, bit, max, | 65 | hid_map_usage(hi, usage, bit, max, |
47 | EV_ABS, ABS_MT_POSITION_X); | 66 | EV_ABS, ABS_MT_POSITION_X); |
67 | set_abs(input, ABS_MT_POSITION_X, field, SN_MOVE); | ||
48 | /* touchscreen emulation */ | 68 | /* touchscreen emulation */ |
49 | input_set_abs_params(hi->input, ABS_X, | 69 | set_abs(input, ABS_X, field, SN_MOVE); |
50 | field->logical_minimum, | ||
51 | field->logical_maximum, 0, 0); | ||
52 | return 1; | 70 | return 1; |
53 | case HID_GD_Y: | 71 | case HID_GD_Y: |
72 | field->logical_maximum = 32760; | ||
54 | hid_map_usage(hi, usage, bit, max, | 73 | hid_map_usage(hi, usage, bit, max, |
55 | EV_ABS, ABS_MT_POSITION_Y); | 74 | EV_ABS, ABS_MT_POSITION_Y); |
75 | set_abs(input, ABS_MT_POSITION_Y, field, SN_MOVE); | ||
56 | /* touchscreen emulation */ | 76 | /* touchscreen emulation */ |
57 | input_set_abs_params(hi->input, ABS_Y, | 77 | set_abs(input, ABS_Y, field, SN_MOVE); |
58 | field->logical_minimum, | ||
59 | field->logical_maximum, 0, 0); | ||
60 | return 1; | 78 | return 1; |
61 | } | 79 | } |
62 | return 0; | 80 | return 0; |
@@ -66,6 +84,7 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
66 | case HID_DG_TIPSWITCH: | 84 | case HID_DG_TIPSWITCH: |
67 | /* touchscreen emulation */ | 85 | /* touchscreen emulation */ |
68 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | 86 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); |
87 | input_set_capability(input, EV_KEY, BTN_TOUCH); | ||
69 | return 1; | 88 | return 1; |
70 | case HID_DG_INRANGE: | 89 | case HID_DG_INRANGE: |
71 | case HID_DG_CONFIDENCE: | 90 | case HID_DG_CONFIDENCE: |
@@ -73,16 +92,15 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
73 | case HID_DG_CONTACTMAX: | 92 | case HID_DG_CONTACTMAX: |
74 | return -1; | 93 | return -1; |
75 | case HID_DG_CONTACTID: | 94 | case HID_DG_CONTACTID: |
76 | hid_map_usage(hi, usage, bit, max, | 95 | input_mt_init_slots(input, MAX_SLOTS); |
77 | EV_ABS, ABS_MT_TRACKING_ID); | ||
78 | return 1; | 96 | return 1; |
79 | case HID_DG_TIPPRESSURE: | 97 | case HID_DG_TIPPRESSURE: |
98 | field->logical_minimum = 0; | ||
80 | hid_map_usage(hi, usage, bit, max, | 99 | hid_map_usage(hi, usage, bit, max, |
81 | EV_ABS, ABS_MT_PRESSURE); | 100 | EV_ABS, ABS_MT_PRESSURE); |
101 | set_abs(input, ABS_MT_PRESSURE, field, SN_PRESSURE); | ||
82 | /* touchscreen emulation */ | 102 | /* touchscreen emulation */ |
83 | input_set_abs_params(hi->input, ABS_PRESSURE, | 103 | set_abs(input, ABS_PRESSURE, field, SN_PRESSURE); |
84 | field->logical_minimum, | ||
85 | field->logical_maximum, 0, 0); | ||
86 | return 1; | 104 | return 1; |
87 | } | 105 | } |
88 | return 0; | 106 | return 0; |
@@ -96,10 +114,10 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
96 | struct hid_field *field, struct hid_usage *usage, | 114 | struct hid_field *field, struct hid_usage *usage, |
97 | unsigned long **bit, int *max) | 115 | unsigned long **bit, int *max) |
98 | { | 116 | { |
117 | /* tell hid-input to skip setup of these event types */ | ||
99 | if (usage->type == EV_KEY || usage->type == EV_ABS) | 118 | if (usage->type == EV_KEY || usage->type == EV_ABS) |
100 | clear_bit(usage->code, *bit); | 119 | set_bit(usage->type, hi->input->evbit); |
101 | 120 | return -1; | |
102 | return 0; | ||
103 | } | 121 | } |
104 | 122 | ||
105 | /* | 123 | /* |
@@ -108,58 +126,16 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
108 | */ | 126 | */ |
109 | static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) | 127 | static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) |
110 | { | 128 | { |
111 | td->first = !td->first; /* touchscreen emulation */ | 129 | input_mt_slot(input, td->slot); |
112 | 130 | input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch); | |
113 | if (td->valid) { | 131 | if (td->touch) { |
114 | /* emit multitouch events */ | 132 | input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); |
115 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); | 133 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); |
116 | input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3); | ||
117 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3); | ||
118 | input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z); | 134 | input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z); |
119 | |||
120 | input_mt_sync(input); | ||
121 | |||
122 | /* | ||
123 | * touchscreen emulation: store (x, y) as | ||
124 | * the last valid values in this frame | ||
125 | */ | ||
126 | td->lastx = td->x; | ||
127 | td->lasty = td->y; | ||
128 | td->lastz = td->z; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * touchscreen emulation: if this is the second finger and at least | ||
133 | * one in this frame is valid, the latest valid in the frame is | ||
134 | * the oldest on the panel, the one we want for single touch | ||
135 | */ | ||
136 | if (!td->first && td->activity) { | ||
137 | input_event(input, EV_ABS, ABS_X, td->lastx >> 3); | ||
138 | input_event(input, EV_ABS, ABS_Y, td->lasty >> 3); | ||
139 | input_event(input, EV_ABS, ABS_PRESSURE, td->lastz); | ||
140 | } | ||
141 | |||
142 | if (!td->valid) { | ||
143 | /* | ||
144 | * touchscreen emulation: if the first finger is invalid | ||
145 | * and there previously was finger activity, this is a release | ||
146 | */ | ||
147 | if (td->first && td->activity) { | ||
148 | input_event(input, EV_KEY, BTN_TOUCH, 0); | ||
149 | td->activity = false; | ||
150 | } | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | |||
155 | /* touchscreen emulation: if no previous activity, emit touch event */ | ||
156 | if (!td->activity) { | ||
157 | input_event(input, EV_KEY, BTN_TOUCH, 1); | ||
158 | td->activity = true; | ||
159 | } | 135 | } |
136 | input_mt_report_pointer_emulation(input, true); | ||
160 | } | 137 | } |
161 | 138 | ||
162 | |||
163 | static int egalax_event(struct hid_device *hid, struct hid_field *field, | 139 | static int egalax_event(struct hid_device *hid, struct hid_field *field, |
164 | struct hid_usage *usage, __s32 value) | 140 | struct hid_usage *usage, __s32 value) |
165 | { | 141 | { |
@@ -169,25 +145,26 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field, | |||
169 | * uses a standard parallel multitouch protocol (product ID == | 145 | * uses a standard parallel multitouch protocol (product ID == |
170 | * 48xx). The second is capacitive and uses an unusual "serial" | 146 | * 48xx). The second is capacitive and uses an unusual "serial" |
171 | * protocol with a different message for each multitouch finger | 147 | * protocol with a different message for each multitouch finger |
172 | * (product ID == 72xx). We do not yet generate a correct event | 148 | * (product ID == 72xx). |
173 | * sequence for the capacitive/serial protocol. | ||
174 | */ | 149 | */ |
175 | if (hid->claimed & HID_CLAIMED_INPUT) { | 150 | if (hid->claimed & HID_CLAIMED_INPUT) { |
176 | struct input_dev *input = field->hidinput->input; | 151 | struct input_dev *input = field->hidinput->input; |
177 | 152 | ||
178 | switch (usage->hid) { | 153 | switch (usage->hid) { |
179 | case HID_DG_INRANGE: | 154 | case HID_DG_INRANGE: |
155 | td->valid = value; | ||
156 | break; | ||
180 | case HID_DG_CONFIDENCE: | 157 | case HID_DG_CONFIDENCE: |
181 | /* avoid interference from generic hidinput handling */ | 158 | /* avoid interference from generic hidinput handling */ |
182 | break; | 159 | break; |
183 | case HID_DG_TIPSWITCH: | 160 | case HID_DG_TIPSWITCH: |
184 | td->valid = value; | 161 | td->touch = value; |
185 | break; | 162 | break; |
186 | case HID_DG_TIPPRESSURE: | 163 | case HID_DG_TIPPRESSURE: |
187 | td->z = value; | 164 | td->z = value; |
188 | break; | 165 | break; |
189 | case HID_DG_CONTACTID: | 166 | case HID_DG_CONTACTID: |
190 | td->id = value; | 167 | td->slot = clamp_val(value, 0, MAX_SLOTS - 1); |
191 | break; | 168 | break; |
192 | case HID_GD_X: | 169 | case HID_GD_X: |
193 | td->x = value; | 170 | td->x = value; |
@@ -195,11 +172,11 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field, | |||
195 | case HID_GD_Y: | 172 | case HID_GD_Y: |
196 | td->y = value; | 173 | td->y = value; |
197 | /* this is the last field in a finger */ | 174 | /* this is the last field in a finger */ |
198 | egalax_filter_event(td, input); | 175 | if (td->valid) |
176 | egalax_filter_event(td, input); | ||
199 | break; | 177 | break; |
200 | case HID_DG_CONTACTCOUNT: | 178 | case HID_DG_CONTACTCOUNT: |
201 | /* touch emulation: this is the last field in a frame */ | 179 | /* touch emulation: this is the last field in a frame */ |
202 | td->first = false; | ||
203 | break; | 180 | break; |
204 | 181 | ||
205 | default: | 182 | default: |
@@ -261,6 +238,12 @@ static const struct hid_device_id egalax_devices[] = { | |||
261 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, | 238 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, |
262 | { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | 239 | { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, |
263 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, | 240 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, |
241 | { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
242 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, | ||
243 | { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
244 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, | ||
245 | { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
246 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, | ||
264 | { } | 247 | { } |
265 | }; | 248 | }; |
266 | MODULE_DEVICE_TABLE(hid, egalax_devices); | 249 | MODULE_DEVICE_TABLE(hid, egalax_devices); |