HID: hidraw: fix window in hidraw_release
[linux-2.6.git] / drivers / hid / hid-cando.c
1 /*
2  *  HID driver for Cando dual-touch panels
3  *
4  *  Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
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 <chatty@enac.fr>");
21 MODULE_DESCRIPTION("Cando dual-touch panel");
22 MODULE_LICENSE("GPL");
23
24 #include "hid-ids.h"
25
26 struct cando_data {
27         __u16 x, y;
28         __u8 id;
29         __s8 oldest;            /* id of the oldest finger in previous frame */
30         bool valid;             /* valid finger data, or just placeholder? */
31         bool first;             /* is this the first finger in this frame? */
32         __s8 firstid;           /* id of the first finger in the frame */
33         __u16 firstx, firsty;   /* (x, y) of the first finger in the frame */
34 };
35
36 static int cando_input_mapping(struct hid_device *hdev, struct hid_input *hi,
37                 struct hid_field *field, struct hid_usage *usage,
38                 unsigned long **bit, int *max)
39 {
40         switch (usage->hid & HID_USAGE_PAGE) {
41
42         case HID_UP_GENDESK:
43                 switch (usage->hid) {
44                 case HID_GD_X:
45                         hid_map_usage(hi, usage, bit, max,
46                                         EV_ABS, ABS_MT_POSITION_X);
47                         /* touchscreen emulation */
48                         input_set_abs_params(hi->input, ABS_X,
49                                                 field->logical_minimum,
50                                                 field->logical_maximum, 0, 0);
51                         return 1;
52                 case HID_GD_Y:
53                         hid_map_usage(hi, usage, bit, max,
54                                         EV_ABS, ABS_MT_POSITION_Y);
55                         /* touchscreen emulation */
56                         input_set_abs_params(hi->input, ABS_Y,
57                                                 field->logical_minimum,
58                                                 field->logical_maximum, 0, 0);
59                         return 1;
60                 }
61                 return 0;
62
63         case HID_UP_DIGITIZER:
64                 switch (usage->hid) {
65                 case HID_DG_TIPSWITCH:
66                 case HID_DG_CONTACTMAX:
67                         return -1;
68                 case HID_DG_INRANGE:
69                         /* touchscreen emulation */
70                         hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
71                         return 1;
72                 case HID_DG_CONTACTID:
73                         hid_map_usage(hi, usage, bit, max,
74                                         EV_ABS, ABS_MT_TRACKING_ID);
75                         return 1;
76                 }
77                 return 0;
78         }
79
80         return 0;
81 }
82
83 static int cando_input_mapped(struct hid_device *hdev, struct hid_input *hi,
84                 struct hid_field *field, struct hid_usage *usage,
85                 unsigned long **bit, int *max)
86 {
87         if (usage->type == EV_KEY || usage->type == EV_ABS)
88                 clear_bit(usage->code, *bit);
89
90         return 0;
91 }
92
93 /*
94  * this function is called when a whole finger has been parsed,
95  * so that it can decide what to send to the input layer.
96  */
97 static void cando_filter_event(struct cando_data *td, struct input_dev *input)
98 {
99         td->first = !td->first; /* touchscreen emulation */
100
101         if (!td->valid) {
102                 /*
103                  * touchscreen emulation: if this is the second finger and
104                  * the first was valid, the first was the oldest; if the
105                  * first was not valid and there was a valid finger in the
106                  * previous frame, this is a release.
107                  */
108                 if (td->first) {
109                         td->firstid = -1;
110                 } else if (td->firstid >= 0) {
111                         input_event(input, EV_ABS, ABS_X, td->firstx);
112                         input_event(input, EV_ABS, ABS_Y, td->firsty);
113                         td->oldest = td->firstid;
114                 } else if (td->oldest >= 0) {
115                         input_event(input, EV_KEY, BTN_TOUCH, 0);
116                         td->oldest = -1;
117                 }
118
119                 return;
120         }
121         
122         input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
123         input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
124         input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
125
126         input_mt_sync(input);
127
128         /*
129          * touchscreen emulation: if there was no touching finger previously,
130          * emit touch event
131          */
132         if (td->oldest < 0) {
133                 input_event(input, EV_KEY, BTN_TOUCH, 1);
134                 td->oldest = td->id;
135         }
136
137         /*
138          * touchscreen emulation: if this is the first finger, wait for the
139          * second; the oldest is then the second if it was the oldest already
140          * or if there was no first, the first otherwise.
141          */
142         if (td->first) {
143                 td->firstx = td->x;
144                 td->firsty = td->y;
145                 td->firstid = td->id;
146         } else {
147                 int x, y, oldest;
148                 if (td->id == td->oldest || td->firstid < 0) {
149                         x = td->x;
150                         y = td->y;
151                         oldest = td->id;
152                 } else {
153                         x = td->firstx;
154                         y = td->firsty;
155                         oldest = td->firstid;
156                 }
157                 input_event(input, EV_ABS, ABS_X, x);
158                 input_event(input, EV_ABS, ABS_Y, y);
159                 td->oldest = oldest;
160         }
161 }
162
163
164 static int cando_event(struct hid_device *hid, struct hid_field *field,
165                                 struct hid_usage *usage, __s32 value)
166 {
167         struct cando_data *td = hid_get_drvdata(hid);
168
169         if (hid->claimed & HID_CLAIMED_INPUT) {
170                 struct input_dev *input = field->hidinput->input;
171
172                 switch (usage->hid) {
173                 case HID_DG_INRANGE:
174                         td->valid = value;
175                         break;
176                 case HID_DG_CONTACTID:
177                         td->id = value;
178                         break;
179                 case HID_GD_X:
180                         td->x = value;
181                         break;
182                 case HID_GD_Y:
183                         td->y = value;
184                         cando_filter_event(td, input);
185                         break;
186                 case HID_DG_TIPSWITCH:
187                         /* avoid interference from generic hidinput handling */
188                         break;
189
190                 default:
191                         /* fallback to the generic hidinput handling */
192                         return 0;
193                 }
194         }
195
196         /* we have handled the hidinput part, now remains hiddev */
197         if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
198                 hid->hiddev_hid_event(hid, field, usage, value);
199
200         return 1;
201 }
202
203 static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id)
204 {
205         int ret;
206         struct cando_data *td;
207
208         td = kmalloc(sizeof(struct cando_data), GFP_KERNEL);
209         if (!td) {
210                 dev_err(&hdev->dev, "cannot allocate Cando Touch data\n");
211                 return -ENOMEM;
212         }
213         hid_set_drvdata(hdev, td);
214         td->first = false;
215         td->oldest = -1;
216         td->valid = false;
217
218         ret = hid_parse(hdev);
219         if (!ret)
220                 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
221
222         if (ret)
223                 kfree(td);
224
225         return ret;
226 }
227
228 static void cando_remove(struct hid_device *hdev)
229 {
230         hid_hw_stop(hdev);
231         kfree(hid_get_drvdata(hdev));
232         hid_set_drvdata(hdev, NULL);
233 }
234
235 static const struct hid_device_id cando_devices[] = {
236         { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
237                         USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
238         { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
239                         USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
240         { }
241 };
242 MODULE_DEVICE_TABLE(hid, cando_devices);
243
244 static const struct hid_usage_id cando_grabbed_usages[] = {
245         { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
246         { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
247 };
248
249 static struct hid_driver cando_driver = {
250         .name = "cando-touch",
251         .id_table = cando_devices,
252         .probe = cando_probe,
253         .remove = cando_remove,
254         .input_mapping = cando_input_mapping,
255         .input_mapped = cando_input_mapped,
256         .usage_table = cando_grabbed_usages,
257         .event = cando_event,
258 };
259
260 static int __init cando_init(void)
261 {
262         return hid_register_driver(&cando_driver);
263 }
264
265 static void __exit cando_exit(void)
266 {
267         hid_unregister_driver(&cando_driver);
268 }
269
270 module_init(cando_init);
271 module_exit(cando_exit);
272