aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-egalax.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2011-01-07 01:34:59 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-01-07 01:34:59 -0500
commit554738da71004d96e06fb75f4772dfc3b0f47810 (patch)
tree149a96ce3727025d3b9260961ec94ba8306db278 /drivers/hid/hid-egalax.c
parent7b4b30689d688d9ca2e5c3859db6bbe1c35e6014 (diff)
parenta6d38f889750ed6290728a19d9dad577b147c6d0 (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.c131
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
28struct egalax_data { 37struct 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
44static 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
37static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, 53static 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 */
109static 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)
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
163static int egalax_event(struct hid_device *hid, struct hid_field *field, 139static 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};
266MODULE_DEVICE_TABLE(hid, egalax_devices); 249MODULE_DEVICE_TABLE(hid, egalax_devices);