diff options
-rw-r--r-- | drivers/hid/Kconfig | 7 | ||||
-rw-r--r-- | drivers/hid/Makefile | 1 | ||||
-rw-r--r-- | drivers/hid/hid-3m-pct.c | 305 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 47 |
4 files changed, 46 insertions, 314 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 1edb0bd72a60..996ae3ac3244 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
@@ -55,12 +55,6 @@ source "drivers/hid/usbhid/Kconfig" | |||
55 | menu "Special HID drivers" | 55 | menu "Special HID drivers" |
56 | depends on HID | 56 | depends on HID |
57 | 57 | ||
58 | config HID_3M_PCT | ||
59 | tristate "3M PCT touchscreen" | ||
60 | depends on USB_HID | ||
61 | ---help--- | ||
62 | Support for 3M PCT touch screens. | ||
63 | |||
64 | config HID_A4TECH | 58 | config HID_A4TECH |
65 | tristate "A4 tech mice" if EXPERT | 59 | tristate "A4 tech mice" if EXPERT |
66 | depends on USB_HID | 60 | depends on USB_HID |
@@ -314,6 +308,7 @@ config HID_MULTITOUCH | |||
314 | Generic support for HID multitouch panels. | 308 | Generic support for HID multitouch panels. |
315 | 309 | ||
316 | Say Y here if you have one of the following devices: | 310 | Say Y here if you have one of the following devices: |
311 | - 3M PCT touch screens | ||
317 | - Cando dual touch panel | 312 | - Cando dual touch panel |
318 | - Cypress TrueTouch panels | 313 | - Cypress TrueTouch panels |
319 | - Hanvon dual touch panels | 314 | - Hanvon dual touch panels |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index f8b90e4e4841..11c9f0b127e1 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile | |||
@@ -25,7 +25,6 @@ ifdef CONFIG_LOGIWII_FF | |||
25 | hid-logitech-y += hid-lg4ff.o | 25 | hid-logitech-y += hid-lg4ff.o |
26 | endif | 26 | endif |
27 | 27 | ||
28 | obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o | ||
29 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o | 28 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o |
30 | obj-$(CONFIG_HID_ACRUX) += hid-axff.o | 29 | obj-$(CONFIG_HID_ACRUX) += hid-axff.o |
31 | obj-$(CONFIG_HID_APPLE) += hid-apple.o | 30 | obj-$(CONFIG_HID_APPLE) += hid-apple.o |
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c deleted file mode 100644 index 5243ae2d3730..000000000000 --- a/drivers/hid/hid-3m-pct.c +++ /dev/null | |||
@@ -1,305 +0,0 @@ | |||
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 | hid_err(hdev, "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 | |||
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index d31301e85c56..0175f8583095 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
@@ -11,6 +11,12 @@ | |||
11 | * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> | 11 | * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> |
12 | * Copyright (c) 2010 Canonical, Ltd. | 12 | * Copyright (c) 2010 Canonical, Ltd. |
13 | * | 13 | * |
14 | * This code is partly based on hid-3m-pct.c: | ||
15 | * | ||
16 | * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> | ||
17 | * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
18 | * Copyright (c) 2010 Canonical, Ltd. | ||
19 | * | ||
14 | */ | 20 | */ |
15 | 21 | ||
16 | /* | 22 | /* |
@@ -69,6 +75,8 @@ struct mt_class { | |||
69 | __s32 name; /* MT_CLS */ | 75 | __s32 name; /* MT_CLS */ |
70 | __s32 quirks; | 76 | __s32 quirks; |
71 | __s32 sn_move; /* Signal/noise ratio for move events */ | 77 | __s32 sn_move; /* Signal/noise ratio for move events */ |
78 | __s32 sn_width; /* Signal/noise ratio for width events */ | ||
79 | __s32 sn_height; /* Signal/noise ratio for height events */ | ||
72 | __s32 sn_pressure; /* Signal/noise ratio for pressure events */ | 80 | __s32 sn_pressure; /* Signal/noise ratio for pressure events */ |
73 | __u8 maxcontacts; | 81 | __u8 maxcontacts; |
74 | }; | 82 | }; |
@@ -80,6 +88,7 @@ struct mt_class { | |||
80 | #define MT_CLS_CYPRESS 4 | 88 | #define MT_CLS_CYPRESS 4 |
81 | #define MT_CLS_EGALAX 5 | 89 | #define MT_CLS_EGALAX 5 |
82 | #define MT_CLS_STANTUM 6 | 90 | #define MT_CLS_STANTUM 6 |
91 | #define MT_CLS_3M 7 | ||
83 | 92 | ||
84 | #define MT_DEFAULT_MAXCONTACT 10 | 93 | #define MT_DEFAULT_MAXCONTACT 10 |
85 | 94 | ||
@@ -141,6 +150,12 @@ struct mt_class mt_classes[] = { | |||
141 | }, | 150 | }, |
142 | { .name = MT_CLS_STANTUM, | 151 | { .name = MT_CLS_STANTUM, |
143 | .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, | 152 | .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, |
153 | { .name = MT_CLS_3M, | ||
154 | .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | | ||
155 | MT_QUIRK_SLOT_IS_CONTACTID, | ||
156 | .sn_move = 2048, | ||
157 | .sn_width = 128, | ||
158 | .sn_height = 128 }, | ||
144 | 159 | ||
145 | { } | 160 | { } |
146 | }; | 161 | }; |
@@ -230,11 +245,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
230 | case HID_DG_WIDTH: | 245 | case HID_DG_WIDTH: |
231 | hid_map_usage(hi, usage, bit, max, | 246 | hid_map_usage(hi, usage, bit, max, |
232 | EV_ABS, ABS_MT_TOUCH_MAJOR); | 247 | EV_ABS, ABS_MT_TOUCH_MAJOR); |
248 | set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, | ||
249 | cls->sn_width); | ||
233 | td->last_slot_field = usage->hid; | 250 | td->last_slot_field = usage->hid; |
234 | return 1; | 251 | return 1; |
235 | case HID_DG_HEIGHT: | 252 | case HID_DG_HEIGHT: |
236 | hid_map_usage(hi, usage, bit, max, | 253 | hid_map_usage(hi, usage, bit, max, |
237 | EV_ABS, ABS_MT_TOUCH_MINOR); | 254 | EV_ABS, ABS_MT_TOUCH_MINOR); |
255 | set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, | ||
256 | cls->sn_height); | ||
238 | input_set_abs_params(hi->input, | 257 | input_set_abs_params(hi->input, |
239 | ABS_MT_ORIENTATION, 0, 1, 0, 0); | 258 | ABS_MT_ORIENTATION, 0, 1, 0, 0); |
240 | td->last_slot_field = usage->hid; | 259 | td->last_slot_field = usage->hid; |
@@ -332,11 +351,18 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) | |||
332 | input_mt_report_slot_state(input, MT_TOOL_FINGER, | 351 | input_mt_report_slot_state(input, MT_TOOL_FINGER, |
333 | s->touch_state); | 352 | s->touch_state); |
334 | if (s->touch_state) { | 353 | if (s->touch_state) { |
354 | /* this finger is on the screen */ | ||
355 | int wide = (s->w > s->h); | ||
356 | /* divided by two to match visual scale of touch */ | ||
357 | int major = max(s->w, s->h) >> 1; | ||
358 | int minor = min(s->w, s->h) >> 1; | ||
359 | |||
335 | input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); | 360 | input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); |
336 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); | 361 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); |
362 | input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); | ||
337 | input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); | 363 | input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); |
338 | input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w); | 364 | input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); |
339 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h); | 365 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); |
340 | } | 366 | } |
341 | s->seen_in_this_frame = false; | 367 | s->seen_in_this_frame = false; |
342 | 368 | ||
@@ -398,6 +424,15 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, | |||
398 | break; | 424 | break; |
399 | 425 | ||
400 | default: | 426 | default: |
427 | if (td->last_field_index | ||
428 | && field->index == td->last_field_index) | ||
429 | /* we reach here when the last field in the | ||
430 | * report is not related to multitouch. | ||
431 | * This is not good. As a temporary solution, | ||
432 | * we trigger our mt event completion and | ||
433 | * ignore the field. | ||
434 | */ | ||
435 | break; | ||
401 | /* fallback to the generic hidinput handling */ | 436 | /* fallback to the generic hidinput handling */ |
402 | return 0; | 437 | return 0; |
403 | } | 438 | } |
@@ -513,6 +548,14 @@ static void mt_remove(struct hid_device *hdev) | |||
513 | 548 | ||
514 | static const struct hid_device_id mt_devices[] = { | 549 | static const struct hid_device_id mt_devices[] = { |
515 | 550 | ||
551 | /* 3M panels */ | ||
552 | { .driver_data = MT_CLS_3M, | ||
553 | HID_USB_DEVICE(USB_VENDOR_ID_3M, | ||
554 | USB_DEVICE_ID_3M1968) }, | ||
555 | { .driver_data = MT_CLS_3M, | ||
556 | HID_USB_DEVICE(USB_VENDOR_ID_3M, | ||
557 | USB_DEVICE_ID_3M2256) }, | ||
558 | |||
516 | /* Cando panels */ | 559 | /* Cando panels */ |
517 | { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, | 560 | { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, |
518 | HID_USB_DEVICE(USB_VENDOR_ID_CANDO, | 561 | HID_USB_DEVICE(USB_VENDOR_ID_CANDO, |