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