2 * HID driver for 3M PCT multitouch panels
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.
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)
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>
24 MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
25 MODULE_DESCRIPTION("3M PCT multitouch panels");
26 MODULE_LICENSE("GPL");
32 /* estimated signal-to-noise ratios */
42 struct mmm_finger f
[MAX_SLOTS
];
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
)
52 int f1
= field
->logical_minimum
;
53 int f2
= field
->logical_maximum
;
56 switch (usage
->hid
& HID_USAGE_PAGE
) {
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);
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);
84 case HID_UP_DIGITIZER
:
86 /* we do not want to map these: no input-oriented meaning */
89 case HID_DG_INPUTMODE
:
90 case HID_DG_DEVICEINDEX
:
91 case HID_DG_CONTACTCOUNT
:
92 case HID_DG_CONTACTMAX
:
94 case HID_DG_CONFIDENCE
:
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
);
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);
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
,
115 case HID_DG_CONTACTID
:
116 input_mt_init_slots(hi
->input
, MAX_SLOTS
);
119 /* let hid-input decide for the others */
123 /* we do not want to map these: no input-oriented meaning */
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
)
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
);
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.
144 static void mmm_filter_event(struct mmm_data
*md
, struct input_dev
*input
)
147 for (i
= 0; i
< MAX_SLOTS
; ++i
) {
148 struct mmm_finger
*f
= &md
->f
[i
];
150 /* this finger is just placeholder data, ignore */
153 input_mt_slot(input
, i
);
154 input_mt_report_slot_state(input
, MT_TOOL_FINGER
, 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;
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
);
171 input_mt_report_pointer_emulation(input
, true);
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.
180 static int mmm_event(struct hid_device
*hid
, struct hid_field
*field
,
181 struct hid_usage
*usage
, __s32 value
)
183 struct mmm_data
*md
= hid_get_drvdata(hid
);
185 * strangely, this function can be called before
186 * field->hidinput is initialized!
188 if (hid
->claimed
& HID_CLAIMED_INPUT
) {
189 struct input_dev
*input
= field
->hidinput
->input
;
190 switch (usage
->hid
) {
191 case HID_DG_TIPSWITCH
:
194 case HID_DG_CONFIDENCE
:
199 md
->f
[md
->curid
].w
= value
;
203 md
->f
[md
->curid
].h
= value
;
205 case HID_DG_CONTACTID
:
206 value
= clamp_val(value
, 0, MAX_SLOTS
- 1);
209 md
->f
[value
].touch
= md
->touch
;
210 md
->f
[value
].valid
= 1;
216 md
->f
[md
->curid
].x
= value
;
220 md
->f
[md
->curid
].y
= value
;
222 case HID_DG_CONTACTCOUNT
:
225 if (md
->nreal
>= md
->nexp
) {
226 mmm_filter_event(md
, input
);
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
);
240 static int mmm_probe(struct hid_device
*hdev
, const struct hid_device_id
*id
)
245 hdev
->quirks
|= HID_QUIRK_NO_INPUT_SYNC
;
247 md
= kzalloc(sizeof(struct mmm_data
), GFP_KERNEL
);
249 hid_err(hdev
, "cannot allocate 3M data\n");
252 hid_set_drvdata(hdev
, md
);
254 ret
= hid_parse(hdev
);
256 ret
= hid_hw_start(hdev
, HID_CONNECT_DEFAULT
);
263 static void mmm_remove(struct hid_device
*hdev
)
266 kfree(hid_get_drvdata(hdev
));
267 hid_set_drvdata(hdev
, NULL
);
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
) },
275 MODULE_DEVICE_TABLE(hid
, mmm_devices
);
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}
282 static struct hid_driver mmm_driver
= {
284 .id_table
= mmm_devices
,
286 .remove
= mmm_remove
,
287 .input_mapping
= mmm_input_mapping
,
288 .input_mapped
= mmm_input_mapped
,
289 .usage_table
= mmm_grabbed_usages
,
293 static int __init
mmm_init(void)
295 return hid_register_driver(&mmm_driver
);
298 static void __exit
mmm_exit(void)
300 hid_unregister_driver(&mmm_driver
);
303 module_init(mmm_init
);
304 module_exit(mmm_exit
);