hid-mosart.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * HID driver for the multitouch panel on the ASUS EeePC T91MT
  3. *
  4. * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
  5. * Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.com>
  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. #include <linux/device.h>
  15. #include <linux/hid.h>
  16. #include <linux/module.h>
  17. #include <linux/usb.h>
  18. #include "usbhid/usbhid.h"
  19. MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
  20. MODULE_DESCRIPTION("MosArt dual-touch panel");
  21. MODULE_LICENSE("GPL");
  22. #include "hid-ids.h"
  23. struct mosart_data {
  24. __u16 x, y;
  25. __u8 id;
  26. bool valid; /* valid finger data, or just placeholder? */
  27. bool first; /* is this the first finger in this frame? */
  28. bool activity_now; /* at least one active finger in this frame? */
  29. bool activity; /* at least one active finger previously? */
  30. };
  31. static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
  32. struct hid_field *field, struct hid_usage *usage,
  33. unsigned long **bit, int *max)
  34. {
  35. switch (usage->hid & HID_USAGE_PAGE) {
  36. case HID_UP_GENDESK:
  37. switch (usage->hid) {
  38. case HID_GD_X:
  39. hid_map_usage(hi, usage, bit, max,
  40. EV_ABS, ABS_MT_POSITION_X);
  41. /* touchscreen emulation */
  42. input_set_abs_params(hi->input, ABS_X,
  43. field->logical_minimum,
  44. field->logical_maximum, 0, 0);
  45. return 1;
  46. case HID_GD_Y:
  47. hid_map_usage(hi, usage, bit, max,
  48. EV_ABS, ABS_MT_POSITION_Y);
  49. /* touchscreen emulation */
  50. input_set_abs_params(hi->input, ABS_Y,
  51. field->logical_minimum,
  52. field->logical_maximum, 0, 0);
  53. return 1;
  54. }
  55. return 0;
  56. case HID_UP_DIGITIZER:
  57. switch (usage->hid) {
  58. case HID_DG_CONFIDENCE:
  59. case HID_DG_TIPSWITCH:
  60. case HID_DG_INPUTMODE:
  61. case HID_DG_DEVICEINDEX:
  62. case HID_DG_CONTACTCOUNT:
  63. case HID_DG_CONTACTMAX:
  64. case HID_DG_TIPPRESSURE:
  65. case HID_DG_WIDTH:
  66. case HID_DG_HEIGHT:
  67. return -1;
  68. case HID_DG_INRANGE:
  69. /* touchscreen emulation */
  70. hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
  71. return 1;
  72. case HID_DG_CONTACTID:
  73. hid_map_usage(hi, usage, bit, max,
  74. EV_ABS, ABS_MT_TRACKING_ID);
  75. return 1;
  76. }
  77. return 0;
  78. case 0xff000000:
  79. /* ignore HID features */
  80. return -1;
  81. }
  82. return 0;
  83. }
  84. static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi,
  85. struct hid_field *field, struct hid_usage *usage,
  86. unsigned long **bit, int *max)
  87. {
  88. if (usage->type == EV_KEY || usage->type == EV_ABS)
  89. clear_bit(usage->code, *bit);
  90. return 0;
  91. }
  92. /*
  93. * this function is called when a whole finger has been parsed,
  94. * so that it can decide what to send to the input layer.
  95. */
  96. static void mosart_filter_event(struct mosart_data *td, struct input_dev *input)
  97. {
  98. td->first = !td->first; /* touchscreen emulation */
  99. if (!td->valid) {
  100. /*
  101. * touchscreen emulation: if no finger in this frame is valid
  102. * and there previously was finger activity, this is a release
  103. */
  104. if (!td->first && !td->activity_now && td->activity) {
  105. input_event(input, EV_KEY, BTN_TOUCH, 0);
  106. td->activity = false;
  107. }
  108. return;
  109. }
  110. input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
  111. input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
  112. input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
  113. input_mt_sync(input);
  114. td->valid = false;
  115. /* touchscreen emulation: if first active finger in this frame... */
  116. if (!td->activity_now) {
  117. /* if there was no previous activity, emit touch event */
  118. if (!td->activity) {
  119. input_event(input, EV_KEY, BTN_TOUCH, 1);
  120. td->activity = true;
  121. }
  122. td->activity_now = true;
  123. /* and in any case this is our preferred finger */
  124. input_event(input, EV_ABS, ABS_X, td->x);
  125. input_event(input, EV_ABS, ABS_Y, td->y);
  126. }
  127. }
  128. static int mosart_event(struct hid_device *hid, struct hid_field *field,
  129. struct hid_usage *usage, __s32 value)
  130. {
  131. struct mosart_data *td = hid_get_drvdata(hid);
  132. if (hid->claimed & HID_CLAIMED_INPUT) {
  133. struct input_dev *input = field->hidinput->input;
  134. switch (usage->hid) {
  135. case HID_DG_INRANGE:
  136. td->valid = !!value;
  137. break;
  138. case HID_GD_X:
  139. td->x = value;
  140. break;
  141. case HID_GD_Y:
  142. td->y = value;
  143. mosart_filter_event(td, input);
  144. break;
  145. case HID_DG_CONTACTID:
  146. td->id = value;
  147. break;
  148. case HID_DG_CONTACTCOUNT:
  149. /* touch emulation: this is the last field in a frame */
  150. td->first = false;
  151. td->activity_now = false;
  152. break;
  153. case HID_DG_CONFIDENCE:
  154. case HID_DG_TIPSWITCH:
  155. /* avoid interference from generic hidinput handling */
  156. break;
  157. default:
  158. /* fallback to the generic hidinput handling */
  159. return 0;
  160. }
  161. }
  162. /* we have handled the hidinput part, now remains hiddev */
  163. if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
  164. hid->hiddev_hid_event(hid, field, usage, value);
  165. return 1;
  166. }
  167. static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
  168. {
  169. int ret;
  170. struct mosart_data *td;
  171. td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
  172. if (!td) {
  173. dev_err(&hdev->dev, "cannot allocate MosArt data\n");
  174. return -ENOMEM;
  175. }
  176. td->valid = false;
  177. td->activity = false;
  178. td->activity_now = false;
  179. td->first = false;
  180. hid_set_drvdata(hdev, td);
  181. /* currently, it's better to have one evdev device only */
  182. #if 0
  183. hdev->quirks |= HID_QUIRK_MULTI_INPUT;
  184. #endif
  185. ret = hid_parse(hdev);
  186. if (ret == 0)
  187. ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
  188. if (ret == 0) {
  189. struct hid_report_enum *re = hdev->report_enum
  190. + HID_FEATURE_REPORT;
  191. struct hid_report *r = re->report_id_hash[7];
  192. r->field[0]->value[0] = 0x02;
  193. usbhid_submit_report(hdev, r, USB_DIR_OUT);
  194. } else
  195. kfree(td);
  196. return ret;
  197. }
  198. static void mosart_remove(struct hid_device *hdev)
  199. {
  200. hid_hw_stop(hdev);
  201. kfree(hid_get_drvdata(hdev));
  202. hid_set_drvdata(hdev, NULL);
  203. }
  204. static const struct hid_device_id mosart_devices[] = {
  205. { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
  206. { }
  207. };
  208. MODULE_DEVICE_TABLE(hid, mosart_devices);
  209. static const struct hid_usage_id mosart_grabbed_usages[] = {
  210. { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
  211. { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
  212. };
  213. static struct hid_driver mosart_driver = {
  214. .name = "mosart",
  215. .id_table = mosart_devices,
  216. .probe = mosart_probe,
  217. .remove = mosart_remove,
  218. .input_mapping = mosart_input_mapping,
  219. .input_mapped = mosart_input_mapped,
  220. .usage_table = mosart_grabbed_usages,
  221. .event = mosart_event,
  222. };
  223. static int __init mosart_init(void)
  224. {
  225. return hid_register_driver(&mosart_driver);
  226. }
  227. static void __exit mosart_exit(void)
  228. {
  229. hid_unregister_driver(&mosart_driver);
  230. }
  231. module_init(mosart_init);
  232. module_exit(mosart_exit);