hid-cmedia.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * HID driver for CMedia CM6533 audio jack controls
  4. *
  5. * Copyright (C) 2015 Ben Chen <ben_chen@bizlinktech.com>
  6. */
  7. #include <linux/device.h>
  8. #include <linux/hid.h>
  9. #include <linux/module.h>
  10. #include "hid-ids.h"
  11. MODULE_AUTHOR("Ben Chen");
  12. MODULE_DESCRIPTION("CM6533 HID jack controls");
  13. MODULE_LICENSE("GPL");
  14. #define CM6533_JD_TYPE_COUNT 1
  15. #define CM6533_JD_RAWEV_LEN 16
  16. #define CM6533_JD_SFX_OFFSET 8
  17. /*
  18. *
  19. *CM6533 audio jack HID raw events:
  20. *
  21. *Plug in:
  22. *01000600 002083xx 080008c0 10000000
  23. *about 3 seconds later...
  24. *01000a00 002083xx 08000380 10000000
  25. *01000600 002083xx 08000380 10000000
  26. *
  27. *Plug out:
  28. *01000400 002083xx 080008c0 x0000000
  29. */
  30. static const u8 ji_sfx[] = { 0x08, 0x00, 0x08, 0xc0 };
  31. static const u8 ji_in[] = { 0x01, 0x00, 0x06, 0x00 };
  32. static const u8 ji_out[] = { 0x01, 0x00, 0x04, 0x00 };
  33. static int jack_switch_types[CM6533_JD_TYPE_COUNT] = {
  34. SW_HEADPHONE_INSERT,
  35. };
  36. struct cmhid {
  37. struct input_dev *input_dev;
  38. struct hid_device *hid;
  39. unsigned short switch_map[CM6533_JD_TYPE_COUNT];
  40. };
  41. static void hp_ev(struct hid_device *hid, struct cmhid *cm, int value)
  42. {
  43. input_report_switch(cm->input_dev, SW_HEADPHONE_INSERT, value);
  44. input_sync(cm->input_dev);
  45. }
  46. static int cmhid_raw_event(struct hid_device *hid, struct hid_report *report,
  47. u8 *data, int len)
  48. {
  49. struct cmhid *cm = hid_get_drvdata(hid);
  50. if (len != CM6533_JD_RAWEV_LEN)
  51. goto out;
  52. if (memcmp(data+CM6533_JD_SFX_OFFSET, ji_sfx, sizeof(ji_sfx)))
  53. goto out;
  54. if (!memcmp(data, ji_out, sizeof(ji_out))) {
  55. hp_ev(hid, cm, 0);
  56. goto out;
  57. }
  58. if (!memcmp(data, ji_in, sizeof(ji_in))) {
  59. hp_ev(hid, cm, 1);
  60. goto out;
  61. }
  62. out:
  63. return 0;
  64. }
  65. static int cmhid_input_configured(struct hid_device *hid,
  66. struct hid_input *hidinput)
  67. {
  68. struct input_dev *input_dev = hidinput->input;
  69. struct cmhid *cm = hid_get_drvdata(hid);
  70. int i;
  71. cm->input_dev = input_dev;
  72. memcpy(cm->switch_map, jack_switch_types, sizeof(cm->switch_map));
  73. input_dev->evbit[0] = BIT(EV_SW);
  74. for (i = 0; i < CM6533_JD_TYPE_COUNT; i++)
  75. input_set_capability(cm->input_dev,
  76. EV_SW, jack_switch_types[i]);
  77. return 0;
  78. }
  79. static int cmhid_input_mapping(struct hid_device *hid,
  80. struct hid_input *hi, struct hid_field *field,
  81. struct hid_usage *usage, unsigned long **bit, int *max)
  82. {
  83. return -1;
  84. }
  85. static int cmhid_probe(struct hid_device *hid, const struct hid_device_id *id)
  86. {
  87. int ret;
  88. struct cmhid *cm;
  89. cm = kzalloc(sizeof(struct cmhid), GFP_KERNEL);
  90. if (!cm) {
  91. ret = -ENOMEM;
  92. goto allocfail;
  93. }
  94. cm->hid = hid;
  95. hid->quirks |= HID_QUIRK_HIDINPUT_FORCE;
  96. hid_set_drvdata(hid, cm);
  97. ret = hid_parse(hid);
  98. if (ret) {
  99. hid_err(hid, "parse failed\n");
  100. goto fail;
  101. }
  102. ret = hid_hw_start(hid, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE);
  103. if (ret) {
  104. hid_err(hid, "hw start failed\n");
  105. goto fail;
  106. }
  107. return 0;
  108. fail:
  109. kfree(cm);
  110. allocfail:
  111. return ret;
  112. }
  113. static void cmhid_remove(struct hid_device *hid)
  114. {
  115. struct cmhid *cm = hid_get_drvdata(hid);
  116. hid_hw_stop(hid);
  117. kfree(cm);
  118. }
  119. static const struct hid_device_id cmhid_devices[] = {
  120. { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM6533) },
  121. { }
  122. };
  123. MODULE_DEVICE_TABLE(hid, cmhid_devices);
  124. static struct hid_driver cmhid_driver = {
  125. .name = "cm6533_jd",
  126. .id_table = cmhid_devices,
  127. .raw_event = cmhid_raw_event,
  128. .input_configured = cmhid_input_configured,
  129. .probe = cmhid_probe,
  130. .remove = cmhid_remove,
  131. .input_mapping = cmhid_input_mapping,
  132. };
  133. module_hid_driver(cmhid_driver);