hid-cmedia.c 3.8 KB

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