aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-uclogic-core.c
diff options
context:
space:
mode:
authorNikolai Kondrashov <spbnick@gmail.com>2019-02-10 05:13:51 -0500
committerBenjamin Tissoires <benjamin.tissoires@redhat.com>2019-02-21 06:00:53 -0500
commit9614219e9310ef19e66719bf37f9f68919bac08e (patch)
treee658e86c165670b6dbc7e49f44ef460415721d3e /drivers/hid/hid-uclogic-core.c
parentff0c13d6d2edc9c4952c668f4503a51b5f101ab3 (diff)
HID: uclogic: Extract tablet parameter discovery into a module
Refactor and extract UC-Logic tablet initialization and parameter discovery into a module. For these tablets, the major part of parameter discovery cannot be separated from initialization so they have to be in the same module. Define explicitly and clearly what possible quirks the tablets may have to make the driver implementation easier and simpler. Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Diffstat (limited to 'drivers/hid/hid-uclogic-core.c')
-rw-r--r--drivers/hid/hid-uclogic-core.c428
1 files changed, 102 insertions, 326 deletions
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index 4042183ee9a3..72a3a43766cc 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -16,126 +16,48 @@
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/hid.h> 17#include <linux/hid.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/usb.h>
20#include "usbhid/usbhid.h" 19#include "usbhid/usbhid.h"
21#include "hid-uclogic-rdesc.h" 20#include "hid-uclogic-params.h"
22 21
23#include "hid-ids.h" 22#include "hid-ids.h"
24 23
25/* Parameter indices */
26enum uclogic_prm {
27 UCLOGIC_PRM_X_LM = 1,
28 UCLOGIC_PRM_Y_LM = 2,
29 UCLOGIC_PRM_PRESSURE_LM = 4,
30 UCLOGIC_PRM_RESOLUTION = 5,
31 UCLOGIC_PRM_NUM
32};
33
34/* Driver data */ 24/* Driver data */
35struct uclogic_drvdata { 25struct uclogic_drvdata {
36 __u8 *rdesc; 26 /* Interface parameters */
37 unsigned int rsize; 27 struct uclogic_params params;
38 bool invert_pen_inrange; 28 /* Pointer to the replacement report descriptor. NULL if none. */
39 bool ignore_pen_usage; 29 __u8 *desc_ptr;
40 bool has_virtual_pad_interface; 30 /*
31 * Size of the replacement report descriptor.
32 * Only valid if desc_ptr is not NULL
33 */
34 unsigned int desc_size;
41}; 35};
42 36
43static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, 37static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
44 unsigned int *rsize) 38 unsigned int *rsize)
45{ 39{
46 struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
47 __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
48 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); 40 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
49 41
50 if (drvdata->rdesc != NULL) { 42 if (drvdata->desc_ptr != NULL) {
51 rdesc = drvdata->rdesc; 43 rdesc = drvdata->desc_ptr;
52 *rsize = drvdata->rsize; 44 *rsize = drvdata->desc_size;
53 return rdesc;
54 }
55
56 switch (hdev->product) {
57 case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
58 if (*rsize == UCLOGIC_RDESC_PF1209_ORIG_SIZE) {
59 rdesc = uclogic_rdesc_pf1209_fixed_arr;
60 *rsize = uclogic_rdesc_pf1209_fixed_size;
61 }
62 break;
63 case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U:
64 if (*rsize == UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE) {
65 rdesc = uclogic_rdesc_wp4030u_fixed_arr;
66 *rsize = uclogic_rdesc_wp4030u_fixed_size;
67 }
68 break;
69 case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U:
70 if (*rsize == UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE) {
71 rdesc = uclogic_rdesc_wp5540u_fixed_arr;
72 *rsize = uclogic_rdesc_wp5540u_fixed_size;
73 }
74 break;
75 case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U:
76 if (*rsize == UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE) {
77 rdesc = uclogic_rdesc_wp8060u_fixed_arr;
78 *rsize = uclogic_rdesc_wp8060u_fixed_size;
79 }
80 break;
81 case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062:
82 if (*rsize == UCLOGIC_RDESC_WP1062_ORIG_SIZE) {
83 rdesc = uclogic_rdesc_wp1062_fixed_arr;
84 *rsize = uclogic_rdesc_wp1062_fixed_size;
85 }
86 break;
87 case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
88 switch (iface_num) {
89 case 0:
90 if (*rsize == UCLOGIC_RDESC_TWHL850_ORIG0_SIZE) {
91 rdesc = uclogic_rdesc_twhl850_fixed0_arr;
92 *rsize = uclogic_rdesc_twhl850_fixed0_size;
93 }
94 break;
95 case 1:
96 if (*rsize == UCLOGIC_RDESC_TWHL850_ORIG1_SIZE) {
97 rdesc = uclogic_rdesc_twhl850_fixed1_arr;
98 *rsize = uclogic_rdesc_twhl850_fixed1_size;
99 }
100 break;
101 case 2:
102 if (*rsize == UCLOGIC_RDESC_TWHL850_ORIG2_SIZE) {
103 rdesc = uclogic_rdesc_twhl850_fixed2_arr;
104 *rsize = uclogic_rdesc_twhl850_fixed2_size;
105 }
106 break;
107 }
108 break;
109 case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
110 switch (iface_num) {
111 case 0:
112 if (*rsize == UCLOGIC_RDESC_TWHA60_ORIG0_SIZE) {
113 rdesc = uclogic_rdesc_twha60_fixed0_arr;
114 *rsize = uclogic_rdesc_twha60_fixed0_size;
115 }
116 break;
117 case 1:
118 if (*rsize == UCLOGIC_RDESC_TWHA60_ORIG1_SIZE) {
119 rdesc = uclogic_rdesc_twha60_fixed1_arr;
120 *rsize = uclogic_rdesc_twha60_fixed1_size;
121 }
122 break;
123 }
124 break;
125 } 45 }
126
127 return rdesc; 46 return rdesc;
128} 47}
129 48
130static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi, 49static int uclogic_input_mapping(struct hid_device *hdev,
131 struct hid_field *field, struct hid_usage *usage, 50 struct hid_input *hi,
132 unsigned long **bit, int *max) 51 struct hid_field *field,
52 struct hid_usage *usage,
53 unsigned long **bit,
54 int *max)
133{ 55{
134 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); 56 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
57 struct uclogic_params *params = &drvdata->params;
135 58
136 /* discard the unused pen interface */ 59 /* discard the unused pen interface */
137 if ((drvdata->ignore_pen_usage) && 60 if (params->pen_unused && (field->application == HID_DG_PEN))
138 (field->application == HID_DG_PEN))
139 return -1; 61 return -1;
140 62
141 /* let hid-core decide what to do */ 63 /* let hid-core decide what to do */
@@ -189,160 +111,12 @@ static int uclogic_input_configured(struct hid_device *hdev,
189 return 0; 111 return 0;
190} 112}
191 113
192/**
193 * Enable fully-functional tablet mode and determine device parameters.
194 *
195 * @hdev: HID device
196 */
197static int uclogic_tablet_enable(struct hid_device *hdev)
198{
199 int rc;
200 struct usb_device *usb_dev = hid_to_usb_dev(hdev);
201 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
202 __le16 *buf = NULL;
203 size_t len;
204 s32 params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
205 s32 resolution;
206
207 /*
208 * Read string descriptor containing tablet parameters. The specific
209 * string descriptor and data were discovered by sniffing the Windows
210 * driver traffic.
211 * NOTE: This enables fully-functional tablet mode.
212 */
213 len = UCLOGIC_PRM_NUM * sizeof(*buf);
214 buf = kmalloc(len, GFP_KERNEL);
215 if (buf == NULL) {
216 rc = -ENOMEM;
217 goto cleanup;
218 }
219 rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
220 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
221 (USB_DT_STRING << 8) + 0x64,
222 0x0409, buf, len,
223 USB_CTRL_GET_TIMEOUT);
224 if (rc == -EPIPE) {
225 hid_err(hdev, "device parameters not found\n");
226 rc = -ENODEV;
227 goto cleanup;
228 } else if (rc < 0) {
229 hid_err(hdev, "failed to get device parameters: %d\n", rc);
230 rc = -ENODEV;
231 goto cleanup;
232 } else if (rc != len) {
233 hid_err(hdev, "invalid device parameters\n");
234 rc = -ENODEV;
235 goto cleanup;
236 }
237
238 /* Extract device parameters */
239 params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
240 le16_to_cpu(buf[UCLOGIC_PRM_X_LM]);
241 params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
242 le16_to_cpu(buf[UCLOGIC_PRM_Y_LM]);
243 params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
244 le16_to_cpu(buf[UCLOGIC_PRM_PRESSURE_LM]);
245 resolution = le16_to_cpu(buf[UCLOGIC_PRM_RESOLUTION]);
246 if (resolution == 0) {
247 params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
248 params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
249 } else {
250 params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
251 params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] *
252 1000 / resolution;
253 params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
254 params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] *
255 1000 / resolution;
256 }
257
258 /* Format fixed report descriptor */
259 drvdata->rdesc = uclogic_rdesc_template_apply(
260 uclogic_rdesc_pen_template_arr,
261 uclogic_rdesc_pen_template_size,
262 params, ARRAY_SIZE(params));
263 if (drvdata->rdesc == NULL) {
264 rc = -ENOMEM;
265 goto cleanup;
266 }
267 drvdata->rsize = uclogic_rdesc_pen_template_size;
268
269 rc = 0;
270
271cleanup:
272 kfree(buf);
273 return rc;
274}
275
276/**
277 * Enable actual button mode.
278 *
279 * @hdev: HID device
280 */
281static int uclogic_button_enable(struct hid_device *hdev)
282{
283 int rc;
284 struct usb_device *usb_dev = hid_to_usb_dev(hdev);
285 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
286 char *str_buf;
287 size_t str_len = 16;
288 unsigned char *rdesc;
289 size_t rdesc_len;
290
291 str_buf = kzalloc(str_len, GFP_KERNEL);
292 if (str_buf == NULL) {
293 rc = -ENOMEM;
294 goto cleanup;
295 }
296
297 /* Enable abstract keyboard mode */
298 rc = usb_string(usb_dev, 0x7b, str_buf, str_len);
299 if (rc == -EPIPE) {
300 hid_info(hdev, "button mode setting not found\n");
301 rc = 0;
302 goto cleanup;
303 } else if (rc < 0) {
304 hid_err(hdev, "failed to enable abstract keyboard\n");
305 goto cleanup;
306 } else if (strncmp(str_buf, "HK On", rc)) {
307 hid_info(hdev, "invalid answer when requesting buttons: '%s'\n",
308 str_buf);
309 rc = -EINVAL;
310 goto cleanup;
311 }
312
313 /* Re-allocate fixed report descriptor */
314 rdesc_len = drvdata->rsize + uclogic_rdesc_buttonpad_size;
315 rdesc = devm_kzalloc(&hdev->dev, rdesc_len, GFP_KERNEL);
316 if (!rdesc) {
317 rc = -ENOMEM;
318 goto cleanup;
319 }
320
321 memcpy(rdesc, drvdata->rdesc, drvdata->rsize);
322
323 /* Append the buttonpad descriptor */
324 memcpy(rdesc + drvdata->rsize, uclogic_rdesc_buttonpad_arr,
325 uclogic_rdesc_buttonpad_size);
326
327 /* clean up old rdesc and use the new one */
328 drvdata->rsize = rdesc_len;
329 devm_kfree(&hdev->dev, drvdata->rdesc);
330 drvdata->rdesc = rdesc;
331
332 rc = 0;
333
334cleanup:
335 kfree(str_buf);
336 return rc;
337}
338
339static int uclogic_probe(struct hid_device *hdev, 114static int uclogic_probe(struct hid_device *hdev,
340 const struct hid_device_id *id) 115 const struct hid_device_id *id)
341{ 116{
342 int rc; 117 int rc;
343 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 118 struct uclogic_drvdata *drvdata = NULL;
344 struct usb_device *udev = hid_to_usb_dev(hdev); 119 bool params_initialized = false;
345 struct uclogic_drvdata *drvdata;
346 120
347 /* 121 /*
348 * libinput requires the pad interface to be on a different node 122 * libinput requires the pad interface to be on a different node
@@ -352,104 +126,97 @@ static int uclogic_probe(struct hid_device *hdev,
352 126
353 /* Allocate and assign driver data */ 127 /* Allocate and assign driver data */
354 drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); 128 drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
355 if (drvdata == NULL) 129 if (drvdata == NULL) {
356 return -ENOMEM; 130 rc = -ENOMEM;
357 131 goto failure;
132 }
358 hid_set_drvdata(hdev, drvdata); 133 hid_set_drvdata(hdev, drvdata);
359 134
360 switch (id->product) { 135 /* Initialize the device and retrieve interface parameters */
361 case USB_DEVICE_ID_HUION_TABLET: 136 rc = uclogic_params_init(&drvdata->params, hdev);
362 case USB_DEVICE_ID_YIYNOVA_TABLET: 137 if (rc != 0) {
363 case USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81: 138 hid_err(hdev, "failed probing parameters: %d\n", rc);
364 case USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3: 139 goto failure;
365 case USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45: 140 }
366 /* If this is the pen interface */ 141 params_initialized = true;
367 if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { 142 hid_dbg(hdev, "parameters:\n" UCLOGIC_PARAMS_FMT_STR,
368 rc = uclogic_tablet_enable(hdev); 143 UCLOGIC_PARAMS_FMT_ARGS(&drvdata->params));
369 if (rc) { 144 if (drvdata->params.invalid) {
370 hid_err(hdev, "tablet enabling failed\n"); 145 hid_info(hdev, "interface is invalid, ignoring\n");
371 return rc; 146 rc = -ENODEV;
372 } 147 goto failure;
373 drvdata->invert_pen_inrange = true; 148 }
374
375 rc = uclogic_button_enable(hdev);
376 drvdata->has_virtual_pad_interface = !rc;
377 } else {
378 drvdata->ignore_pen_usage = true;
379 }
380 break;
381 case USB_DEVICE_ID_UGTIZER_TABLET_GP0610:
382 case USB_DEVICE_ID_UGEE_TABLET_EX07S:
383 /* If this is the pen interface */
384 if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
385 rc = uclogic_tablet_enable(hdev);
386 if (rc) {
387 hid_err(hdev, "tablet enabling failed\n");
388 return rc;
389 }
390 drvdata->invert_pen_inrange = true;
391 } else {
392 drvdata->ignore_pen_usage = true;
393 }
394 break;
395 case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
396 /*
397 * If it is the three-interface version, which is known to
398 * respond to initialization.
399 */
400 if (udev->config->desc.bNumInterfaces == 3) {
401 /* If it is the pen interface */
402 if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
403 rc = uclogic_tablet_enable(hdev);
404 if (rc) {
405 hid_err(hdev, "tablet enabling failed\n");
406 return rc;
407 }
408 drvdata->invert_pen_inrange = true;
409 149
410 rc = uclogic_button_enable(hdev); 150 /* Generate replacement report descriptor */
411 drvdata->has_virtual_pad_interface = !rc; 151 rc = uclogic_params_get_desc(&drvdata->params,
412 } else { 152 &drvdata->desc_ptr,
413 drvdata->ignore_pen_usage = true; 153 &drvdata->desc_size);
414 } 154 if (rc) {
415 } 155 hid_err(hdev,
416 break; 156 "failed generating replacement report descriptor: %d\n",
157 rc);
158 goto failure;
417 } 159 }
418 160
419 rc = hid_parse(hdev); 161 rc = hid_parse(hdev);
420 if (rc) { 162 if (rc) {
421 hid_err(hdev, "parse failed\n"); 163 hid_err(hdev, "parse failed\n");
422 return rc; 164 goto failure;
423 } 165 }
424 166
425 rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 167 rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
426 if (rc) { 168 if (rc) {
427 hid_err(hdev, "hw start failed\n"); 169 hid_err(hdev, "hw start failed\n");
428 return rc; 170 goto failure;
429 } 171 }
430 172
431 return 0; 173 return 0;
174failure:
175 /* Assume "remove" might not be called if "probe" failed */
176 if (params_initialized)
177 uclogic_params_cleanup(&drvdata->params);
178 return rc;
432} 179}
433 180
434static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report, 181static int uclogic_raw_event(struct hid_device *hdev,
435 u8 *data, int size) 182 struct hid_report *report,
183 u8 *data, int size)
436{ 184{
437 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); 185 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
186 struct uclogic_params *params = &drvdata->params;
438 187
439 if ((report->type == HID_INPUT_REPORT) && 188 /* Tweak pen reports, if necessary */
440 (report->id == UCLOGIC_RDESC_PEN_ID) && 189 if (!params->pen_unused &&
190 (report->type == HID_INPUT_REPORT) &&
191 (report->id == params->pen.id) &&
441 (size >= 2)) { 192 (size >= 2)) {
442 if (drvdata->has_virtual_pad_interface && (data[1] & 0x20)) 193 /* If it's the "virtual" frame controls report */
443 /* Change to virtual frame button report ID */ 194 if (params->frame.id != 0 &&
444 data[0] = 0xf7; 195 data[1] & params->pen_frame_flag) {
445 else if (drvdata->invert_pen_inrange) 196 /* Change to virtual frame controls report ID */
197 data[0] = params->frame.id;
198 return 0;
199 }
200 /* If in-range reports are inverted */
201 if (params->pen.inrange ==
202 UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
446 /* Invert the in-range bit */ 203 /* Invert the in-range bit */
447 data[1] ^= 0x40; 204 data[1] ^= 0x40;
205 }
448 } 206 }
449 207
450 return 0; 208 return 0;
451} 209}
452 210
211static void uclogic_remove(struct hid_device *hdev)
212{
213 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
214
215 hid_hw_stop(hdev);
216 kfree(drvdata->desc_ptr);
217 uclogic_params_cleanup(&drvdata->params);
218}
219
453static const struct hid_device_id uclogic_devices[] = { 220static const struct hid_device_id uclogic_devices[] = {
454 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 221 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
455 USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) }, 222 USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
@@ -465,14 +232,22 @@ static const struct hid_device_id uclogic_devices[] = {
465 USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, 232 USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
466 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, 233 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
467 USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, 234 USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
468 { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) }, 235 { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
469 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) }, 236 USB_DEVICE_ID_HUION_TABLET) },
470 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) }, 237 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
471 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81) }, 238 USB_DEVICE_ID_HUION_TABLET) },
472 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45) }, 239 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
473 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) }, 240 USB_DEVICE_ID_YIYNOVA_TABLET) },
474 { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) }, 241 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
475 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_EX07S) }, 242 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81) },
243 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
244 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45) },
245 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
246 USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
247 { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
248 USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
249 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
250 USB_DEVICE_ID_UGEE_TABLET_EX07S) },
476 { } 251 { }
477}; 252};
478MODULE_DEVICE_TABLE(hid, uclogic_devices); 253MODULE_DEVICE_TABLE(hid, uclogic_devices);
@@ -481,6 +256,7 @@ static struct hid_driver uclogic_driver = {
481 .name = "uclogic", 256 .name = "uclogic",
482 .id_table = uclogic_devices, 257 .id_table = uclogic_devices,
483 .probe = uclogic_probe, 258 .probe = uclogic_probe,
259 .remove = uclogic_remove,
484 .report_fixup = uclogic_report_fixup, 260 .report_fixup = uclogic_report_fixup,
485 .raw_event = uclogic_raw_event, 261 .raw_event = uclogic_raw_event,
486 .input_mapping = uclogic_input_mapping, 262 .input_mapping = uclogic_input_mapping,