hid: egalax: Correct for device resolution report error
[linux-2.6.git] / drivers / hid / hid-3m-pct.c
1 /*
2  *  HID driver for 3M PCT multitouch panels
3  *
4  *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
5  *  Copyright (c) 2010      Henrik Rydberg <rydberg@euromail.se>
6  *  Copyright (c) 2010      Canonical, Ltd.
7  *
8  */
9
10 /*
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License as published by the Free
13  * Software Foundation; either version 2 of the License, or (at your option)
14  * any later version.
15  */
16
17 #include <linux/device.h>
18 #include <linux/hid.h>
19 #include <linux/module.h>
20 #include <linux/slab.h>
21 #include <linux/usb.h>
22 #include <linux/input/mt.h>
23
24 MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
25 MODULE_DESCRIPTION("3M PCT multitouch panels");
26 MODULE_LICENSE("GPL");
27
28 #include "hid-ids.h"
29
30 #define MAX_SLOTS               60
31
32 /* estimated signal-to-noise ratios */
33 #define SN_MOVE                 2048
34 #define SN_WIDTH                128
35
36 struct mmm_finger {
37         __s32 x, y, w, h;
38         bool touch, valid;
39 };
40
41 struct mmm_data {
42         struct mmm_finger f[MAX_SLOTS];
43         __u8 curid;
44         __u8 nexp, nreal;
45         bool touch, valid;
46 };
47
48 static int mmm_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         int f1 = field->logical_minimum;
53         int f2 = field->logical_maximum;
54         int df = f2 - f1;
55
56         switch (usage->hid & HID_USAGE_PAGE) {
57
58         case HID_UP_BUTTON:
59                 return -1;
60
61         case HID_UP_GENDESK:
62                 switch (usage->hid) {
63                 case HID_GD_X:
64                         hid_map_usage(hi, usage, bit, max,
65                                         EV_ABS, ABS_MT_POSITION_X);
66                         input_set_abs_params(hi->input, ABS_MT_POSITION_X,
67                                              f1, f2, df / SN_MOVE, 0);
68                         /* touchscreen emulation */
69                         input_set_abs_params(hi->input, ABS_X,
70                                              f1, f2, df / SN_MOVE, 0);
71                         return 1;
72                 case HID_GD_Y:
73                         hid_map_usage(hi, usage, bit, max,
74                                         EV_ABS, ABS_MT_POSITION_Y);
75                         input_set_abs_params(hi->input, ABS_MT_POSITION_Y,
76                                              f1, f2, df / SN_MOVE, 0);
77                         /* touchscreen emulation */
78                         input_set_abs_params(hi->input, ABS_Y,
79                                              f1, f2, df / SN_MOVE, 0);
80                         return 1;
81                 }
82                 return 0;
83
84         case HID_UP_DIGITIZER:
85                 switch (usage->hid) {
86                 /* we do not want to map these: no input-oriented meaning */
87                 case 0x14:
88                 case 0x23:
89                 case HID_DG_INPUTMODE:
90                 case HID_DG_DEVICEINDEX:
91                 case HID_DG_CONTACTCOUNT:
92                 case HID_DG_CONTACTMAX:
93                 case HID_DG_INRANGE:
94                 case HID_DG_CONFIDENCE:
95                         return -1;
96                 case HID_DG_TIPSWITCH:
97                         /* touchscreen emulation */
98                         hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
99                         input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
100                         return 1;
101                 case HID_DG_WIDTH:
102                         hid_map_usage(hi, usage, bit, max,
103                                         EV_ABS, ABS_MT_TOUCH_MAJOR);
104                         input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR,
105                                              f1, f2, df / SN_WIDTH, 0);
106                         return 1;
107                 case HID_DG_HEIGHT:
108                         hid_map_usage(hi, usage, bit, max,
109                                         EV_ABS, ABS_MT_TOUCH_MINOR);
110                         input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR,
111                                              f1, f2, df / SN_WIDTH, 0);
112                         input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
113                                         0, 1, 0, 0);
114                         return 1;
115                 case HID_DG_CONTACTID:
116                         input_mt_init_slots(hi->input, MAX_SLOTS);
117                         return 1;
118                 }
119                 /* let hid-input decide for the others */
120                 return 0;
121
122         case 0xff000000:
123                 /* we do not want to map these: no input-oriented meaning */
124                 return -1;
125         }
126
127         return 0;
128 }
129
130 static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
131                 struct hid_field *field, struct hid_usage *usage,
132                 unsigned long **bit, int *max)
133 {
134         /* tell hid-input to skip setup of these event types */
135         if (usage->type == EV_KEY || usage->type == EV_ABS)
136                 set_bit(usage->type, hi->input->evbit);
137         return -1;
138 }
139
140 /*
141  * this function is called when a whole packet has been received and processed,
142  * so that it can decide what to send to the input layer.
143  */
144 static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
145 {
146         int i;
147         for (i = 0; i < MAX_SLOTS; ++i) {
148                 struct mmm_finger *f = &md->f[i];
149                 if (!f->valid) {
150                         /* this finger is just placeholder data, ignore */
151                         continue;
152                 }
153                 input_mt_slot(input, i);
154                 input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch);
155                 if (f->touch) {
156                         /* this finger is on the screen */
157                         int wide = (f->w > f->h);
158                         /* divided by two to match visual scale of touch */
159                         int major = max(f->w, f->h) >> 1;
160                         int minor = min(f->w, f->h) >> 1;
161
162                         input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
163                         input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
164                         input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
165                         input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
166                         input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
167                 }
168                 f->valid = 0;
169         }
170
171         input_mt_report_pointer_emulation(input, true);
172         input_sync(input);
173 }
174
175 /*
176  * this function is called upon all reports
177  * so that we can accumulate contact point information,
178  * and call input_mt_sync after each point.
179  */
180 static int mmm_event(struct hid_device *hid, struct hid_field *field,
181                                 struct hid_usage *usage, __s32 value)
182 {
183         struct mmm_data *md = hid_get_drvdata(hid);
184         /*
185          * strangely, this function can be called before
186          * field->hidinput is initialized!
187          */
188         if (hid->claimed & HID_CLAIMED_INPUT) {
189                 struct input_dev *input = field->hidinput->input;
190                 switch (usage->hid) {
191                 case HID_DG_TIPSWITCH:
192                         md->touch = value;
193                         break;
194                 case HID_DG_CONFIDENCE:
195                         md->valid = value;
196                         break;
197                 case HID_DG_WIDTH:
198                         if (md->valid)
199                                 md->f[md->curid].w = value;
200                         break;
201                 case HID_DG_HEIGHT:
202                         if (md->valid)
203                                 md->f[md->curid].h = value;
204                         break;
205                 case HID_DG_CONTACTID:
206                         value = clamp_val(value, 0, MAX_SLOTS - 1);
207                         if (md->valid) {
208                                 md->curid = value;
209                                 md->f[value].touch = md->touch;
210                                 md->f[value].valid = 1;
211                                 md->nreal++;
212                         }
213                         break;
214                 case HID_GD_X:
215                         if (md->valid)
216                                 md->f[md->curid].x = value;
217                         break;
218                 case HID_GD_Y:
219                         if (md->valid)
220                                 md->f[md->curid].y = value;
221                         break;
222                 case HID_DG_CONTACTCOUNT:
223                         if (value)
224                                 md->nexp = value;
225                         if (md->nreal >= md->nexp) {
226                                 mmm_filter_event(md, input);
227                                 md->nreal = 0;
228                         }
229                         break;
230                 }
231         }
232
233         /* we have handled the hidinput part, now remains hiddev */
234         if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
235                 hid->hiddev_hid_event(hid, field, usage, value);
236
237         return 1;
238 }
239
240 static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
241 {
242         int ret;
243         struct mmm_data *md;
244
245         hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
246
247         md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
248         if (!md) {
249                 dev_err(&hdev->dev, "cannot allocate 3M data\n");
250                 return -ENOMEM;
251         }
252         hid_set_drvdata(hdev, md);
253
254         ret = hid_parse(hdev);
255         if (!ret)
256                 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
257
258         if (ret)
259                 kfree(md);
260         return ret;
261 }
262
263 static void mmm_remove(struct hid_device *hdev)
264 {
265         hid_hw_stop(hdev);
266         kfree(hid_get_drvdata(hdev));
267         hid_set_drvdata(hdev, NULL);
268 }
269
270 static const struct hid_device_id mmm_devices[] = {
271         { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
272         { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
273         { }
274 };
275 MODULE_DEVICE_TABLE(hid, mmm_devices);
276
277 static const struct hid_usage_id mmm_grabbed_usages[] = {
278         { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
279         { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
280 };
281
282 static struct hid_driver mmm_driver = {
283         .name = "3m-pct",
284         .id_table = mmm_devices,
285         .probe = mmm_probe,
286         .remove = mmm_remove,
287         .input_mapping = mmm_input_mapping,
288         .input_mapped = mmm_input_mapped,
289         .usage_table = mmm_grabbed_usages,
290         .event = mmm_event,
291 };
292
293 static int __init mmm_init(void)
294 {
295         return hid_register_driver(&mmm_driver);
296 }
297
298 static void __exit mmm_exit(void)
299 {
300         hid_unregister_driver(&mmm_driver);
301 }
302
303 module_init(mmm_init);
304 module_exit(mmm_exit);
305