hid-uclogic.c 43 KB

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