hid-uclogic.c 46 KB

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