aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2010-12-06 08:04:21 -0500
committerHenrik Rydberg <rydberg@euromail.se>2010-12-16 04:43:53 -0500
commitf7bc8046b33b9fb2e61318f885cc5d94e0a6b805 (patch)
tree216caf0ba099b61bcc5f1d720c596a32c5ba7333 /drivers/hid
parent17c760687f1270af9bd798d938198caa7d5aa3eb (diff)
hid: egalax: Convert to MT slots
The firmware in the joojoo reports touches sequentially, one per report, which confuses the current driver. A further complication is the absense of any indication of a touch frame. This patch converts the driver to the MT slots protocol, and outputs one full touch frame per report. This way, proper handling for both firmwares is ensured. Tested-by: Philipp Merkel <mail@philmerk.de> Cc: Stephane Chatty <chatty@enac.fr> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-egalax.c86
1 files changed, 23 insertions, 63 deletions
diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c
index 66b2c5d919af..38fdaadacdd4 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,17 +28,17 @@ MODULE_LICENSE("GPL");
25 28
26#include "hid-ids.h" 29#include "hid-ids.h"
27 30
31#define MAX_SLOTS 2
32
28/* estimated signal-to-noise ratios */ 33/* estimated signal-to-noise ratios */
29#define SN_MOVE 4096 34#define SN_MOVE 4096
30#define SN_PRESSURE 32 35#define SN_PRESSURE 32
31 36
32struct egalax_data { 37struct egalax_data {
33 __u16 x, y, z; 38 int valid;
34 __u8 id; 39 int slot;
35 bool first; /* is this the first finger in the frame? */ 40 int touch;
36 bool valid; /* valid finger data, or just placeholder? */ 41 int x, y, z;
37 bool activity; /* at least one active finger previously? */
38 __u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */
39}; 42};
40 43
41static void set_abs(struct input_dev *input, unsigned int code, 44static void set_abs(struct input_dev *input, unsigned int code,
@@ -89,9 +92,7 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
89 case HID_DG_CONTACTMAX: 92 case HID_DG_CONTACTMAX:
90 return -1; 93 return -1;
91 case HID_DG_CONTACTID: 94 case HID_DG_CONTACTID:
92 hid_map_usage(hi, usage, bit, max, 95 input_mt_init_slots(input, MAX_SLOTS);
93 EV_ABS, ABS_MT_TRACKING_ID);
94 set_abs(input, ABS_MT_TRACKING_ID, field, 0);
95 return 1; 96 return 1;
96 case HID_DG_TIPPRESSURE: 97 case HID_DG_TIPPRESSURE:
97 field->logical_minimum = 0; 98 field->logical_minimum = 0;
@@ -125,58 +126,16 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
125 */ 126 */
126static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) 127static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
127{ 128{
128 td->first = !td->first; /* touchscreen emulation */ 129 input_mt_slot(input, td->slot);
129 130 input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch);
130 if (td->valid) { 131 if (td->touch) {
131 /* emit multitouch events */ 132 input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
132 input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); 133 input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
133 input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3);
134 input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3);
135 input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z); 134 input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);
136
137 input_mt_sync(input);
138
139 /*
140 * touchscreen emulation: store (x, y) as
141 * the last valid values in this frame
142 */
143 td->lastx = td->x;
144 td->lasty = td->y;
145 td->lastz = td->z;
146 }
147
148 /*
149 * touchscreen emulation: if this is the second finger and at least
150 * one in this frame is valid, the latest valid in the frame is
151 * the oldest on the panel, the one we want for single touch
152 */
153 if (!td->first && td->activity) {
154 input_event(input, EV_ABS, ABS_X, td->lastx >> 3);
155 input_event(input, EV_ABS, ABS_Y, td->lasty >> 3);
156 input_event(input, EV_ABS, ABS_PRESSURE, td->lastz);
157 }
158
159 if (!td->valid) {
160 /*
161 * touchscreen emulation: if the first finger is invalid
162 * and there previously was finger activity, this is a release
163 */
164 if (td->first && td->activity) {
165 input_event(input, EV_KEY, BTN_TOUCH, 0);
166 td->activity = false;
167 }
168 return;
169 }
170
171
172 /* touchscreen emulation: if no previous activity, emit touch event */
173 if (!td->activity) {
174 input_event(input, EV_KEY, BTN_TOUCH, 1);
175 td->activity = true;
176 } 135 }
136 input_mt_report_pointer_emulation(input, true);
177} 137}
178 138
179
180static int egalax_event(struct hid_device *hid, struct hid_field *field, 139static int egalax_event(struct hid_device *hid, struct hid_field *field,
181 struct hid_usage *usage, __s32 value) 140 struct hid_usage *usage, __s32 value)
182{ 141{
@@ -186,25 +145,26 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
186 * uses a standard parallel multitouch protocol (product ID == 145 * uses a standard parallel multitouch protocol (product ID ==
187 * 48xx). The second is capacitive and uses an unusual "serial" 146 * 48xx). The second is capacitive and uses an unusual "serial"
188 * protocol with a different message for each multitouch finger 147 * protocol with a different message for each multitouch finger
189 * (product ID == 72xx). We do not yet generate a correct event 148 * (product ID == 72xx).
190 * sequence for the capacitive/serial protocol.
191 */ 149 */
192 if (hid->claimed & HID_CLAIMED_INPUT) { 150 if (hid->claimed & HID_CLAIMED_INPUT) {
193 struct input_dev *input = field->hidinput->input; 151 struct input_dev *input = field->hidinput->input;
194 152
195 switch (usage->hid) { 153 switch (usage->hid) {
196 case HID_DG_INRANGE: 154 case HID_DG_INRANGE:
155 td->valid = value;
156 break;
197 case HID_DG_CONFIDENCE: 157 case HID_DG_CONFIDENCE:
198 /* avoid interference from generic hidinput handling */ 158 /* avoid interference from generic hidinput handling */
199 break; 159 break;
200 case HID_DG_TIPSWITCH: 160 case HID_DG_TIPSWITCH:
201 td->valid = value; 161 td->touch = value;
202 break; 162 break;
203 case HID_DG_TIPPRESSURE: 163 case HID_DG_TIPPRESSURE:
204 td->z = value; 164 td->z = value;
205 break; 165 break;
206 case HID_DG_CONTACTID: 166 case HID_DG_CONTACTID:
207 td->id = value; 167 td->slot = clamp_val(value, 0, MAX_SLOTS - 1);
208 break; 168 break;
209 case HID_GD_X: 169 case HID_GD_X:
210 td->x = value; 170 td->x = value;
@@ -212,11 +172,11 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
212 case HID_GD_Y: 172 case HID_GD_Y:
213 td->y = value; 173 td->y = value;
214 /* this is the last field in a finger */ 174 /* this is the last field in a finger */
215 egalax_filter_event(td, input); 175 if (td->valid)
176 egalax_filter_event(td, input);
216 break; 177 break;
217 case HID_DG_CONTACTCOUNT: 178 case HID_DG_CONTACTCOUNT:
218 /* touch emulation: this is the last field in a frame */ 179 /* touch emulation: this is the last field in a frame */
219 td->first = false;
220 break; 180 break;
221 181
222 default: 182 default: