hid_surface_dial.bpf.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2022 Benjamin Tissoires
  3. */
  4. #include "vmlinux.h"
  5. #include <bpf/bpf_helpers.h>
  6. #include <bpf/bpf_tracing.h>
  7. #include "hid_bpf_helpers.h"
  8. #define HID_UP_BUTTON 0x0009
  9. #define HID_GD_WHEEL 0x0038
  10. SEC("struct_ops/hid_device_event")
  11. int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx)
  12. {
  13. __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);
  14. if (!data)
  15. return 0; /* EPERM check */
  16. /* Touch */
  17. data[1] &= 0xfd;
  18. /* X */
  19. data[4] = 0;
  20. data[5] = 0;
  21. /* Y */
  22. data[6] = 0;
  23. data[7] = 0;
  24. return 0;
  25. }
  26. /* 72 == 360 / 5 -> 1 report every 5 degrees */
  27. int resolution = 72;
  28. int physical = 5;
  29. struct haptic_syscall_args {
  30. unsigned int hid;
  31. int retval;
  32. };
  33. static __u8 haptic_data[8];
  34. SEC("syscall")
  35. int set_haptic(struct haptic_syscall_args *args)
  36. {
  37. struct hid_bpf_ctx *ctx;
  38. const size_t size = sizeof(haptic_data);
  39. u16 *res;
  40. int ret;
  41. if (size > sizeof(haptic_data))
  42. return -7; /* -E2BIG */
  43. ctx = hid_bpf_allocate_context(args->hid);
  44. if (!ctx)
  45. return -1; /* EPERM check */
  46. haptic_data[0] = 1; /* report ID */
  47. ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
  48. bpf_printk("probed/remove event ret value: %d", ret);
  49. bpf_printk("buf: %02x %02x %02x",
  50. haptic_data[0],
  51. haptic_data[1],
  52. haptic_data[2]);
  53. bpf_printk(" %02x %02x %02x",
  54. haptic_data[3],
  55. haptic_data[4],
  56. haptic_data[5]);
  57. bpf_printk(" %02x %02x",
  58. haptic_data[6],
  59. haptic_data[7]);
  60. /* whenever resolution multiplier is not 3600, we have the fixed report descriptor */
  61. res = (u16 *)&haptic_data[1];
  62. if (*res != 3600) {
  63. // haptic_data[1] = 72; /* resolution multiplier */
  64. // haptic_data[2] = 0; /* resolution multiplier */
  65. // haptic_data[3] = 0; /* Repeat Count */
  66. haptic_data[4] = 3; /* haptic Auto Trigger */
  67. // haptic_data[5] = 5; /* Waveform Cutoff Time */
  68. // haptic_data[6] = 80; /* Retrigger Period */
  69. // haptic_data[7] = 0; /* Retrigger Period */
  70. } else {
  71. haptic_data[4] = 0;
  72. }
  73. ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
  74. bpf_printk("set haptic ret value: %d -> %d", ret, haptic_data[4]);
  75. args->retval = ret;
  76. hid_bpf_release_context(ctx);
  77. return 0;
  78. }
  79. /* Convert REL_DIAL into REL_WHEEL */
  80. SEC("struct_ops/hid_rdesc_fixup")
  81. int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
  82. {
  83. __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
  84. __u16 *res, *phys;
  85. if (!data)
  86. return 0; /* EPERM check */
  87. /* Convert TOUCH into a button */
  88. data[31] = HID_UP_BUTTON;
  89. data[33] = 2;
  90. /* Convert REL_DIAL into REL_WHEEL */
  91. data[45] = HID_GD_WHEEL;
  92. /* Change Resolution Multiplier */
  93. phys = (__u16 *)&data[61];
  94. *phys = physical;
  95. res = (__u16 *)&data[66];
  96. *res = resolution;
  97. /* Convert X,Y from Abs to Rel */
  98. data[88] = 0x06;
  99. data[98] = 0x06;
  100. return 0;
  101. }
  102. SEC(".struct_ops.link")
  103. struct hid_bpf_ops surface_dial = {
  104. .hid_rdesc_fixup = (void *)hid_rdesc_fixup,
  105. .hid_device_event = (void *)hid_event,
  106. };
  107. char _license[] SEC("license") = "GPL";
  108. u32 _version SEC("version") = 1;