1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Apple Touch Bar Keyboard Mode Driver 4 * 5 * Copyright (c) 2017-2018 Ronald Tschalär 6 * Copyright (c) 2022-2023 Kerem Karabay <kekrby@gmail.com> 7 * Copyright (c) 2024-2025 Aditya Garg <gargaditya08@live.com> 8 */ 9 10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 12 #include <linux/hid.h> 13 #include <linux/usb.h> 14 #include <linux/input.h> 15 #include <linux/sysfs.h> 16 #include <linux/bitops.h> 17 #include <linux/module.h> 18 #include <linux/string.h> 19 #include <linux/backlight.h> 20 #include <linux/workqueue.h> 21 #include <linux/input/sparse-keymap.h> 22 23 #include "hid-ids.h" 24 25 #define APPLETB_KBD_MODE_ESC 0 26 #define APPLETB_KBD_MODE_FN 1 27 #define APPLETB_KBD_MODE_SPCL 2 28 #define APPLETB_KBD_MODE_OFF 3 29 #define APPLETB_KBD_MODE_MAX APPLETB_KBD_MODE_OFF 30 31 #define APPLETB_DEVID_KEYBOARD 1 32 #define APPLETB_DEVID_TRACKPAD 2 33 34 #define HID_USAGE_MODE 0x00ff0004 35 36 static int appletb_tb_def_mode = APPLETB_KBD_MODE_SPCL; 37 module_param_named(mode, appletb_tb_def_mode, int, 0444); 38 MODULE_PARM_DESC(mode, "Default touchbar mode:\n" 39 " 0 - escape key only\n" 40 " 1 - function-keys\n" 41 " [2] - special keys"); 42 43 static bool appletb_tb_fn_toggle = true; 44 module_param_named(fntoggle, appletb_tb_fn_toggle, bool, 0644); 45 MODULE_PARM_DESC(fntoggle, "Switch between Fn and media controls on pressing Fn key"); 46 47 static bool appletb_tb_autodim = true; 48 module_param_named(autodim, appletb_tb_autodim, bool, 0644); 49 MODULE_PARM_DESC(autodim, "Automatically dim and turn off the Touch Bar after some time"); 50 51 static int appletb_tb_dim_timeout = 60; 52 module_param_named(dim_timeout, appletb_tb_dim_timeout, int, 0644); 53 MODULE_PARM_DESC(dim_timeout, "Dim timeout in sec"); 54 55 static int appletb_tb_idle_timeout = 15; 56 module_param_named(idle_timeout, appletb_tb_idle_timeout, int, 0644); 57 MODULE_PARM_DESC(idle_timeout, "Idle timeout in sec"); 58 59 static int appletb_tb_double_press_switch_time; 60 module_param_named(double_press_switch_time, 61 appletb_tb_double_press_switch_time, int, 0644); 62 MODULE_PARM_DESC(double_press_switch_time, 63 "Fn double-press interval in ms (0 disables layer switching)"); 64 65 struct appletb_kbd { 66 struct hid_field *mode_field; 67 struct input_handler inp_handler; 68 struct input_handle kbd_handle; 69 struct input_handle tpd_handle; 70 struct backlight_device *backlight_dev; 71 struct delayed_work inactivity_work; 72 struct work_struct restore_brightness_work; 73 bool has_dimmed; 74 bool has_turned_off; 75 u8 saved_mode; 76 u8 current_mode; 77 unsigned long last_fn_press; 78 }; 79 80 static const struct key_entry appletb_kbd_keymap[] = { 81 { KE_KEY, KEY_ESC, { KEY_ESC } }, 82 { KE_KEY, KEY_F1, { KEY_BRIGHTNESSDOWN } }, 83 { KE_KEY, KEY_F2, { KEY_BRIGHTNESSUP } }, 84 { KE_KEY, KEY_F3, { KEY_RESERVED } }, 85 { KE_KEY, KEY_F4, { KEY_RESERVED } }, 86 { KE_KEY, KEY_F5, { KEY_KBDILLUMDOWN } }, 87 { KE_KEY, KEY_F6, { KEY_KBDILLUMUP } }, 88 { KE_KEY, KEY_F7, { KEY_PREVIOUSSONG } }, 89 { KE_KEY, KEY_F8, { KEY_PLAYPAUSE } }, 90 { KE_KEY, KEY_F9, { KEY_NEXTSONG } }, 91 { KE_KEY, KEY_F10, { KEY_MUTE } }, 92 { KE_KEY, KEY_F11, { KEY_VOLUMEDOWN } }, 93 { KE_KEY, KEY_F12, { KEY_VOLUMEUP } }, 94 { KE_END, 0 } 95 }; 96 97 static int appletb_kbd_set_mode_active(struct appletb_kbd *kbd, u8 mode) 98 { 99 struct hid_report *report = kbd->mode_field->report; 100 struct hid_device *hdev = report->device; 101 int ret; 102 103 ret = hid_set_field(kbd->mode_field, 0, mode); 104 if (ret) { 105 hid_err(hdev, "Failed to set mode field to %u (%pe)\n", mode, ERR_PTR(ret)); 106 return ret; 107 } 108 109 hid_hw_request(hdev, report, HID_REQ_SET_REPORT); 110 111 kbd->current_mode = mode; 112 return 0; 113 } 114 115 static int appletb_kbd_set_mode(struct appletb_kbd *kbd, u8 mode) 116 { 117 struct hid_device *hdev = kbd->mode_field->report->device; 118 int ret; 119 120 ret = hid_hw_power(hdev, PM_HINT_FULLON); 121 if (ret) { 122 hid_err(hdev, "Device didn't resume (%pe)\n", ERR_PTR(ret)); 123 return ret; 124 } 125 126 ret = appletb_kbd_set_mode_active(kbd, mode); 127 128 hid_hw_power(hdev, PM_HINT_NORMAL); 129 130 return ret; 131 } 132 133 static ssize_t mode_show(struct device *dev, 134 struct device_attribute *attr, char *buf) 135 { 136 struct appletb_kbd *kbd = dev_get_drvdata(dev); 137 138 return sysfs_emit(buf, "%d\n", kbd->current_mode); 139 } 140 141 static ssize_t mode_store(struct device *dev, 142 struct device_attribute *attr, 143 const char *buf, size_t size) 144 { 145 struct appletb_kbd *kbd = dev_get_drvdata(dev); 146 u8 mode; 147 int ret; 148 149 ret = kstrtou8(buf, 0, &mode); 150 if (ret) 151 return ret; 152 153 if (mode > APPLETB_KBD_MODE_MAX) 154 return -EINVAL; 155 156 ret = appletb_kbd_set_mode(kbd, mode); 157 158 return ret < 0 ? ret : size; 159 } 160 static DEVICE_ATTR_RW(mode); 161 162 static struct attribute *appletb_kbd_attrs[] = { 163 &dev_attr_mode.attr, 164 NULL 165 }; 166 ATTRIBUTE_GROUPS(appletb_kbd); 167 168 static int appletb_tb_key_to_slot(unsigned int code) 169 { 170 switch (code) { 171 case KEY_ESC: 172 return 0; 173 case KEY_F1 ... KEY_F10: 174 return code - KEY_F1 + 1; 175 case KEY_F11 ... KEY_F12: 176 return code - KEY_F11 + 11; 177 178 default: 179 return -EINVAL; 180 } 181 } 182 183 static void appletb_inactivity_work(struct work_struct *work) 184 { 185 struct appletb_kbd *kbd = container_of(to_delayed_work(work), 186 struct appletb_kbd, 187 inactivity_work); 188 189 if (kbd->backlight_dev && appletb_tb_autodim) { 190 if (!kbd->has_dimmed) { 191 backlight_device_set_brightness(kbd->backlight_dev, 1); 192 kbd->has_dimmed = true; 193 mod_delayed_work(system_dfl_wq, &kbd->inactivity_work, 194 secs_to_jiffies(appletb_tb_idle_timeout)); 195 } else if (!kbd->has_turned_off) { 196 backlight_device_set_brightness(kbd->backlight_dev, 0); 197 kbd->has_turned_off = true; 198 } 199 } 200 } 201 202 static void appletb_restore_brightness_work(struct work_struct *work) 203 { 204 struct appletb_kbd *kbd = container_of(work, struct appletb_kbd, 205 restore_brightness_work); 206 207 if (kbd->backlight_dev) 208 backlight_device_set_brightness(kbd->backlight_dev, 2); 209 } 210 211 static void reset_inactivity_timer(struct appletb_kbd *kbd) 212 { 213 if (kbd->backlight_dev && appletb_tb_autodim) { 214 if (kbd->has_dimmed || kbd->has_turned_off) { 215 kbd->has_dimmed = false; 216 kbd->has_turned_off = false; 217 schedule_work(&kbd->restore_brightness_work); 218 } 219 mod_delayed_work(system_dfl_wq, &kbd->inactivity_work, 220 secs_to_jiffies(appletb_tb_dim_timeout)); 221 } 222 } 223 224 static int appletb_kbd_hid_event(struct hid_device *hdev, struct hid_field *field, 225 struct hid_usage *usage, __s32 value) 226 { 227 struct appletb_kbd *kbd = hid_get_drvdata(hdev); 228 struct key_entry *translation; 229 struct input_dev *input; 230 int slot; 231 232 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_KEYBOARD || usage->type != EV_KEY) 233 return 0; 234 235 input = field->hidinput->input; 236 237 /* 238 * Skip non-touch-bar keys. 239 * 240 * Either the touch bar itself or usbhid generate a slew of key-down 241 * events for all the meta keys. None of which we're at all interested 242 * in. 243 */ 244 slot = appletb_tb_key_to_slot(usage->code); 245 if (slot < 0) 246 return 0; 247 248 reset_inactivity_timer(kbd); 249 250 translation = sparse_keymap_entry_from_scancode(input, usage->code); 251 252 if (translation && kbd->current_mode == APPLETB_KBD_MODE_SPCL) { 253 input_event(input, usage->type, translation->keycode, value); 254 255 return 1; 256 } 257 258 return kbd->current_mode == APPLETB_KBD_MODE_OFF; 259 } 260 261 static u8 appletb_switch_mode(u8 mode) 262 { 263 switch (mode) { 264 case APPLETB_KBD_MODE_SPCL: 265 return APPLETB_KBD_MODE_FN; 266 case APPLETB_KBD_MODE_FN: 267 return APPLETB_KBD_MODE_SPCL; 268 default: 269 return mode; 270 } 271 } 272 273 static void appletb_kbd_inp_event(struct input_handle *handle, unsigned int type, 274 unsigned int code, int value) 275 { 276 struct appletb_kbd *kbd = handle->private; 277 278 reset_inactivity_timer(kbd); 279 280 if (type == EV_KEY && code == KEY_FN && 281 (kbd->current_mode == APPLETB_KBD_MODE_SPCL || 282 kbd->current_mode == APPLETB_KBD_MODE_FN)) { 283 if (value == 1) { 284 if (appletb_tb_double_press_switch_time > 0) { 285 unsigned long now = jiffies; 286 287 if (time_before(now, kbd->last_fn_press + 288 msecs_to_jiffies(appletb_tb_double_press_switch_time))) { 289 appletb_tb_def_mode = 290 appletb_switch_mode(appletb_tb_def_mode); 291 292 appletb_kbd_set_mode(kbd, appletb_tb_def_mode); 293 294 kbd->saved_mode = appletb_tb_def_mode; 295 kbd->last_fn_press = 0; 296 297 return; 298 } 299 300 kbd->last_fn_press = now; 301 } 302 if (appletb_tb_fn_toggle) { 303 kbd->saved_mode = kbd->current_mode; 304 305 appletb_kbd_set_mode(kbd, appletb_switch_mode(kbd->current_mode)); 306 } 307 } else if (value == 0) { 308 if (appletb_tb_fn_toggle && 309 kbd->saved_mode != kbd->current_mode) 310 appletb_kbd_set_mode(kbd, kbd->saved_mode); 311 } 312 } 313 } 314 315 static int appletb_kbd_inp_connect(struct input_handler *handler, 316 struct input_dev *dev, 317 const struct input_device_id *id) 318 { 319 struct appletb_kbd *kbd = handler->private; 320 struct input_handle *handle; 321 int rc; 322 323 if (id->driver_info == APPLETB_DEVID_KEYBOARD) { 324 handle = &kbd->kbd_handle; 325 handle->name = "tbkbd"; 326 } else if (id->driver_info == APPLETB_DEVID_TRACKPAD) { 327 handle = &kbd->tpd_handle; 328 handle->name = "tbtpd"; 329 } else { 330 return -ENOENT; 331 } 332 333 if (handle->dev) 334 return -EEXIST; 335 336 handle->open = 0; 337 handle->dev = input_get_device(dev); 338 handle->handler = handler; 339 handle->private = kbd; 340 341 rc = input_register_handle(handle); 342 if (rc) 343 goto err_free_dev; 344 345 rc = input_open_device(handle); 346 if (rc) 347 goto err_unregister_handle; 348 349 return 0; 350 351 err_unregister_handle: 352 input_unregister_handle(handle); 353 err_free_dev: 354 input_put_device(handle->dev); 355 handle->dev = NULL; 356 return rc; 357 } 358 359 static void appletb_kbd_inp_disconnect(struct input_handle *handle) 360 { 361 input_close_device(handle); 362 input_unregister_handle(handle); 363 364 input_put_device(handle->dev); 365 handle->dev = NULL; 366 } 367 368 static int appletb_kbd_input_configured(struct hid_device *hdev, struct hid_input *hidinput) 369 { 370 int idx; 371 struct input_dev *input = hidinput->input; 372 373 /* 374 * Clear various input capabilities that are blindly set by the hid 375 * driver (usbkbd.c) 376 */ 377 memset(input->evbit, 0, sizeof(input->evbit)); 378 memset(input->keybit, 0, sizeof(input->keybit)); 379 memset(input->ledbit, 0, sizeof(input->ledbit)); 380 381 __set_bit(EV_REP, input->evbit); 382 383 sparse_keymap_setup(input, appletb_kbd_keymap, NULL); 384 385 for (idx = 0; appletb_kbd_keymap[idx].type != KE_END; idx++) 386 input_set_capability(input, EV_KEY, appletb_kbd_keymap[idx].code); 387 388 return 0; 389 } 390 391 static const struct input_device_id appletb_kbd_input_devices[] = { 392 { 393 .flags = INPUT_DEVICE_ID_MATCH_BUS | 394 INPUT_DEVICE_ID_MATCH_VENDOR | 395 INPUT_DEVICE_ID_MATCH_KEYBIT, 396 .bustype = BUS_USB, 397 .vendor = USB_VENDOR_ID_APPLE, 398 .keybit = { [BIT_WORD(KEY_FN)] = BIT_MASK(KEY_FN) }, 399 .driver_info = APPLETB_DEVID_KEYBOARD, 400 }, 401 { 402 .flags = INPUT_DEVICE_ID_MATCH_BUS | 403 INPUT_DEVICE_ID_MATCH_VENDOR | 404 INPUT_DEVICE_ID_MATCH_KEYBIT, 405 .bustype = BUS_USB, 406 .vendor = USB_VENDOR_ID_APPLE, 407 .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, 408 .driver_info = APPLETB_DEVID_TRACKPAD, 409 }, 410 { } 411 }; 412 413 static bool appletb_kbd_match_internal_device(struct input_handler *handler, 414 struct input_dev *inp_dev) 415 { 416 struct device *dev = &inp_dev->dev; 417 418 /* in kernel: dev && !is_usb_device(dev) */ 419 while (dev && !(dev->type && dev->type->name && 420 !strcmp(dev->type->name, "usb_device"))) 421 dev = dev->parent; 422 423 /* 424 * Apple labels all their internal keyboards and trackpads as such, 425 * instead of maintaining an ever expanding list of product-id's we 426 * just look at the device's product name. 427 */ 428 if (dev) 429 return !!strstr(to_usb_device(dev)->product, "Internal Keyboard"); 430 431 return false; 432 } 433 434 static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id *id) 435 { 436 struct appletb_kbd *kbd; 437 struct device *dev = &hdev->dev; 438 struct hid_field *mode_field; 439 int ret; 440 441 ret = hid_parse(hdev); 442 if (ret) 443 return dev_err_probe(dev, ret, "HID parse failed\n"); 444 445 mode_field = hid_find_field(hdev, HID_OUTPUT_REPORT, 446 HID_GD_KEYBOARD, HID_USAGE_MODE); 447 if (!mode_field) 448 return -ENODEV; 449 450 kbd = devm_kzalloc(dev, sizeof(*kbd), GFP_KERNEL); 451 if (!kbd) 452 return -ENOMEM; 453 454 kbd->mode_field = mode_field; 455 456 ret = hid_hw_start(hdev, HID_CONNECT_HIDINPUT); 457 if (ret) 458 return dev_err_probe(dev, ret, "HID hw start failed\n"); 459 460 ret = hid_hw_open(hdev); 461 if (ret) { 462 dev_err_probe(dev, ret, "HID hw open failed\n"); 463 goto stop_hw; 464 } 465 466 kbd->backlight_dev = backlight_device_get_by_name("appletb_backlight"); 467 if (!kbd->backlight_dev) { 468 dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n"); 469 } else { 470 backlight_device_set_brightness(kbd->backlight_dev, 2); 471 INIT_DELAYED_WORK(&kbd->inactivity_work, appletb_inactivity_work); 472 INIT_WORK(&kbd->restore_brightness_work, 473 appletb_restore_brightness_work); 474 mod_delayed_work(system_dfl_wq, &kbd->inactivity_work, 475 secs_to_jiffies(appletb_tb_dim_timeout)); 476 } 477 478 kbd->inp_handler.event = appletb_kbd_inp_event; 479 kbd->inp_handler.connect = appletb_kbd_inp_connect; 480 kbd->inp_handler.disconnect = appletb_kbd_inp_disconnect; 481 kbd->inp_handler.name = "appletb"; 482 kbd->inp_handler.id_table = appletb_kbd_input_devices; 483 kbd->inp_handler.match = appletb_kbd_match_internal_device; 484 kbd->inp_handler.private = kbd; 485 486 ret = input_register_handler(&kbd->inp_handler); 487 if (ret) { 488 dev_err_probe(dev, ret, "Unable to register keyboard handler\n"); 489 goto close_hw; 490 } 491 492 ret = appletb_kbd_set_mode(kbd, appletb_tb_def_mode); 493 if (ret) { 494 dev_err_probe(dev, ret, "Failed to set touchbar mode\n"); 495 goto unregister_handler; 496 } 497 498 hid_set_drvdata(hdev, kbd); 499 500 return 0; 501 502 unregister_handler: 503 input_unregister_handler(&kbd->inp_handler); 504 close_hw: 505 hid_hw_close(hdev); 506 stop_hw: 507 hid_hw_stop(hdev); 508 if (kbd->backlight_dev) { 509 cancel_delayed_work_sync(&kbd->inactivity_work); 510 cancel_work_sync(&kbd->restore_brightness_work); 511 put_device(&kbd->backlight_dev->dev); 512 } 513 return ret; 514 } 515 516 static void appletb_kbd_remove(struct hid_device *hdev) 517 { 518 struct appletb_kbd *kbd = hid_get_drvdata(hdev); 519 520 appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); 521 522 input_unregister_handler(&kbd->inp_handler); 523 hid_hw_close(hdev); 524 hid_hw_stop(hdev); 525 526 if (kbd->backlight_dev) { 527 cancel_delayed_work_sync(&kbd->inactivity_work); 528 cancel_work_sync(&kbd->restore_brightness_work); 529 put_device(&kbd->backlight_dev->dev); 530 } 531 } 532 533 static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg) 534 { 535 struct appletb_kbd *kbd = hid_get_drvdata(hdev); 536 537 kbd->saved_mode = kbd->current_mode; 538 539 /* This callback already runs as part of a USB PM transition. Taking a 540 * nested runtime-PM reference would wait for that transition to complete 541 * and deadlock the USB PM state machine. 542 */ 543 return appletb_kbd_set_mode_active(kbd, APPLETB_KBD_MODE_OFF); 544 } 545 546 static int appletb_kbd_resume(struct hid_device *hdev) 547 { 548 struct appletb_kbd *kbd = hid_get_drvdata(hdev); 549 550 return appletb_kbd_set_mode_active(kbd, kbd->saved_mode); 551 } 552 553 static const struct hid_device_id appletb_kbd_hid_ids[] = { 554 /* MacBook Pro's 2018, 2019, with T2 chip: iBridge Display */ 555 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, 556 { } 557 }; 558 MODULE_DEVICE_TABLE(hid, appletb_kbd_hid_ids); 559 560 static struct hid_driver appletb_kbd_hid_driver = { 561 .name = "hid-appletb-kbd", 562 .id_table = appletb_kbd_hid_ids, 563 .probe = appletb_kbd_probe, 564 .remove = appletb_kbd_remove, 565 .event = appletb_kbd_hid_event, 566 .input_configured = appletb_kbd_input_configured, 567 .suspend = pm_ptr(appletb_kbd_suspend), 568 .resume = pm_ptr(appletb_kbd_resume), 569 .reset_resume = pm_ptr(appletb_kbd_resume), 570 .driver.dev_groups = appletb_kbd_groups, 571 }; 572 module_hid_driver(appletb_kbd_hid_driver); 573 574 /* The backlight driver should be loaded before the keyboard driver is initialised */ 575 MODULE_SOFTDEP("pre: hid_appletb_bl"); 576 577 MODULE_AUTHOR("Ronald Tschalär"); 578 MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>"); 579 MODULE_AUTHOR("Aditya Garg <gargaditya08@live.com>"); 580 MODULE_DESCRIPTION("MacBook Pro Touch Bar Keyboard Mode driver"); 581 MODULE_LICENSE("GPL"); 582