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 = from_timer(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, jiffies + msecs_to_jiffies(appletb_tb_idle_timeout * 1000)); 176 } else if (!kbd->has_turned_off) { 177 backlight_device_set_brightness(kbd->backlight_dev, 0); 178 kbd->has_turned_off = true; 179 } 180 } 181 } 182 183 static void reset_inactivity_timer(struct appletb_kbd *kbd) 184 { 185 if (kbd->backlight_dev && appletb_tb_autodim) { 186 if (kbd->has_dimmed || kbd->has_turned_off) { 187 backlight_device_set_brightness(kbd->backlight_dev, 2); 188 kbd->has_dimmed = false; 189 kbd->has_turned_off = false; 190 } 191 mod_timer(&kbd->inactivity_timer, jiffies + msecs_to_jiffies(appletb_tb_dim_timeout * 1000)); 192 } 193 } 194 195 static int appletb_kbd_hid_event(struct hid_device *hdev, struct hid_field *field, 196 struct hid_usage *usage, __s32 value) 197 { 198 struct appletb_kbd *kbd = hid_get_drvdata(hdev); 199 struct key_entry *translation; 200 struct input_dev *input; 201 int slot; 202 203 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_KEYBOARD || usage->type != EV_KEY) 204 return 0; 205 206 input = field->hidinput->input; 207 208 /* 209 * Skip non-touch-bar keys. 210 * 211 * Either the touch bar itself or usbhid generate a slew of key-down 212 * events for all the meta keys. None of which we're at all interested 213 * in. 214 */ 215 slot = appletb_tb_key_to_slot(usage->code); 216 if (slot < 0) 217 return 0; 218 219 reset_inactivity_timer(kbd); 220 221 translation = sparse_keymap_entry_from_scancode(input, usage->code); 222 223 if (translation && kbd->current_mode == APPLETB_KBD_MODE_SPCL) { 224 input_event(input, usage->type, translation->keycode, value); 225 226 return 1; 227 } 228 229 return kbd->current_mode == APPLETB_KBD_MODE_OFF; 230 } 231 232 static void appletb_kbd_inp_event(struct input_handle *handle, unsigned int type, 233 unsigned int code, int value) 234 { 235 struct appletb_kbd *kbd = handle->private; 236 237 reset_inactivity_timer(kbd); 238 239 if (type == EV_KEY && code == KEY_FN && appletb_tb_fn_toggle && 240 (kbd->current_mode == APPLETB_KBD_MODE_SPCL || 241 kbd->current_mode == APPLETB_KBD_MODE_FN)) { 242 if (value == 1) { 243 kbd->saved_mode = kbd->current_mode; 244 appletb_kbd_set_mode(kbd, kbd->current_mode == APPLETB_KBD_MODE_SPCL 245 ? APPLETB_KBD_MODE_FN : APPLETB_KBD_MODE_SPCL); 246 } else if (value == 0) { 247 if (kbd->saved_mode != kbd->current_mode) 248 appletb_kbd_set_mode(kbd, kbd->saved_mode); 249 } 250 } 251 } 252 253 static int appletb_kbd_inp_connect(struct input_handler *handler, 254 struct input_dev *dev, 255 const struct input_device_id *id) 256 { 257 struct appletb_kbd *kbd = handler->private; 258 struct input_handle *handle; 259 int rc; 260 261 if (id->driver_info == APPLETB_DEVID_KEYBOARD) { 262 handle = &kbd->kbd_handle; 263 handle->name = "tbkbd"; 264 } else if (id->driver_info == APPLETB_DEVID_TRACKPAD) { 265 handle = &kbd->tpd_handle; 266 handle->name = "tbtpd"; 267 } else { 268 return -ENOENT; 269 } 270 271 if (handle->dev) 272 return -EEXIST; 273 274 handle->open = 0; 275 handle->dev = input_get_device(dev); 276 handle->handler = handler; 277 handle->private = kbd; 278 279 rc = input_register_handle(handle); 280 if (rc) 281 goto err_free_dev; 282 283 rc = input_open_device(handle); 284 if (rc) 285 goto err_unregister_handle; 286 287 return 0; 288 289 err_unregister_handle: 290 input_unregister_handle(handle); 291 err_free_dev: 292 input_put_device(handle->dev); 293 handle->dev = NULL; 294 return rc; 295 } 296 297 static void appletb_kbd_inp_disconnect(struct input_handle *handle) 298 { 299 input_close_device(handle); 300 input_unregister_handle(handle); 301 302 input_put_device(handle->dev); 303 handle->dev = NULL; 304 } 305 306 static int appletb_kbd_input_configured(struct hid_device *hdev, struct hid_input *hidinput) 307 { 308 int idx; 309 struct input_dev *input = hidinput->input; 310 311 /* 312 * Clear various input capabilities that are blindly set by the hid 313 * driver (usbkbd.c) 314 */ 315 memset(input->evbit, 0, sizeof(input->evbit)); 316 memset(input->keybit, 0, sizeof(input->keybit)); 317 memset(input->ledbit, 0, sizeof(input->ledbit)); 318 319 __set_bit(EV_REP, input->evbit); 320 321 sparse_keymap_setup(input, appletb_kbd_keymap, NULL); 322 323 for (idx = 0; appletb_kbd_keymap[idx].type != KE_END; idx++) 324 input_set_capability(input, EV_KEY, appletb_kbd_keymap[idx].code); 325 326 return 0; 327 } 328 329 static const struct input_device_id appletb_kbd_input_devices[] = { 330 { 331 .flags = INPUT_DEVICE_ID_MATCH_BUS | 332 INPUT_DEVICE_ID_MATCH_VENDOR | 333 INPUT_DEVICE_ID_MATCH_KEYBIT, 334 .bustype = BUS_USB, 335 .vendor = USB_VENDOR_ID_APPLE, 336 .keybit = { [BIT_WORD(KEY_FN)] = BIT_MASK(KEY_FN) }, 337 .driver_info = APPLETB_DEVID_KEYBOARD, 338 }, 339 { 340 .flags = INPUT_DEVICE_ID_MATCH_BUS | 341 INPUT_DEVICE_ID_MATCH_VENDOR | 342 INPUT_DEVICE_ID_MATCH_KEYBIT, 343 .bustype = BUS_USB, 344 .vendor = USB_VENDOR_ID_APPLE, 345 .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, 346 .driver_info = APPLETB_DEVID_TRACKPAD, 347 }, 348 { } 349 }; 350 351 static bool appletb_kbd_match_internal_device(struct input_handler *handler, 352 struct input_dev *inp_dev) 353 { 354 struct device *dev = &inp_dev->dev; 355 356 /* in kernel: dev && !is_usb_device(dev) */ 357 while (dev && !(dev->type && dev->type->name && 358 !strcmp(dev->type->name, "usb_device"))) 359 dev = dev->parent; 360 361 /* 362 * Apple labels all their internal keyboards and trackpads as such, 363 * instead of maintaining an ever expanding list of product-id's we 364 * just look at the device's product name. 365 */ 366 if (dev) 367 return !!strstr(to_usb_device(dev)->product, "Internal Keyboard"); 368 369 return false; 370 } 371 372 static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id *id) 373 { 374 struct appletb_kbd *kbd; 375 struct device *dev = &hdev->dev; 376 struct hid_field *mode_field; 377 int ret; 378 379 ret = hid_parse(hdev); 380 if (ret) 381 return dev_err_probe(dev, ret, "HID parse failed\n"); 382 383 mode_field = hid_find_field(hdev, HID_OUTPUT_REPORT, 384 HID_GD_KEYBOARD, HID_USAGE_MODE); 385 if (!mode_field) 386 return -ENODEV; 387 388 kbd = devm_kzalloc(dev, sizeof(*kbd), GFP_KERNEL); 389 if (!kbd) 390 return -ENOMEM; 391 392 kbd->mode_field = mode_field; 393 394 ret = hid_hw_start(hdev, HID_CONNECT_HIDINPUT); 395 if (ret) 396 return dev_err_probe(dev, ret, "HID hw start failed\n"); 397 398 ret = hid_hw_open(hdev); 399 if (ret) { 400 dev_err_probe(dev, ret, "HID hw open failed\n"); 401 goto stop_hw; 402 } 403 404 kbd->backlight_dev = backlight_device_get_by_name("appletb_backlight"); 405 if (!kbd->backlight_dev) { 406 dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n"); 407 } else { 408 backlight_device_set_brightness(kbd->backlight_dev, 2); 409 timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0); 410 mod_timer(&kbd->inactivity_timer, jiffies + msecs_to_jiffies(appletb_tb_dim_timeout * 1000)); 411 } 412 413 kbd->inp_handler.event = appletb_kbd_inp_event; 414 kbd->inp_handler.connect = appletb_kbd_inp_connect; 415 kbd->inp_handler.disconnect = appletb_kbd_inp_disconnect; 416 kbd->inp_handler.name = "appletb"; 417 kbd->inp_handler.id_table = appletb_kbd_input_devices; 418 kbd->inp_handler.match = appletb_kbd_match_internal_device; 419 kbd->inp_handler.private = kbd; 420 421 ret = input_register_handler(&kbd->inp_handler); 422 if (ret) { 423 dev_err_probe(dev, ret, "Unable to register keyboard handler\n"); 424 goto close_hw; 425 } 426 427 ret = appletb_kbd_set_mode(kbd, appletb_tb_def_mode); 428 if (ret) { 429 dev_err_probe(dev, ret, "Failed to set touchbar mode\n"); 430 goto close_hw; 431 } 432 433 hid_set_drvdata(hdev, kbd); 434 435 return 0; 436 437 close_hw: 438 hid_hw_close(hdev); 439 stop_hw: 440 hid_hw_stop(hdev); 441 return ret; 442 } 443 444 static void appletb_kbd_remove(struct hid_device *hdev) 445 { 446 struct appletb_kbd *kbd = hid_get_drvdata(hdev); 447 448 appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); 449 450 input_unregister_handler(&kbd->inp_handler); 451 timer_delete_sync(&kbd->inactivity_timer); 452 453 hid_hw_close(hdev); 454 hid_hw_stop(hdev); 455 } 456 457 #ifdef CONFIG_PM 458 static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg) 459 { 460 struct appletb_kbd *kbd = hid_get_drvdata(hdev); 461 462 kbd->saved_mode = kbd->current_mode; 463 appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); 464 465 return 0; 466 } 467 468 static int appletb_kbd_reset_resume(struct hid_device *hdev) 469 { 470 struct appletb_kbd *kbd = hid_get_drvdata(hdev); 471 472 appletb_kbd_set_mode(kbd, kbd->saved_mode); 473 474 return 0; 475 } 476 #endif 477 478 static const struct hid_device_id appletb_kbd_hid_ids[] = { 479 /* MacBook Pro's 2018, 2019, with T2 chip: iBridge Display */ 480 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) }, 481 { } 482 }; 483 MODULE_DEVICE_TABLE(hid, appletb_kbd_hid_ids); 484 485 static struct hid_driver appletb_kbd_hid_driver = { 486 .name = "hid-appletb-kbd", 487 .id_table = appletb_kbd_hid_ids, 488 .probe = appletb_kbd_probe, 489 .remove = appletb_kbd_remove, 490 .event = appletb_kbd_hid_event, 491 .input_configured = appletb_kbd_input_configured, 492 #ifdef CONFIG_PM 493 .suspend = appletb_kbd_suspend, 494 .reset_resume = appletb_kbd_reset_resume, 495 #endif 496 .driver.dev_groups = appletb_kbd_groups, 497 }; 498 module_hid_driver(appletb_kbd_hid_driver); 499 500 /* The backlight driver should be loaded before the keyboard driver is initialised */ 501 MODULE_SOFTDEP("pre: hid_appletb_bl"); 502 503 MODULE_AUTHOR("Ronald Tschalär"); 504 MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>"); 505 MODULE_AUTHOR("Aditya Garg <gargaditya08@live.com>"); 506 MODULE_DESCRIPTION("MacBook Pro Touch Bar Keyboard Mode driver"); 507 MODULE_LICENSE("GPL"); 508