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