hid-chicony.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * HID driver for some chicony "special" devices
  4. *
  5. * Copyright (c) 1999 Andreas Gal
  6. * Copyright (c) 2000-2005 Vojtech Pavlik <[email protected]>
  7. * Copyright (c) 2005 Michael Haboustak <[email protected]> for Concept2, Inc
  8. * Copyright (c) 2006-2007 Jiri Kosina
  9. * Copyright (c) 2007 Paul Walmsley
  10. * Copyright (c) 2008 Jiri Slaby
  11. */
  12. /*
  13. */
  14. #include <linux/device.h>
  15. #include <linux/input.h>
  16. #include <linux/hid.h>
  17. #include <linux/module.h>
  18. #include <linux/usb.h>
  19. #include "hid-ids.h"
  20. #define CH_WIRELESS_CTL_REPORT_ID 0x11
  21. static int ch_report_wireless(struct hid_report *report, u8 *data, int size)
  22. {
  23. struct hid_device *hdev = report->device;
  24. struct input_dev *input;
  25. if (report->id != CH_WIRELESS_CTL_REPORT_ID || report->maxfield != 1)
  26. return 0;
  27. input = report->field[0]->hidinput->input;
  28. if (!input) {
  29. hid_warn(hdev, "can't find wireless radio control's input");
  30. return 0;
  31. }
  32. input_report_key(input, KEY_RFKILL, 1);
  33. input_sync(input);
  34. input_report_key(input, KEY_RFKILL, 0);
  35. input_sync(input);
  36. return 1;
  37. }
  38. static int ch_raw_event(struct hid_device *hdev,
  39. struct hid_report *report, u8 *data, int size)
  40. {
  41. if (report->application == HID_GD_WIRELESS_RADIO_CTLS)
  42. return ch_report_wireless(report, data, size);
  43. return 0;
  44. }
  45. #define ch_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
  46. EV_KEY, (c))
  47. static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
  48. struct hid_field *field, struct hid_usage *usage,
  49. unsigned long **bit, int *max)
  50. {
  51. if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
  52. return 0;
  53. set_bit(EV_REP, hi->input->evbit);
  54. switch (usage->hid & HID_USAGE) {
  55. case 0xff01: ch_map_key_clear(BTN_1); break;
  56. case 0xff02: ch_map_key_clear(BTN_2); break;
  57. case 0xff03: ch_map_key_clear(BTN_3); break;
  58. case 0xff04: ch_map_key_clear(BTN_4); break;
  59. case 0xff05: ch_map_key_clear(BTN_5); break;
  60. case 0xff06: ch_map_key_clear(BTN_6); break;
  61. case 0xff07: ch_map_key_clear(BTN_7); break;
  62. case 0xff08: ch_map_key_clear(BTN_8); break;
  63. case 0xff09: ch_map_key_clear(BTN_9); break;
  64. case 0xff0a: ch_map_key_clear(BTN_A); break;
  65. case 0xff0b: ch_map_key_clear(BTN_B); break;
  66. case 0x00f1: ch_map_key_clear(KEY_WLAN); break;
  67. case 0x00f2: ch_map_key_clear(KEY_BRIGHTNESSDOWN); break;
  68. case 0x00f3: ch_map_key_clear(KEY_BRIGHTNESSUP); break;
  69. case 0x00f4: ch_map_key_clear(KEY_DISPLAY_OFF); break;
  70. case 0x00f7: ch_map_key_clear(KEY_CAMERA); break;
  71. case 0x00f8: ch_map_key_clear(KEY_PROG1); break;
  72. default:
  73. return 0;
  74. }
  75. return 1;
  76. }
  77. static __u8 *ch_switch12_report_fixup(struct hid_device *hdev, __u8 *rdesc,
  78. unsigned int *rsize)
  79. {
  80. struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  81. if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
  82. /* Change usage maximum and logical maximum from 0x7fff to
  83. * 0x2fff, so they don't exceed HID_MAX_USAGES */
  84. switch (hdev->product) {
  85. case USB_DEVICE_ID_CHICONY_ACER_SWITCH12:
  86. if (*rsize >= 128 && rdesc[64] == 0xff && rdesc[65] == 0x7f
  87. && rdesc[69] == 0xff && rdesc[70] == 0x7f) {
  88. hid_info(hdev, "Fixing up report descriptor\n");
  89. rdesc[65] = rdesc[70] = 0x2f;
  90. }
  91. break;
  92. }
  93. }
  94. return rdesc;
  95. }
  96. static int ch_probe(struct hid_device *hdev, const struct hid_device_id *id)
  97. {
  98. int ret;
  99. if (!hid_is_usb(hdev))
  100. return -EINVAL;
  101. hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
  102. ret = hid_parse(hdev);
  103. if (ret) {
  104. hid_err(hdev, "Chicony hid parse failed: %d\n", ret);
  105. return ret;
  106. }
  107. ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
  108. if (ret) {
  109. hid_err(hdev, "Chicony hw start failed: %d\n", ret);
  110. return ret;
  111. }
  112. return 0;
  113. }
  114. static const struct hid_device_id ch_devices[] = {
  115. { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
  116. { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
  117. { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS3) },
  118. { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
  119. { }
  120. };
  121. MODULE_DEVICE_TABLE(hid, ch_devices);
  122. static struct hid_driver ch_driver = {
  123. .name = "chicony",
  124. .id_table = ch_devices,
  125. .report_fixup = ch_switch12_report_fixup,
  126. .input_mapping = ch_input_mapping,
  127. .probe = ch_probe,
  128. .raw_event = ch_raw_event,
  129. };
  130. module_hid_driver(ch_driver);
  131. MODULE_LICENSE("GPL");