1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2024 Red Hat, Inc 3 */ 4 5 #include "vmlinux.h" 6 #include "hid_bpf.h" 7 #include "hid_bpf_helpers.h" 8 #include "hid_report_helpers.h" 9 #include <bpf/bpf_tracing.h> 10 11 #define VID_HUION 0x256C 12 #define PID_KEYDIAL_K20_BLUETOOTH 0x8251 13 14 HID_BPF_CONFIG( 15 HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_HUION, PID_KEYDIAL_K20_BLUETOOTH), 16 ); 17 18 /* This is the same device as in 0010-Huion__KeydialK20 but connected via Bluetooth. 19 * It does not need (to support?) switching to a vendor mode so we just modify the 20 * existing mode. 21 * 22 * By default it exports two hidraw nodes, only the second one sends events. 23 * 24 * This is the first hidraw node which we disable: 25 * 26 * # Keydial mini-050 27 * # Report descriptor length: 114 bytes 28 * # Bytes // Field Name Offset 29 * # ---------------------------------------------------------------------------------- 30 * # 0x05, 0x01, // Usage Page (Generic Desktop) 0 31 * # 0x09, 0x0e, // Usage (System Multi-Axis Controller) 2 32 * # 0xa1, 0x01, // Collection (Application) 4 33 * # ┅ 0x85, 0x03, // Report ID (3) 6 34 * # 0x05, 0x0d, // Usage Page (Digitizers) 8 35 * # 0x75, 0x08, // Report Size (8) 10 36 * # 0x95, 0x01, // Report Count (1) 12 37 * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 14 38 * # 0x09, 0x21, // Usage (Puck) 16 39 * # 0xa1, 0x02, // Collection (Logical) 18 40 * # 0x15, 0x00, // Logical Minimum (0) 20 41 * # 0x25, 0x01, // Logical Maximum (1) 22 42 * # 0x75, 0x01, // Report Size (1) 24 43 * # 0x95, 0x01, // Report Count (1) 26 44 * # 0xa1, 0x00, // Collection (Physical) 28 45 * # 0x05, 0x09, // Usage Page (Button) 30 46 * # 0x09, 0x01, // Usage (Button 1) 32 47 * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 34 48 * # 0x05, 0x0d, // Usage Page (Digitizers) 36 49 * # 0x09, 0x33, // Usage (Touch) 38 50 * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 40 51 * # 0x95, 0x06, // Report Count (6) 42 52 * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 44 53 * # 0xa1, 0x02, // Collection (Logical) 46 54 * # 0x05, 0x01, // Usage Page (Generic Desktop) 48 55 * # 0x09, 0x37, // Usage (Dial) 50 56 * # 0x16, 0x00, 0x80, // Logical Minimum (32768) 52 57 * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 55 58 * # 0x75, 0x10, // Report Size (16) 58 59 * # 0x95, 0x01, // Report Count (1) 60 60 * # ┇ 0x81, 0x06, // Input (Data,Var,Rel) 62 61 * # 0x35, 0x00, // Physical Minimum (0) 64 62 * # 0x46, 0x10, 0x0e, // Physical Maximum (3600) 66 63 * # 0x15, 0x00, // Logical Minimum (0) 69 64 * # 0x26, 0x10, 0x0e, // Logical Maximum (3600) 71 65 * # 0x09, 0x48, // Usage (Resolution Multiplier) 74 66 * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 76 67 * # 0x45, 0x00, // Physical Maximum (0) 78 68 * # 0xc0, // End Collection 80 69 * # 0x75, 0x08, // Report Size (8) 81 70 * # 0x95, 0x01, // Report Count (1) 83 71 * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 85 72 * # 0x75, 0x08, // Report Size (8) 87 73 * # 0x95, 0x01, // Report Count (1) 89 74 * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 91 75 * # 0x75, 0x08, // Report Size (8) 93 76 * # 0x95, 0x01, // Report Count (1) 95 77 * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 97 78 * # 0x75, 0x08, // Report Size (8) 99 79 * # 0x95, 0x01, // Report Count (1) 101 80 * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 103 81 * # 0x75, 0x08, // Report Size (8) 105 82 * # 0x95, 0x01, // Report Count (1) 107 83 * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 109 84 * # 0xc0, // End Collection 111 85 * # 0xc0, // End Collection 112 86 * # 0xc0, // End Collection 113 87 * R: 114 05 01 09 0e a1 01 85 03 05 0d 75 08 95 01 81 01 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0 88 * N: Keydial mini-050 89 * I: 5 256c 8251 90 * 91 * The second hidraw node is what sends events: 92 * 93 * # Keydial mini-050 94 * # Report descriptor length: 160 bytes 95 * # Bytes // Field Name Offset 96 * # ---------------------------------------------------------------------------------- 97 * # 0x05, 0x01, // Usage Page (Generic Desktop) 0 98 * # 0x09, 0x06, // Usage (Keyboard) 2 99 * # 0xa1, 0x01, // Collection (Application) 4 100 * # ┅ 0x85, 0x01, // Report ID (1) 6 101 * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 8 102 * # 0x19, 0xe0, // Usage Minimum (224) 10 103 * # 0x29, 0xe7, // Usage Maximum (231) 12 104 * # 0x15, 0x00, // Logical Minimum (0) 14 105 * # 0x25, 0x01, // Logical Maximum (1) 16 106 * # 0x75, 0x01, // Report Size (1) 18 107 * # 0x95, 0x08, // Report Count (8) 20 108 * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 22 109 * # 0x95, 0x01, // Report Count (1) 24 110 * # 0x75, 0x08, // Report Size (8) 26 111 * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 28 112 * # 0x95, 0x05, // Report Count (5) 30 113 * # 0x75, 0x01, // Report Size (1) 32 114 * # 0x05, 0x08, // Usage Page (LED) 34 115 * # 0x19, 0x01, // Usage Minimum (1) 36 116 * # 0x29, 0x05, // Usage Maximum (5) 38 117 * # ┊ 0x91, 0x02, // Output (Data,Var,Abs) 40 118 * # 0x95, 0x01, // Report Count (1) 42 119 * # 0x75, 0x03, // Report Size (3) 44 120 * # ┊ 0x91, 0x01, // Output (Cnst,Arr,Abs) 46 121 * # 0x95, 0x06, // Report Count (6) 48 122 * # 0x75, 0x08, // Report Size (8) 50 123 * # 0x15, 0x00, // Logical Minimum (0) 52 124 * # 0x25, 0xf1, // Logical Maximum (241) 54 125 * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 56 126 * # 0x19, 0x00, // Usage Minimum (0) 58 127 * # 0x29, 0xf1, // Usage Maximum (241) 60 128 * # ┇ 0x81, 0x00, // Input (Data,Arr,Abs) 62 129 * # 0xc0, // End Collection 64 130 * # 0x05, 0x0c, // Usage Page (Consumer) 65 131 * # 0x09, 0x01, // Usage (Consumer Control) 67 132 * # 0xa1, 0x01, // Collection (Application) 69 133 * # ┅ 0x85, 0x02, // Report ID (2) 71 134 * # 0x05, 0x0c, // Usage Page (Consumer) 73 135 * # 0x19, 0x00, // Usage Minimum (0) 75 136 * # 0x2a, 0x80, 0x03, // Usage Maximum (896) 77 137 * # 0x15, 0x00, // Logical Minimum (0) 80 138 * # 0x26, 0x80, 0x03, // Logical Maximum (896) 82 139 * # 0x75, 0x10, // Report Size (16) 85 140 * # 0x95, 0x01, // Report Count (1) 87 141 * # ┇ 0x81, 0x00, // Input (Data,Arr,Abs) 89 142 * # 0xc0, // End Collection 91 143 * # 0x05, 0x01, // Usage Page (Generic Desktop) 92 144 * # 0x09, 0x02, // Usage (Mouse) 94 145 * # 0xa1, 0x01, // Collection (Application) 96 146 * # 0x09, 0x01, // Usage (Pointer) 98 147 * # ┅ 0x85, 0x05, // Report ID (5) 100 148 * # 0xa1, 0x00, // Collection (Physical) 102 149 * # 0x05, 0x09, // Usage Page (Button) 104 150 * # 0x19, 0x01, // Usage Minimum (1) 106 151 * # 0x29, 0x05, // Usage Maximum (5) 108 152 * # 0x15, 0x00, // Logical Minimum (0) 110 153 * # 0x25, 0x01, // Logical Maximum (1) 112 154 * # 0x95, 0x05, // Report Count (5) 114 155 * # 0x75, 0x01, // Report Size (1) 116 156 * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 118 157 * # 0x95, 0x01, // Report Count (1) 120 158 * # 0x75, 0x03, // Report Size (3) 122 159 * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 124 160 * # 0x05, 0x01, // Usage Page (Generic Desktop) 126 161 * # 0x09, 0x30, // Usage (X) 128 162 * # 0x09, 0x31, // Usage (Y) 130 163 * # 0x16, 0x01, 0x80, // Logical Minimum (32769) 132 164 * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 135 165 * # 0x75, 0x10, // Report Size (16) 138 166 * # 0x95, 0x02, // Report Count (2) 140 167 * # ┇ 0x81, 0x06, // Input (Data,Var,Rel) 142 168 * # 0x05, 0x01, // Usage Page (Generic Desktop) 144 169 * # 0x09, 0x38, // Usage (Wheel) 146 170 * # 0x15, 0x81, // Logical Minimum (129) 148 171 * # 0x25, 0x7f, // Logical Maximum (127) 150 172 * # 0x95, 0x01, // Report Count (1) 152 173 * # 0x75, 0x08, // Report Size (8) 154 174 * # ┇ 0x81, 0x06, // Input (Data,Var,Rel) 156 175 * # 0xc0, // End Collection 158 176 * # 0xc0, // End Collection 159 177 * R: 160 05 01 09 06 a1 01 85 01 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 95 01 75 08 81 01 95 05 75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 01 95 06 75 08 15 00 25 f1 05 07 19 00 29 f1 81 00 c0 05 0c 09 01 a1 01 85 02 05 0c 19 00 2a 80 03 15 00 26 80 03 75 10 95 01 81 00 c0 05 01 09 02 a1 01 09 01 85 05 a1 00 05 09 19 01 29 05 15 00 25 01 95 05 75 01 81 02 95 01 75 03 81 01 05 01 09 30 09 31 16 01 80 26 ff 7f 75 10 95 02 81 06 05 01 09 38 15 81 25 7f 95 01 75 08 81 06 c0 c0 178 * N: Keydial mini-050 179 * I: 5 256c 8251 180 * # Report descriptor: 181 * # ------- Input Report ------- 182 * # ░ Report ID: 1 183 * # ░ | Report size: 72 bits 184 * # ░ Bit: 8 Usage: 0007/00e0: Keyboard/Keypad / Keyboard LeftControl Logical Range: 0..=1 185 * # ░ Bit: 9 Usage: 0007/00e1: Keyboard/Keypad / Keyboard LeftShift Logical Range: 0..=1 186 * # ░ Bit: 10 Usage: 0007/00e2: Keyboard/Keypad / Keyboard LeftAlt Logical Range: 0..=1 187 * # ░ Bit: 11 Usage: 0007/00e3: Keyboard/Keypad / Keyboard Left GUI Logical Range: 0..=1 188 * # ░ Bit: 12 Usage: 0007/00e4: Keyboard/Keypad / Keyboard RightControl Logical Range: 0..=1 189 * # ░ Bit: 13 Usage: 0007/00e5: Keyboard/Keypad / Keyboard RightShift Logical Range: 0..=1 190 * # ░ Bit: 14 Usage: 0007/00e6: Keyboard/Keypad / Keyboard RightAlt Logical Range: 0..=1 191 * # ░ Bit: 15 Usage: 0007/00e7: Keyboard/Keypad / Keyboard Right GUI Logical Range: 0..=1 192 * # ░ Bits: 16..=23 ######### Padding 193 * # ░ Bits: 24..=71 Usages: Logical Range: 0..=241 194 * # ░ 0007/0000: <unknown> 195 * # ░ 0007/0001: Keyboard/Keypad / ErrorRollOver 196 * # ░ 0007/0002: Keyboard/Keypad / POSTFail 197 * # ░ 0007/0003: Keyboard/Keypad / ErrorUndefined 198 * # ░ 0007/0004: Keyboard/Keypad / Keyboard A 199 * # ░ ... use --full to see all usages 200 * # ------- Input Report ------- 201 * # ▒ Report ID: 2 202 * # ▒ | Report size: 24 bits 203 * # ▒ Bits: 8..=23 Usages: Logical Range: 0..=896 204 * # ▒ 000c/0000: <unknown> 205 * # ▒ 000c/0001: Consumer / Consumer Control 206 * # ▒ 000c/0002: Consumer / Numeric Key Pad 207 * # ▒ 000c/0003: Consumer / Programmable Buttons 208 * # ▒ 000c/0004: Consumer / Microphone 209 * # ▒ ... use --full to see all usages 210 * # ------- Input Report ------- 211 * # ▞ Report ID: 5 212 * # ▞ | Report size: 56 bits 213 * # ▞ Bit: 8 Usage: 0009/0001: Button / Button 1 Logical Range: 0..=1 214 * # ▞ Bit: 9 Usage: 0009/0002: Button / Button 2 Logical Range: 0..=1 215 * # ▞ Bit: 10 Usage: 0009/0003: Button / Button 3 Logical Range: 0..=1 216 * # ▞ Bit: 11 Usage: 0009/0004: Button / Button 4 Logical Range: 0..=1 217 * # ▞ Bit: 12 Usage: 0009/0005: Button / Button 5 Logical Range: 0..=1 218 * # ▞ Bits: 13..=15 ######### Padding 219 * # ▞ Bits: 16..=31 Usage: 0001/0030: Generic Desktop / X Logical Range: 32769..=32767 220 * # ▞ Bits: 32..=47 Usage: 0001/0031: Generic Desktop / Y Logical Range: 32769..=32767 221 * # ▞ Bits: 48..=55 Usage: 0001/0038: Generic Desktop / Wheel Logical Range: 129..=127 222 * # ------- Output Report ------- 223 * # ░ Report ID: 1 224 * # ░ | Report size: 16 bits 225 * # ░ Bit: 8 Usage: 0008/0001: LED / Num Lock Logical Range: 0..=1 226 * # ░ Bit: 9 Usage: 0008/0002: LED / Caps Lock Logical Range: 0..=1 227 * # ░ Bit: 10 Usage: 0008/0003: LED / Scroll Lock Logical Range: 0..=1 228 * # ░ Bit: 11 Usage: 0008/0004: LED / Compose Logical Range: 0..=1 229 * # ░ Bit: 12 Usage: 0008/0005: LED / Kana Logical Range: 0..=1 230 * # ░ Bits: 13..=15 ######### Padding 231 * ############################################################################## 232 * # Event nodes: 233 * # - /dev/input/event12: "Keydial mini-050 Keyboard" 234 * # - /dev/input/event14: "Keydial mini-050 Mouse" 235 * ############################################################################## 236 * # Recorded events below in format: 237 * # E: <seconds>.<microseconds> <length-in-bytes> [bytes ...] 238 * # 239 * 240 * - Report ID 1 sends keyboard shortcuts when pressing the buttons, e.g. 241 * 242 * # ░ Report ID: 1 / 243 * # ░ Keyboard LeftControl: 0 |Keyboard LeftShift: 0 |Keyboard LeftAlt: 0 |Keyboard Left GUI: 0 |Keyboard RightControl: 0 |Keyboard RightShift: 0 |Keyboard RightAlt: 0 |Keyboard Right GUI: 0 |<8 bits padding> |0007/0000: 0| Keyboard K: 14| 0007/0000: 0| 0007/0000: 0| 0007/0000: 0| 0007/0000: 0 244 * E: 000000.000292 9 01 00 00 00 0e 00 00 00 00 245 * 246 * - Report ID 2 sends the button inside the wheel/dial thing 247 * # ▒ Report ID: 2 / 248 * # ▒ Play/Pause: 205 249 * E: 000134.347845 3 02 cd 00 250 * # ▒ Report ID: 2 / 251 * # ▒ 000c/0000: 0 252 * E: 000134.444965 3 02 00 00 253 * 254 * - Report ID 5 sends the wheel relative events (always a double-event with the second as zero) 255 * # ▞ Report ID: 5 / 256 * # ▞ Button 1: 0 |Button 2: 0 |Button 3: 0 |Button 4: 0 |Button 5: 0 |<3 bits padding> |X: 0 |Y: 0 |Wheel: 255 257 * E: 000064.859915 7 05 00 00 00 00 00 ff 258 * # ▞ Report ID: 5 / 259 * # ▞ Button 1: 0 |Button 2: 0 |Button 3: 0 |Button 4: 0 |Button 5: 0 |<3 bits padding> |X: 0 |Y: 0 |Wheel: 0 260 * E: 000064.882009 7 05 00 00 00 00 00 00 261 */ 262 263 #define BT_PAD_REPORT_DESCRIPTOR_LENGTH 160 264 #define BT_PUCK_REPORT_DESCRIPTOR_LENGTH 114 // This one doesn't send events 265 #define BT_PAD_KBD_REPORT_ID 1 266 #define BT_PAD_CC_REPORT_ID 2 267 #define BT_PAD_MOUSE_REPORT_ID 5 268 #define BT_PAD_KBD_REPORT_LENGTH 9 269 #define BT_PAD_CC_REPORT_LENGTH 3 270 #define BT_PAD_MOUSE_REPORT_LENGTH 7 271 #define OUR_REPORT_ID 11 /* "randomly" picked report ID for our reports */ 272 273 __u32 last_button_state = 0; 274 275 static const __u8 disabled_rdesc_puck[] = { 276 FixedSizeVendorReport(BT_PUCK_REPORT_DESCRIPTOR_LENGTH) 277 }; 278 279 static const __u8 fixed_rdesc_pad[] = { 280 UsagePage_GenericDesktop 281 Usage_GD_Keypad 282 CollectionApplication( 283 // Byte 0 284 ReportId(OUR_REPORT_ID) 285 UsagePage_Digitizers 286 Usage_Dig_TabletFunctionKeys 287 CollectionPhysical( 288 // Byte 1 is a button so we look like a tablet 289 Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad 290 ReportCount(1) 291 ReportSize(1) 292 Input(Var|Abs) 293 ReportCount(7) // Padding 294 Input(Const) 295 // Bytes 2/3 - x/y just exist so we get to be a tablet pad 296 UsagePage_GenericDesktop 297 Usage_GD_X 298 Usage_GD_Y 299 LogicalMinimum_i8(0x0) 300 LogicalMaximum_i8(0x1) 301 ReportCount(2) 302 ReportSize(8) 303 Input(Var|Abs) 304 // Bytes 4-7 are the button state for 19 buttons + pad out to u32 305 // We send the first 10 buttons as buttons 1-10 which is BTN_0 -> BTN_9 306 UsagePage_Button 307 UsageMinimum_i8(1) 308 UsageMaximum_i8(10) 309 LogicalMinimum_i8(0x0) 310 LogicalMaximum_i8(0x1) 311 ReportCount(10) 312 ReportSize(1) 313 Input(Var|Abs) 314 // We send the other 9 buttons as buttons 0x31 and above -> BTN_A - BTN_TL2 315 UsageMinimum_i8(0x31) 316 UsageMaximum_i8(0x3a) 317 ReportCount(9) 318 ReportSize(1) 319 Input(Var|Abs) 320 ReportCount(13) 321 ReportSize(1) 322 Input(Const) // padding 323 // Byte 8 is the wheel 324 UsagePage_GenericDesktop 325 Usage_GD_Wheel 326 LogicalMinimum_i8(-1) 327 LogicalMaximum_i8(1) 328 ReportCount(1) 329 ReportSize(8) 330 Input(Var|Rel) 331 ) 332 // Make sure we match our original report length 333 FixedSizeVendorReport(BT_PAD_KBD_REPORT_LENGTH) 334 ) 335 }; 336 337 SEC(HID_BPF_RDESC_FIXUP) 338 int BPF_PROG(k20_bt_fix_rdesc, struct hid_bpf_ctx *hctx) 339 { 340 __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); 341 __s32 rdesc_size = hctx->size; 342 343 if (!data) 344 return 0; /* EPERM check */ 345 346 if (rdesc_size == BT_PAD_REPORT_DESCRIPTOR_LENGTH) { 347 __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad)); 348 return sizeof(fixed_rdesc_pad); 349 } 350 if (rdesc_size == BT_PUCK_REPORT_DESCRIPTOR_LENGTH) { 351 // This hidraw node doesn't send anything and can be ignored 352 __builtin_memcpy(data, disabled_rdesc_puck, sizeof(disabled_rdesc_puck)); 353 return sizeof(disabled_rdesc_puck); 354 } 355 356 return 0; 357 } 358 359 SEC(HID_BPF_DEVICE_EVENT) 360 int BPF_PROG(k20_bt_fix_events, struct hid_bpf_ctx *hctx) 361 { 362 __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 12 /* size */); 363 struct pad_report { 364 __u8 report_id; 365 __u8 btn_stylus:1; 366 __u8 pad:7; 367 __u8 x; 368 __u8 y; 369 __u32 buttons; 370 __u8 wheel; 371 } __packed * pad_report = (struct pad_report *)data; 372 373 if (!data) 374 return 0; /* EPERM check */ 375 376 /* Report ID 1 - Keyboard events (button presses) */ 377 if (data[0] == BT_PAD_KBD_REPORT_ID) { 378 const __u8 button_mapping[] = { 379 0x0e, /* Button 1: K */ 380 0x0a, /* Button 2: G */ 381 0x0f, /* Button 3: L */ 382 0x4c, /* Button 4: Delete */ 383 0x0c, /* Button 5: I */ 384 0x07, /* Button 6: D */ 385 0x05, /* Button 7: B */ 386 0x08, /* Button 8: E */ 387 0x16, /* Button 9: S */ 388 0x1d, /* Button 10: Z */ 389 0x06, /* Button 11: C */ 390 0x19, /* Button 12: V */ 391 0xff, /* Button 13: LeftControl */ 392 0xff, /* Button 14: LeftAlt */ 393 0xff, /* Button 15: LeftShift */ 394 0x28, /* Button 16: Return Enter */ 395 0x2c, /* Button 17: Spacebar */ 396 0x11, /* Button 18: N */ 397 }; 398 399 __u8 modifiers = data[1]; 400 __u32 buttons = 0; 401 402 if (modifiers & 0x01) { /* Control */ 403 buttons |= BIT(12); 404 } 405 if (modifiers & 0x02) { /* Shift */ 406 buttons |= BIT(14); 407 } 408 if (modifiers & 0x04) { /* Alt */ 409 buttons |= BIT(13); 410 } 411 412 for (int i = 4; i < BT_PAD_KBD_REPORT_LENGTH; i++) { 413 if (!data[i]) 414 break; 415 416 for (size_t b = 0; b < ARRAY_SIZE(button_mapping); b++) { 417 if (data[i] != 0xff && data[i] == button_mapping[b]) { 418 buttons |= BIT(b); 419 break; 420 } 421 } 422 } 423 424 last_button_state = buttons; 425 426 pad_report->report_id = OUR_REPORT_ID; 427 pad_report->btn_stylus = 0; 428 pad_report->x = 0; 429 pad_report->y = 0; 430 pad_report->buttons = buttons; 431 pad_report->wheel = 0; 432 433 return sizeof(struct pad_report); 434 } 435 436 /* Report ID 2 - Consumer control events (the button inside the wheel) */ 437 if (data[0] == BT_PAD_CC_REPORT_ID) { 438 const __u8 PlayPause = 0xcd; 439 440 if (data[1] == PlayPause) 441 last_button_state |= BIT(18); 442 else 443 last_button_state &= ~BIT(18); 444 445 pad_report->report_id = OUR_REPORT_ID; 446 pad_report->btn_stylus = 0; 447 pad_report->x = 0; 448 pad_report->y = 0; 449 pad_report->buttons = last_button_state; 450 pad_report->wheel = 0; 451 452 return sizeof(struct pad_report); 453 } 454 455 /* Report ID 5 - Mouse events (wheel rotation) */ 456 if (data[0] == BT_PAD_MOUSE_REPORT_ID) { 457 __u8 wheel_delta = data[6]; 458 459 pad_report->report_id = OUR_REPORT_ID; 460 pad_report->btn_stylus = 0; 461 pad_report->x = 0; 462 pad_report->y = 0; 463 pad_report->buttons = last_button_state; 464 pad_report->wheel = wheel_delta; 465 466 return sizeof(struct pad_report); 467 } 468 469 return 0; 470 } 471 472 HID_BPF_OPS(keydial_k20_bluetooth) = { 473 .hid_device_event = (void *)k20_bt_fix_events, 474 .hid_rdesc_fixup = (void *)k20_bt_fix_rdesc, 475 }; 476 477 SEC("syscall") 478 int probe(struct hid_bpf_probe_args *ctx) 479 { 480 switch (ctx->rdesc_size) { 481 case BT_PAD_REPORT_DESCRIPTOR_LENGTH: 482 case BT_PUCK_REPORT_DESCRIPTOR_LENGTH: 483 ctx->retval = 0; 484 break; 485 default: 486 ctx->retval = -EINVAL; 487 } 488 489 return 0; 490 } 491 492 char _license[] SEC("license") = "GPL"; 493