Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1/*
  2 *  HID driver for UC-Logic devices not fully compliant with HID standard
  3 *
  4 *  Copyright (c) 2010-2014 Nikolai Kondrashov
  5 *  Copyright (c) 2013 Martin Rusko
  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/usb.h>
 19#include <asm/unaligned.h>
 20#include "usbhid/usbhid.h"
 21
 22#include "hid-ids.h"
 23
 24/*
 25 * See WPXXXXU model descriptions, device and HID report descriptors at
 26 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP4030U
 27 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP5540U
 28 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP8060U
 29 */
 30
 31/* Size of the original descriptor of WPXXXXU tablets */
 32#define WPXXXXU_RDESC_ORIG_SIZE	212
 33
 34/* Fixed WP4030U report descriptor */
 35static __u8 wp4030u_rdesc_fixed[] = {
 36	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
 37	0x09, 0x02,         /*  Usage (Pen),                        */
 38	0xA1, 0x01,         /*  Collection (Application),           */
 39	0x85, 0x09,         /*      Report ID (9),                  */
 40	0x09, 0x20,         /*      Usage (Stylus),                 */
 41	0xA0,               /*      Collection (Physical),          */
 42	0x75, 0x01,         /*          Report Size (1),            */
 43	0x09, 0x42,         /*          Usage (Tip Switch),         */
 44	0x09, 0x44,         /*          Usage (Barrel Switch),      */
 45	0x09, 0x46,         /*          Usage (Tablet Pick),        */
 46	0x14,               /*          Logical Minimum (0),        */
 47	0x25, 0x01,         /*          Logical Maximum (1),        */
 48	0x95, 0x03,         /*          Report Count (3),           */
 49	0x81, 0x02,         /*          Input (Variable),           */
 50	0x95, 0x05,         /*          Report Count (5),           */
 51	0x81, 0x01,         /*          Input (Constant),           */
 52	0x75, 0x10,         /*          Report Size (16),           */
 53	0x95, 0x01,         /*          Report Count (1),           */
 54	0x14,               /*          Logical Minimum (0),        */
 55	0xA4,               /*          Push,                       */
 56	0x05, 0x01,         /*          Usage Page (Desktop),       */
 57	0x55, 0xFD,         /*          Unit Exponent (-3),         */
 58	0x65, 0x13,         /*          Unit (Inch),                */
 59	0x34,               /*          Physical Minimum (0),       */
 60	0x09, 0x30,         /*          Usage (X),                  */
 61	0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
 62	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
 63	0x81, 0x02,         /*          Input (Variable),           */
 64	0x09, 0x31,         /*          Usage (Y),                  */
 65	0x46, 0xB8, 0x0B,   /*          Physical Maximum (3000),    */
 66	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
 67	0x81, 0x02,         /*          Input (Variable),           */
 68	0xB4,               /*          Pop,                        */
 69	0x09, 0x30,         /*          Usage (Tip Pressure),       */
 70	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 71	0x81, 0x02,         /*          Input (Variable),           */
 72	0xC0,               /*      End Collection,                 */
 73	0xC0                /*  End Collection                      */
 74};
 75
 76/* Fixed WP5540U report descriptor */
 77static __u8 wp5540u_rdesc_fixed[] = {
 78	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
 79	0x09, 0x02,         /*  Usage (Pen),                        */
 80	0xA1, 0x01,         /*  Collection (Application),           */
 81	0x85, 0x09,         /*      Report ID (9),                  */
 82	0x09, 0x20,         /*      Usage (Stylus),                 */
 83	0xA0,               /*      Collection (Physical),          */
 84	0x75, 0x01,         /*          Report Size (1),            */
 85	0x09, 0x42,         /*          Usage (Tip Switch),         */
 86	0x09, 0x44,         /*          Usage (Barrel Switch),      */
 87	0x09, 0x46,         /*          Usage (Tablet Pick),        */
 88	0x14,               /*          Logical Minimum (0),        */
 89	0x25, 0x01,         /*          Logical Maximum (1),        */
 90	0x95, 0x03,         /*          Report Count (3),           */
 91	0x81, 0x02,         /*          Input (Variable),           */
 92	0x95, 0x05,         /*          Report Count (5),           */
 93	0x81, 0x01,         /*          Input (Constant),           */
 94	0x75, 0x10,         /*          Report Size (16),           */
 95	0x95, 0x01,         /*          Report Count (1),           */
 96	0x14,               /*          Logical Minimum (0),        */
 97	0xA4,               /*          Push,                       */
 98	0x05, 0x01,         /*          Usage Page (Desktop),       */
 99	0x55, 0xFD,         /*          Unit Exponent (-3),         */
100	0x65, 0x13,         /*          Unit (Inch),                */
101	0x34,               /*          Physical Minimum (0),       */
102	0x09, 0x30,         /*          Usage (X),                  */
103	0x46, 0x7C, 0x15,   /*          Physical Maximum (5500),    */
104	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
105	0x81, 0x02,         /*          Input (Variable),           */
106	0x09, 0x31,         /*          Usage (Y),                  */
107	0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
108	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
109	0x81, 0x02,         /*          Input (Variable),           */
110	0xB4,               /*          Pop,                        */
111	0x09, 0x30,         /*          Usage (Tip Pressure),       */
112	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
113	0x81, 0x02,         /*          Input (Variable),           */
114	0xC0,               /*      End Collection,                 */
115	0xC0,               /*  End Collection,                     */
116	0x05, 0x01,         /*  Usage Page (Desktop),               */
117	0x09, 0x02,         /*  Usage (Mouse),                      */
118	0xA1, 0x01,         /*  Collection (Application),           */
119	0x85, 0x08,         /*      Report ID (8),                  */
120	0x09, 0x01,         /*      Usage (Pointer),                */
121	0xA0,               /*      Collection (Physical),          */
122	0x75, 0x01,         /*          Report Size (1),            */
123	0x05, 0x09,         /*          Usage Page (Button),        */
124	0x19, 0x01,         /*          Usage Minimum (01h),        */
125	0x29, 0x03,         /*          Usage Maximum (03h),        */
126	0x14,               /*          Logical Minimum (0),        */
127	0x25, 0x01,         /*          Logical Maximum (1),        */
128	0x95, 0x03,         /*          Report Count (3),           */
129	0x81, 0x02,         /*          Input (Variable),           */
130	0x95, 0x05,         /*          Report Count (5),           */
131	0x81, 0x01,         /*          Input (Constant),           */
132	0x05, 0x01,         /*          Usage Page (Desktop),       */
133	0x75, 0x08,         /*          Report Size (8),            */
134	0x09, 0x30,         /*          Usage (X),                  */
135	0x09, 0x31,         /*          Usage (Y),                  */
136	0x15, 0x81,         /*          Logical Minimum (-127),     */
137	0x25, 0x7F,         /*          Logical Maximum (127),      */
138	0x95, 0x02,         /*          Report Count (2),           */
139	0x81, 0x06,         /*          Input (Variable, Relative), */
140	0x09, 0x38,         /*          Usage (Wheel),              */
141	0x15, 0xFF,         /*          Logical Minimum (-1),       */
142	0x25, 0x01,         /*          Logical Maximum (1),        */
143	0x95, 0x01,         /*          Report Count (1),           */
144	0x81, 0x06,         /*          Input (Variable, Relative), */
145	0x81, 0x01,         /*          Input (Constant),           */
146	0xC0,               /*      End Collection,                 */
147	0xC0                /*  End Collection                      */
148};
149
150/* Fixed WP8060U report descriptor */
151static __u8 wp8060u_rdesc_fixed[] = {
152	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
153	0x09, 0x02,         /*  Usage (Pen),                        */
154	0xA1, 0x01,         /*  Collection (Application),           */
155	0x85, 0x09,         /*      Report ID (9),                  */
156	0x09, 0x20,         /*      Usage (Stylus),                 */
157	0xA0,               /*      Collection (Physical),          */
158	0x75, 0x01,         /*          Report Size (1),            */
159	0x09, 0x42,         /*          Usage (Tip Switch),         */
160	0x09, 0x44,         /*          Usage (Barrel Switch),      */
161	0x09, 0x46,         /*          Usage (Tablet Pick),        */
162	0x14,               /*          Logical Minimum (0),        */
163	0x25, 0x01,         /*          Logical Maximum (1),        */
164	0x95, 0x03,         /*          Report Count (3),           */
165	0x81, 0x02,         /*          Input (Variable),           */
166	0x95, 0x05,         /*          Report Count (5),           */
167	0x81, 0x01,         /*          Input (Constant),           */
168	0x75, 0x10,         /*          Report Size (16),           */
169	0x95, 0x01,         /*          Report Count (1),           */
170	0x14,               /*          Logical Minimum (0),        */
171	0xA4,               /*          Push,                       */
172	0x05, 0x01,         /*          Usage Page (Desktop),       */
173	0x55, 0xFD,         /*          Unit Exponent (-3),         */
174	0x65, 0x13,         /*          Unit (Inch),                */
175	0x34,               /*          Physical Minimum (0),       */
176	0x09, 0x30,         /*          Usage (X),                  */
177	0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
178	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
179	0x81, 0x02,         /*          Input (Variable),           */
180	0x09, 0x31,         /*          Usage (Y),                  */
181	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
182	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
183	0x81, 0x02,         /*          Input (Variable),           */
184	0xB4,               /*          Pop,                        */
185	0x09, 0x30,         /*          Usage (Tip Pressure),       */
186	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
187	0x81, 0x02,         /*          Input (Variable),           */
188	0xC0,               /*      End Collection,                 */
189	0xC0,               /*  End Collection,                     */
190	0x05, 0x01,         /*  Usage Page (Desktop),               */
191	0x09, 0x02,         /*  Usage (Mouse),                      */
192	0xA1, 0x01,         /*  Collection (Application),           */
193	0x85, 0x08,         /*      Report ID (8),                  */
194	0x09, 0x01,         /*      Usage (Pointer),                */
195	0xA0,               /*      Collection (Physical),          */
196	0x75, 0x01,         /*          Report Size (1),            */
197	0x05, 0x09,         /*          Usage Page (Button),        */
198	0x19, 0x01,         /*          Usage Minimum (01h),        */
199	0x29, 0x03,         /*          Usage Maximum (03h),        */
200	0x14,               /*          Logical Minimum (0),        */
201	0x25, 0x01,         /*          Logical Maximum (1),        */
202	0x95, 0x03,         /*          Report Count (3),           */
203	0x81, 0x02,         /*          Input (Variable),           */
204	0x95, 0x05,         /*          Report Count (5),           */
205	0x81, 0x01,         /*          Input (Constant),           */
206	0x05, 0x01,         /*          Usage Page (Desktop),       */
207	0x75, 0x08,         /*          Report Size (8),            */
208	0x09, 0x30,         /*          Usage (X),                  */
209	0x09, 0x31,         /*          Usage (Y),                  */
210	0x15, 0x81,         /*          Logical Minimum (-127),     */
211	0x25, 0x7F,         /*          Logical Maximum (127),      */
212	0x95, 0x02,         /*          Report Count (2),           */
213	0x81, 0x06,         /*          Input (Variable, Relative), */
214	0x09, 0x38,         /*          Usage (Wheel),              */
215	0x15, 0xFF,         /*          Logical Minimum (-1),       */
216	0x25, 0x01,         /*          Logical Maximum (1),        */
217	0x95, 0x01,         /*          Report Count (1),           */
218	0x81, 0x06,         /*          Input (Variable, Relative), */
219	0x81, 0x01,         /*          Input (Constant),           */
220	0xC0,               /*      End Collection,                 */
221	0xC0                /*  End Collection                      */
222};
223
224/*
225 * See WP1062 description, device and HID report descriptors at
226 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP1062
227 */
228
229/* Size of the original descriptor of WP1062 tablet */
230#define WP1062_RDESC_ORIG_SIZE	254
231
232/* Fixed WP1062 report descriptor */
233static __u8 wp1062_rdesc_fixed[] = {
234	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
235	0x09, 0x02,         /*  Usage (Pen),                        */
236	0xA1, 0x01,         /*  Collection (Application),           */
237	0x85, 0x09,         /*      Report ID (9),                  */
238	0x09, 0x20,         /*      Usage (Stylus),                 */
239	0xA0,               /*      Collection (Physical),          */
240	0x75, 0x01,         /*          Report Size (1),            */
241	0x09, 0x42,         /*          Usage (Tip Switch),         */
242	0x09, 0x44,         /*          Usage (Barrel Switch),      */
243	0x09, 0x46,         /*          Usage (Tablet Pick),        */
244	0x14,               /*          Logical Minimum (0),        */
245	0x25, 0x01,         /*          Logical Maximum (1),        */
246	0x95, 0x03,         /*          Report Count (3),           */
247	0x81, 0x02,         /*          Input (Variable),           */
248	0x95, 0x04,         /*          Report Count (4),           */
249	0x81, 0x01,         /*          Input (Constant),           */
250	0x09, 0x32,         /*          Usage (In Range),           */
251	0x95, 0x01,         /*          Report Count (1),           */
252	0x81, 0x02,         /*          Input (Variable),           */
253	0x75, 0x10,         /*          Report Size (16),           */
254	0x95, 0x01,         /*          Report Count (1),           */
255	0x14,               /*          Logical Minimum (0),        */
256	0xA4,               /*          Push,                       */
257	0x05, 0x01,         /*          Usage Page (Desktop),       */
258	0x55, 0xFD,         /*          Unit Exponent (-3),         */
259	0x65, 0x13,         /*          Unit (Inch),                */
260	0x34,               /*          Physical Minimum (0),       */
261	0x09, 0x30,         /*          Usage (X),                  */
262	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
263	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
264	0x81, 0x02,         /*          Input (Variable),           */
265	0x09, 0x31,         /*          Usage (Y),                  */
266	0x46, 0xB7, 0x19,   /*          Physical Maximum (6583),    */
267	0x26, 0x6E, 0x33,   /*          Logical Maximum (13166),    */
268	0x81, 0x02,         /*          Input (Variable),           */
269	0xB4,               /*          Pop,                        */
270	0x09, 0x30,         /*          Usage (Tip Pressure),       */
271	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
272	0x81, 0x02,         /*          Input (Variable),           */
273	0xC0,               /*      End Collection,                 */
274	0xC0                /*  End Collection                      */
275};
276
277/*
278 * See PF1209 description, device and HID report descriptors at
279 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_PF1209
280 */
281
282/* Size of the original descriptor of PF1209 tablet */
283#define PF1209_RDESC_ORIG_SIZE	234
284
285/* Fixed PF1209 report descriptor */
286static __u8 pf1209_rdesc_fixed[] = {
287	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
288	0x09, 0x02,         /*  Usage (Pen),                        */
289	0xA1, 0x01,         /*  Collection (Application),           */
290	0x85, 0x09,         /*      Report ID (9),                  */
291	0x09, 0x20,         /*      Usage (Stylus),                 */
292	0xA0,               /*      Collection (Physical),          */
293	0x75, 0x01,         /*          Report Size (1),            */
294	0x09, 0x42,         /*          Usage (Tip Switch),         */
295	0x09, 0x44,         /*          Usage (Barrel Switch),      */
296	0x09, 0x46,         /*          Usage (Tablet Pick),        */
297	0x14,               /*          Logical Minimum (0),        */
298	0x25, 0x01,         /*          Logical Maximum (1),        */
299	0x95, 0x03,         /*          Report Count (3),           */
300	0x81, 0x02,         /*          Input (Variable),           */
301	0x95, 0x05,         /*          Report Count (5),           */
302	0x81, 0x01,         /*          Input (Constant),           */
303	0x75, 0x10,         /*          Report Size (16),           */
304	0x95, 0x01,         /*          Report Count (1),           */
305	0x14,               /*          Logical Minimum (0),        */
306	0xA4,               /*          Push,                       */
307	0x05, 0x01,         /*          Usage Page (Desktop),       */
308	0x55, 0xFD,         /*          Unit Exponent (-3),         */
309	0x65, 0x13,         /*          Unit (Inch),                */
310	0x34,               /*          Physical Minimum (0),       */
311	0x09, 0x30,         /*          Usage (X),                  */
312	0x46, 0xE0, 0x2E,   /*          Physical Maximum (12000),   */
313	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
314	0x81, 0x02,         /*          Input (Variable),           */
315	0x09, 0x31,         /*          Usage (Y),                  */
316	0x46, 0x28, 0x23,   /*          Physical Maximum (9000),    */
317	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
318	0x81, 0x02,         /*          Input (Variable),           */
319	0xB4,               /*          Pop,                        */
320	0x09, 0x30,         /*          Usage (Tip Pressure),       */
321	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
322	0x81, 0x02,         /*          Input (Variable),           */
323	0xC0,               /*      End Collection,                 */
324	0xC0,               /*  End Collection,                     */
325	0x05, 0x01,         /*  Usage Page (Desktop),               */
326	0x09, 0x02,         /*  Usage (Mouse),                      */
327	0xA1, 0x01,         /*  Collection (Application),           */
328	0x85, 0x08,         /*      Report ID (8),                  */
329	0x09, 0x01,         /*      Usage (Pointer),                */
330	0xA0,               /*      Collection (Physical),          */
331	0x75, 0x01,         /*          Report Size (1),            */
332	0x05, 0x09,         /*          Usage Page (Button),        */
333	0x19, 0x01,         /*          Usage Minimum (01h),        */
334	0x29, 0x03,         /*          Usage Maximum (03h),        */
335	0x14,               /*          Logical Minimum (0),        */
336	0x25, 0x01,         /*          Logical Maximum (1),        */
337	0x95, 0x03,         /*          Report Count (3),           */
338	0x81, 0x02,         /*          Input (Variable),           */
339	0x95, 0x05,         /*          Report Count (5),           */
340	0x81, 0x01,         /*          Input (Constant),           */
341	0x05, 0x01,         /*          Usage Page (Desktop),       */
342	0x75, 0x08,         /*          Report Size (8),            */
343	0x09, 0x30,         /*          Usage (X),                  */
344	0x09, 0x31,         /*          Usage (Y),                  */
345	0x15, 0x81,         /*          Logical Minimum (-127),     */
346	0x25, 0x7F,         /*          Logical Maximum (127),      */
347	0x95, 0x02,         /*          Report Count (2),           */
348	0x81, 0x06,         /*          Input (Variable, Relative), */
349	0x09, 0x38,         /*          Usage (Wheel),              */
350	0x15, 0xFF,         /*          Logical Minimum (-1),       */
351	0x25, 0x01,         /*          Logical Maximum (1),        */
352	0x95, 0x01,         /*          Report Count (1),           */
353	0x81, 0x06,         /*          Input (Variable, Relative), */
354	0x81, 0x01,         /*          Input (Constant),           */
355	0xC0,               /*      End Collection,                 */
356	0xC0                /*  End Collection                      */
357};
358
359/*
360 * See TWHL850 description, device and HID report descriptors at
361 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
362 */
363
364/* Size of the original descriptors of TWHL850 tablet */
365#define TWHL850_RDESC_ORIG_SIZE0	182
366#define TWHL850_RDESC_ORIG_SIZE1	161
367#define TWHL850_RDESC_ORIG_SIZE2	92
368
369/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
370static __u8 twhl850_rdesc_fixed0[] = {
371	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
372	0x09, 0x02,         /*  Usage (Pen),                        */
373	0xA1, 0x01,         /*  Collection (Application),           */
374	0x85, 0x09,         /*      Report ID (9),                  */
375	0x09, 0x20,         /*      Usage (Stylus),                 */
376	0xA0,               /*      Collection (Physical),          */
377	0x14,               /*          Logical Minimum (0),        */
378	0x25, 0x01,         /*          Logical Maximum (1),        */
379	0x75, 0x01,         /*          Report Size (1),            */
380	0x95, 0x03,         /*          Report Count (3),           */
381	0x09, 0x42,         /*          Usage (Tip Switch),         */
382	0x09, 0x44,         /*          Usage (Barrel Switch),      */
383	0x09, 0x46,         /*          Usage (Tablet Pick),        */
384	0x81, 0x02,         /*          Input (Variable),           */
385	0x81, 0x03,         /*          Input (Constant, Variable), */
386	0x95, 0x01,         /*          Report Count (1),           */
387	0x09, 0x32,         /*          Usage (In Range),           */
388	0x81, 0x02,         /*          Input (Variable),           */
389	0x81, 0x03,         /*          Input (Constant, Variable), */
390	0x75, 0x10,         /*          Report Size (16),           */
391	0xA4,               /*          Push,                       */
392	0x05, 0x01,         /*          Usage Page (Desktop),       */
393	0x65, 0x13,         /*          Unit (Inch),                */
394	0x55, 0xFD,         /*          Unit Exponent (-3),         */
395	0x34,               /*          Physical Minimum (0),       */
396	0x09, 0x30,         /*          Usage (X),                  */
397	0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
398	0x26, 0x00, 0x7D,   /*          Logical Maximum (32000),    */
399	0x81, 0x02,         /*          Input (Variable),           */
400	0x09, 0x31,         /*          Usage (Y),                  */
401	0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
402	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
403	0x81, 0x02,         /*          Input (Variable),           */
404	0xB4,               /*          Pop,                        */
405	0x09, 0x30,         /*          Usage (Tip Pressure),       */
406	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
407	0x81, 0x02,         /*          Input (Variable),           */
408	0xC0,               /*      End Collection,                 */
409	0xC0                /*  End Collection                      */
410};
411
412/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
413static __u8 twhl850_rdesc_fixed1[] = {
414	0x05, 0x01,         /*  Usage Page (Desktop),               */
415	0x09, 0x02,         /*  Usage (Mouse),                      */
416	0xA1, 0x01,         /*  Collection (Application),           */
417	0x85, 0x01,         /*      Report ID (1),                  */
418	0x09, 0x01,         /*      Usage (Pointer),                */
419	0xA0,               /*      Collection (Physical),          */
420	0x05, 0x09,         /*          Usage Page (Button),        */
421	0x75, 0x01,         /*          Report Size (1),            */
422	0x95, 0x03,         /*          Report Count (3),           */
423	0x19, 0x01,         /*          Usage Minimum (01h),        */
424	0x29, 0x03,         /*          Usage Maximum (03h),        */
425	0x14,               /*          Logical Minimum (0),        */
426	0x25, 0x01,         /*          Logical Maximum (1),        */
427	0x81, 0x02,         /*          Input (Variable),           */
428	0x95, 0x05,         /*          Report Count (5),           */
429	0x81, 0x03,         /*          Input (Constant, Variable), */
430	0x05, 0x01,         /*          Usage Page (Desktop),       */
431	0x09, 0x30,         /*          Usage (X),                  */
432	0x09, 0x31,         /*          Usage (Y),                  */
433	0x16, 0x00, 0x80,   /*          Logical Minimum (-32768),   */
434	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
435	0x75, 0x10,         /*          Report Size (16),           */
436	0x95, 0x02,         /*          Report Count (2),           */
437	0x81, 0x06,         /*          Input (Variable, Relative), */
438	0x09, 0x38,         /*          Usage (Wheel),              */
439	0x15, 0xFF,         /*          Logical Minimum (-1),       */
440	0x25, 0x01,         /*          Logical Maximum (1),        */
441	0x95, 0x01,         /*          Report Count (1),           */
442	0x75, 0x08,         /*          Report Size (8),            */
443	0x81, 0x06,         /*          Input (Variable, Relative), */
444	0x81, 0x03,         /*          Input (Constant, Variable), */
445	0xC0,               /*      End Collection,                 */
446	0xC0                /*  End Collection                      */
447};
448
449/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
450static __u8 twhl850_rdesc_fixed2[] = {
451	0x05, 0x01,         /*  Usage Page (Desktop),               */
452	0x09, 0x06,         /*  Usage (Keyboard),                   */
453	0xA1, 0x01,         /*  Collection (Application),           */
454	0x85, 0x03,         /*      Report ID (3),                  */
455	0x05, 0x07,         /*      Usage Page (Keyboard),          */
456	0x14,               /*      Logical Minimum (0),            */
457	0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
458	0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
459	0x25, 0x01,         /*      Logical Maximum (1),            */
460	0x75, 0x01,         /*      Report Size (1),                */
461	0x95, 0x08,         /*      Report Count (8),               */
462	0x81, 0x02,         /*      Input (Variable),               */
463	0x18,               /*      Usage Minimum (None),           */
464	0x29, 0xFF,         /*      Usage Maximum (FFh),            */
465	0x26, 0xFF, 0x00,   /*      Logical Maximum (255),          */
466	0x75, 0x08,         /*      Report Size (8),                */
467	0x95, 0x06,         /*      Report Count (6),               */
468	0x80,               /*      Input,                          */
469	0xC0                /*  End Collection                      */
470};
471
472/*
473 * See TWHA60 description, device and HID report descriptors at
474 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_TWHA60
475 */
476
477/* Size of the original descriptors of TWHA60 tablet */
478#define TWHA60_RDESC_ORIG_SIZE0 254
479#define TWHA60_RDESC_ORIG_SIZE1 139
480
481/* Fixed TWHA60 report descriptor, interface 0 (stylus) */
482static __u8 twha60_rdesc_fixed0[] = {
483	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
484	0x09, 0x02,         /*  Usage (Pen),                        */
485	0xA1, 0x01,         /*  Collection (Application),           */
486	0x85, 0x09,         /*      Report ID (9),                  */
487	0x09, 0x20,         /*      Usage (Stylus),                 */
488	0xA0,               /*      Collection (Physical),          */
489	0x75, 0x01,         /*          Report Size (1),            */
490	0x09, 0x42,         /*          Usage (Tip Switch),         */
491	0x09, 0x44,         /*          Usage (Barrel Switch),      */
492	0x09, 0x46,         /*          Usage (Tablet Pick),        */
493	0x14,               /*          Logical Minimum (0),        */
494	0x25, 0x01,         /*          Logical Maximum (1),        */
495	0x95, 0x03,         /*          Report Count (3),           */
496	0x81, 0x02,         /*          Input (Variable),           */
497	0x95, 0x04,         /*          Report Count (4),           */
498	0x81, 0x01,         /*          Input (Constant),           */
499	0x09, 0x32,         /*          Usage (In Range),           */
500	0x95, 0x01,         /*          Report Count (1),           */
501	0x81, 0x02,         /*          Input (Variable),           */
502	0x75, 0x10,         /*          Report Size (16),           */
503	0x95, 0x01,         /*          Report Count (1),           */
504	0x14,               /*          Logical Minimum (0),        */
505	0xA4,               /*          Push,                       */
506	0x05, 0x01,         /*          Usage Page (Desktop),       */
507	0x55, 0xFD,         /*          Unit Exponent (-3),         */
508	0x65, 0x13,         /*          Unit (Inch),                */
509	0x34,               /*          Physical Minimum (0),       */
510	0x09, 0x30,         /*          Usage (X),                  */
511	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
512	0x27, 0x3F, 0x9C,
513		0x00, 0x00, /*          Logical Maximum (39999),    */
514	0x81, 0x02,         /*          Input (Variable),           */
515	0x09, 0x31,         /*          Usage (Y),                  */
516	0x46, 0x6A, 0x18,   /*          Physical Maximum (6250),    */
517	0x26, 0xA7, 0x61,   /*          Logical Maximum (24999),    */
518	0x81, 0x02,         /*          Input (Variable),           */
519	0xB4,               /*          Pop,                        */
520	0x09, 0x30,         /*          Usage (Tip Pressure),       */
521	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
522	0x81, 0x02,         /*          Input (Variable),           */
523	0xC0,               /*      End Collection,                 */
524	0xC0                /*  End Collection                      */
525};
526
527/* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */
528static __u8 twha60_rdesc_fixed1[] = {
529	0x05, 0x01, /*  Usage Page (Desktop),       */
530	0x09, 0x06, /*  Usage (Keyboard),           */
531	0xA1, 0x01, /*  Collection (Application),   */
532	0x85, 0x05, /*      Report ID (5),          */
533	0x05, 0x07, /*      Usage Page (Keyboard),  */
534	0x14,       /*      Logical Minimum (0),    */
535	0x25, 0x01, /*      Logical Maximum (1),    */
536	0x75, 0x01, /*      Report Size (1),        */
537	0x95, 0x08, /*      Report Count (8),       */
538	0x81, 0x01, /*      Input (Constant),       */
539	0x95, 0x0C, /*      Report Count (12),      */
540	0x19, 0x3A, /*      Usage Minimum (KB F1),  */
541	0x29, 0x45, /*      Usage Maximum (KB F12), */
542	0x81, 0x02, /*      Input (Variable),       */
543	0x95, 0x0C, /*      Report Count (12),      */
544	0x19, 0x68, /*      Usage Minimum (KB F13), */
545	0x29, 0x73, /*      Usage Maximum (KB F24), */
546	0x81, 0x02, /*      Input (Variable),       */
547	0x95, 0x08, /*      Report Count (8),       */
548	0x81, 0x01, /*      Input (Constant),       */
549	0xC0        /*  End Collection              */
550};
551
552/* Report descriptor template placeholder head */
553#define UCLOGIC_PH_HEAD	0xFE, 0xED, 0x1D
554
555/* Report descriptor template placeholder IDs */
556enum uclogic_ph_id {
557	UCLOGIC_PH_ID_X_LM,
558	UCLOGIC_PH_ID_X_PM,
559	UCLOGIC_PH_ID_Y_LM,
560	UCLOGIC_PH_ID_Y_PM,
561	UCLOGIC_PH_ID_PRESSURE_LM,
562	UCLOGIC_PH_ID_NUM
563};
564
565/* Report descriptor template placeholder */
566#define UCLOGIC_PH(_ID) UCLOGIC_PH_HEAD, UCLOGIC_PH_ID_##_ID
567#define UCLOGIC_PEN_REPORT_ID	0x07
568
569/* Fixed report descriptor template */
570static const __u8 uclogic_tablet_rdesc_template[] = {
571	0x05, 0x0D,             /*  Usage Page (Digitizer),                 */
572	0x09, 0x02,             /*  Usage (Pen),                            */
573	0xA1, 0x01,             /*  Collection (Application),               */
574	0x85, 0x07,             /*      Report ID (7),                      */
575	0x09, 0x20,             /*      Usage (Stylus),                     */
576	0xA0,                   /*      Collection (Physical),              */
577	0x14,                   /*          Logical Minimum (0),            */
578	0x25, 0x01,             /*          Logical Maximum (1),            */
579	0x75, 0x01,             /*          Report Size (1),                */
580	0x09, 0x42,             /*          Usage (Tip Switch),             */
581	0x09, 0x44,             /*          Usage (Barrel Switch),          */
582	0x09, 0x46,             /*          Usage (Tablet Pick),            */
583	0x95, 0x03,             /*          Report Count (3),               */
584	0x81, 0x02,             /*          Input (Variable),               */
585	0x95, 0x03,             /*          Report Count (3),               */
586	0x81, 0x03,             /*          Input (Constant, Variable),     */
587	0x09, 0x32,             /*          Usage (In Range),               */
588	0x95, 0x01,             /*          Report Count (1),               */
589	0x81, 0x02,             /*          Input (Variable),               */
590	0x95, 0x01,             /*          Report Count (1),               */
591	0x81, 0x03,             /*          Input (Constant, Variable),     */
592	0x75, 0x10,             /*          Report Size (16),               */
593	0x95, 0x01,             /*          Report Count (1),               */
594	0xA4,                   /*          Push,                           */
595	0x05, 0x01,             /*          Usage Page (Desktop),           */
596	0x65, 0x13,             /*          Unit (Inch),                    */
597	0x55, 0xFD,             /*          Unit Exponent (-3),             */
598	0x34,                   /*          Physical Minimum (0),           */
599	0x09, 0x30,             /*          Usage (X),                      */
600	0x27, UCLOGIC_PH(X_LM), /*          Logical Maximum (PLACEHOLDER),  */
601	0x47, UCLOGIC_PH(X_PM), /*          Physical Maximum (PLACEHOLDER), */
602	0x81, 0x02,             /*          Input (Variable),               */
603	0x09, 0x31,             /*          Usage (Y),                      */
604	0x27, UCLOGIC_PH(Y_LM), /*          Logical Maximum (PLACEHOLDER),  */
605	0x47, UCLOGIC_PH(Y_PM), /*          Physical Maximum (PLACEHOLDER), */
606	0x81, 0x02,             /*          Input (Variable),               */
607	0xB4,                   /*          Pop,                            */
608	0x09, 0x30,             /*          Usage (Tip Pressure),           */
609	0x27,
610	UCLOGIC_PH(PRESSURE_LM),/*          Logical Maximum (PLACEHOLDER),  */
611	0x81, 0x02,             /*          Input (Variable),               */
612	0xC0,                   /*      End Collection,                     */
613	0xC0                    /*  End Collection                          */
614};
615
616/* Parameter indices */
617enum uclogic_prm {
618	UCLOGIC_PRM_X_LM	= 1,
619	UCLOGIC_PRM_Y_LM	= 2,
620	UCLOGIC_PRM_PRESSURE_LM	= 4,
621	UCLOGIC_PRM_RESOLUTION	= 5,
622	UCLOGIC_PRM_NUM
623};
624
625/* Driver data */
626struct uclogic_drvdata {
627	__u8 *rdesc;
628	unsigned int rsize;
629	bool invert_pen_inrange;
630	bool ignore_pen_usage;
631};
632
633static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
634					unsigned int *rsize)
635{
636	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
637	__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
638	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
639
640	switch (hdev->product) {
641	case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
642		if (*rsize == PF1209_RDESC_ORIG_SIZE) {
643			rdesc = pf1209_rdesc_fixed;
644			*rsize = sizeof(pf1209_rdesc_fixed);
645		}
646		break;
647	case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U:
648		if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
649			rdesc = wp4030u_rdesc_fixed;
650			*rsize = sizeof(wp4030u_rdesc_fixed);
651		}
652		break;
653	case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U:
654		if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
655			rdesc = wp5540u_rdesc_fixed;
656			*rsize = sizeof(wp5540u_rdesc_fixed);
657		}
658		break;
659	case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U:
660		if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
661			rdesc = wp8060u_rdesc_fixed;
662			*rsize = sizeof(wp8060u_rdesc_fixed);
663		}
664		break;
665	case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062:
666		if (*rsize == WP1062_RDESC_ORIG_SIZE) {
667			rdesc = wp1062_rdesc_fixed;
668			*rsize = sizeof(wp1062_rdesc_fixed);
669		}
670		break;
671	case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
672		switch (iface_num) {
673		case 0:
674			if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
675				rdesc = twhl850_rdesc_fixed0;
676				*rsize = sizeof(twhl850_rdesc_fixed0);
677			}
678			break;
679		case 1:
680			if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
681				rdesc = twhl850_rdesc_fixed1;
682				*rsize = sizeof(twhl850_rdesc_fixed1);
683			}
684			break;
685		case 2:
686			if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
687				rdesc = twhl850_rdesc_fixed2;
688				*rsize = sizeof(twhl850_rdesc_fixed2);
689			}
690			break;
691		}
692		break;
693	case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
694		switch (iface_num) {
695		case 0:
696			if (*rsize == TWHA60_RDESC_ORIG_SIZE0) {
697				rdesc = twha60_rdesc_fixed0;
698				*rsize = sizeof(twha60_rdesc_fixed0);
699			}
700			break;
701		case 1:
702			if (*rsize == TWHA60_RDESC_ORIG_SIZE1) {
703				rdesc = twha60_rdesc_fixed1;
704				*rsize = sizeof(twha60_rdesc_fixed1);
705			}
706			break;
707		}
708		break;
709	default:
710		if (drvdata->rdesc != NULL) {
711			rdesc = drvdata->rdesc;
712			*rsize = drvdata->rsize;
713		}
714	}
715
716	return rdesc;
717}
718
719static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi,
720		struct hid_field *field, struct hid_usage *usage,
721		unsigned long **bit, int *max)
722{
723	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
724
725	/* discard the unused pen interface */
726	if ((drvdata->ignore_pen_usage) &&
727	    (field->application == HID_DG_PEN))
728		return -1;
729
730	/* let hid-core decide what to do */
731	return 0;
732}
733
734static int uclogic_input_configured(struct hid_device *hdev,
735		struct hid_input *hi)
736{
737	char *name;
738	const char *suffix = NULL;
739	struct hid_field *field;
740	size_t len;
741
742	/* no report associated (HID_QUIRK_MULTI_INPUT not set) */
743	if (!hi->report)
744		return 0;
745
746	field = hi->report->field[0];
747
748	switch (field->application) {
749	case HID_GD_KEYBOARD:
750		suffix = "Keyboard";
751		break;
752	case HID_GD_MOUSE:
753		suffix = "Mouse";
754		break;
755	case HID_GD_KEYPAD:
756		suffix = "Pad";
757		break;
758	case HID_DG_PEN:
759		suffix = "Pen";
760		break;
761	case HID_CP_CONSUMER_CONTROL:
762		suffix = "Consumer Control";
763		break;
764	case HID_GD_SYSTEM_CONTROL:
765		suffix = "System Control";
766		break;
767	}
768
769	if (suffix) {
770		len = strlen(hdev->name) + 2 + strlen(suffix);
771		name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL);
772		if (name) {
773			snprintf(name, len, "%s %s", hdev->name, suffix);
774			hi->input->name = name;
775		}
776	}
777
778	return 0;
779}
780
781/**
782 * Enable fully-functional tablet mode and determine device parameters.
783 *
784 * @hdev:	HID device
785 */
786static int uclogic_tablet_enable(struct hid_device *hdev)
787{
788	int rc;
789	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
790	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
791	__le16 *buf = NULL;
792	size_t len;
793	s32 params[UCLOGIC_PH_ID_NUM];
794	s32 resolution;
795	__u8 *p;
796	s32 v;
797
798	/*
799	 * Read string descriptor containing tablet parameters. The specific
800	 * string descriptor and data were discovered by sniffing the Windows
801	 * driver traffic.
802	 * NOTE: This enables fully-functional tablet mode.
803	 */
804	len = UCLOGIC_PRM_NUM * sizeof(*buf);
805	buf = kmalloc(len, GFP_KERNEL);
806	if (buf == NULL) {
807		hid_err(hdev, "failed to allocate parameter buffer\n");
808		rc = -ENOMEM;
809		goto cleanup;
810	}
811	rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
812				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
813				(USB_DT_STRING << 8) + 0x64,
814				0x0409, buf, len,
815				USB_CTRL_GET_TIMEOUT);
816	if (rc == -EPIPE) {
817		hid_err(hdev, "device parameters not found\n");
818		rc = -ENODEV;
819		goto cleanup;
820	} else if (rc < 0) {
821		hid_err(hdev, "failed to get device parameters: %d\n", rc);
822		rc = -ENODEV;
823		goto cleanup;
824	} else if (rc != len) {
825		hid_err(hdev, "invalid device parameters\n");
826		rc = -ENODEV;
827		goto cleanup;
828	}
829
830	/* Extract device parameters */
831	params[UCLOGIC_PH_ID_X_LM] = le16_to_cpu(buf[UCLOGIC_PRM_X_LM]);
832	params[UCLOGIC_PH_ID_Y_LM] = le16_to_cpu(buf[UCLOGIC_PRM_Y_LM]);
833	params[UCLOGIC_PH_ID_PRESSURE_LM] =
834		le16_to_cpu(buf[UCLOGIC_PRM_PRESSURE_LM]);
835	resolution = le16_to_cpu(buf[UCLOGIC_PRM_RESOLUTION]);
836	if (resolution == 0) {
837		params[UCLOGIC_PH_ID_X_PM] = 0;
838		params[UCLOGIC_PH_ID_Y_PM] = 0;
839	} else {
840		params[UCLOGIC_PH_ID_X_PM] = params[UCLOGIC_PH_ID_X_LM] *
841						1000 / resolution;
842		params[UCLOGIC_PH_ID_Y_PM] = params[UCLOGIC_PH_ID_Y_LM] *
843						1000 / resolution;
844	}
845
846	/* Allocate fixed report descriptor */
847	drvdata->rdesc = devm_kzalloc(&hdev->dev,
848				sizeof(uclogic_tablet_rdesc_template),
849				GFP_KERNEL);
850	if (drvdata->rdesc == NULL) {
851		hid_err(hdev, "failed to allocate fixed rdesc\n");
852		rc = -ENOMEM;
853		goto cleanup;
854	}
855	drvdata->rsize = sizeof(uclogic_tablet_rdesc_template);
856
857	/* Format fixed report descriptor */
858	memcpy(drvdata->rdesc, uclogic_tablet_rdesc_template,
859		drvdata->rsize);
860	for (p = drvdata->rdesc;
861	     p <= drvdata->rdesc + drvdata->rsize - 4;) {
862		if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
863		    p[3] < ARRAY_SIZE(params)) {
864			v = params[p[3]];
865			put_unaligned(cpu_to_le32(v), (s32 *)p);
866			p += 4;
867		} else {
868			p++;
869		}
870	}
871
872	rc = 0;
873
874cleanup:
875	kfree(buf);
876	return rc;
877}
878
879static int uclogic_probe(struct hid_device *hdev,
880		const struct hid_device_id *id)
881{
882	int rc;
883	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
884	struct uclogic_drvdata *drvdata;
885
886	/*
887	 * libinput requires the pad interface to be on a different node
888	 * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
889	 */
890	hdev->quirks |= HID_QUIRK_MULTI_INPUT;
891	hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
892
893	/* Allocate and assign driver data */
894	drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
895	if (drvdata == NULL)
896		return -ENOMEM;
897
898	hid_set_drvdata(hdev, drvdata);
899
900	switch (id->product) {
901	case USB_DEVICE_ID_HUION_TABLET:
902		/* If this is the pen interface */
903		if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
904			rc = uclogic_tablet_enable(hdev);
905			if (rc) {
906				hid_err(hdev, "tablet enabling failed\n");
907				return rc;
908			}
909			drvdata->invert_pen_inrange = true;
910		} else {
911			drvdata->ignore_pen_usage = true;
912		}
913		break;
914	}
915
916	rc = hid_parse(hdev);
917	if (rc) {
918		hid_err(hdev, "parse failed\n");
919		return rc;
920	}
921
922	rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
923	if (rc) {
924		hid_err(hdev, "hw start failed\n");
925		return rc;
926	}
927
928	return 0;
929}
930
931static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report,
932			u8 *data, int size)
933{
934	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
935
936	if ((drvdata->invert_pen_inrange) &&
937	    (report->type == HID_INPUT_REPORT) &&
938	    (report->id == UCLOGIC_PEN_REPORT_ID) &&
939	    (size >= 2))
940		/* Invert the in-range bit */
941		data[1] ^= 0x40;
942
943	return 0;
944}
945
946static const struct hid_device_id uclogic_devices[] = {
947	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
948				USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
949	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
950				USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
951	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
952				USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
953	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
954				USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
955	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
956				USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
957	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
958				USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
959	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
960				USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
961	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
962	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
963	{ }
964};
965MODULE_DEVICE_TABLE(hid, uclogic_devices);
966
967static struct hid_driver uclogic_driver = {
968	.name = "uclogic",
969	.id_table = uclogic_devices,
970	.probe = uclogic_probe,
971	.report_fixup = uclogic_report_fixup,
972	.raw_event = uclogic_raw_event,
973	.input_mapping = uclogic_input_mapping,
974	.input_configured = uclogic_input_configured,
975};
976module_hid_driver(uclogic_driver);
977
978MODULE_AUTHOR("Martin Rusko");
979MODULE_AUTHOR("Nikolai Kondrashov");
980MODULE_LICENSE("GPL");