xref: /linux/drivers/hid/hid-appletb-kbd.c (revision 5d7f3375cd574fc83f0cd30839b21455c0e79ae2)
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