Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: apple: Add support for magic keyboard backlight on T2 Macs

Unlike T2 Macs with Butterfly keyboard, who have their keyboard backlight
on the USB device the T2 Macs with Magic keyboard have their backlight on
the Touchbar backlight device (05ac:8102).

Support for Butterfly keyboards has already been added in
commit 9018eacbe623 ("HID: apple: Add support for keyboard backlight on
certain T2 Macs.") This patch adds support for the Magic keyboards.

Signed-off-by: Orlando Chamberlain <orlandoch.dev@gmail.com>
Co-developed-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Aditya Garg <gargaditya08@live.com>
Link: https://patch.msgid.link/E1D444EA-7FD0-42DA-B198-50B0F03298FB@live.com
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>

authored by

Orlando Chamberlain and committed by
Benjamin Tissoires
394ba612 061d1af7

+87
+87
drivers/hid/hid-apple.c
··· 8 8 * Copyright (c) 2006-2007 Jiri Kosina 9 9 * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> 10 10 * Copyright (c) 2019 Paul Pawlowski <paul@mrarm.io> 11 + * Copyright (c) 2023 Orlando Chamberlain <orlandoch.dev@gmail.com> 12 + * Copyright (c) 2024 Aditya Garg <gargaditya08@live.com> 11 13 */ 12 14 13 15 /* ··· 25 23 #include <linux/timer.h> 26 24 #include <linux/string.h> 27 25 #include <linux/leds.h> 26 + #include <dt-bindings/leds/common.h> 28 27 29 28 #include "hid-ids.h" 30 29 ··· 41 38 #define APPLE_RDESC_BATTERY BIT(9) 42 39 #define APPLE_BACKLIGHT_CTL BIT(10) 43 40 #define APPLE_IS_NON_APPLE BIT(11) 41 + #define APPLE_MAGIC_BACKLIGHT BIT(12) 44 42 45 43 #define APPLE_FLAG_FKEY 0x01 46 44 47 45 #define HID_COUNTRY_INTERNATIONAL_ISO 13 48 46 #define APPLE_BATTERY_TIMEOUT_MS 60000 47 + 48 + #define HID_USAGE_MAGIC_BL 0xff00000f 49 + #define APPLE_MAGIC_REPORT_ID_POWER 3 50 + #define APPLE_MAGIC_REPORT_ID_BRIGHTNESS 1 49 51 50 52 static unsigned int fnmode = 3; 51 53 module_param(fnmode, uint, 0644); ··· 87 79 struct apple_sc_backlight { 88 80 struct led_classdev cdev; 89 81 struct hid_device *hdev; 82 + }; 83 + 84 + struct apple_magic_backlight { 85 + struct led_classdev cdev; 86 + struct hid_report *brightness; 87 + struct hid_report *power; 90 88 }; 91 89 92 90 struct apple_sc { ··· 836 822 return ret; 837 823 } 838 824 825 + static void apple_magic_backlight_report_set(struct hid_report *rep, s32 value, u8 rate) 826 + { 827 + rep->field[0]->value[0] = value; 828 + rep->field[1]->value[0] = 0x5e; /* Mimic Windows */ 829 + rep->field[1]->value[0] |= rate << 8; 830 + 831 + hid_hw_request(rep->device, rep, HID_REQ_SET_REPORT); 832 + } 833 + 834 + static void apple_magic_backlight_set(struct apple_magic_backlight *backlight, 835 + int brightness, char rate) 836 + { 837 + apple_magic_backlight_report_set(backlight->power, brightness ? 1 : 0, rate); 838 + if (brightness) 839 + apple_magic_backlight_report_set(backlight->brightness, brightness, rate); 840 + } 841 + 842 + static int apple_magic_backlight_led_set(struct led_classdev *led_cdev, 843 + enum led_brightness brightness) 844 + { 845 + struct apple_magic_backlight *backlight = container_of(led_cdev, 846 + struct apple_magic_backlight, cdev); 847 + 848 + apple_magic_backlight_set(backlight, brightness, 1); 849 + return 0; 850 + } 851 + 852 + static int apple_magic_backlight_init(struct hid_device *hdev) 853 + { 854 + struct apple_magic_backlight *backlight; 855 + struct hid_report_enum *report_enum; 856 + 857 + /* 858 + * Ensure this usb endpoint is for the keyboard backlight, not touchbar 859 + * backlight. 860 + */ 861 + if (hdev->collection[0].usage != HID_USAGE_MAGIC_BL) 862 + return -ENODEV; 863 + 864 + backlight = devm_kzalloc(&hdev->dev, sizeof(*backlight), GFP_KERNEL); 865 + if (!backlight) 866 + return -ENOMEM; 867 + 868 + report_enum = &hdev->report_enum[HID_FEATURE_REPORT]; 869 + backlight->brightness = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_BRIGHTNESS]; 870 + backlight->power = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_POWER]; 871 + 872 + if (!backlight->brightness || !backlight->power) 873 + return -ENODEV; 874 + 875 + backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT; 876 + backlight->cdev.max_brightness = backlight->brightness->field[0]->logical_maximum; 877 + backlight->cdev.brightness_set_blocking = apple_magic_backlight_led_set; 878 + 879 + apple_magic_backlight_set(backlight, 0, 0); 880 + 881 + return devm_led_classdev_register(&hdev->dev, &backlight->cdev); 882 + 883 + } 884 + 839 885 static int apple_probe(struct hid_device *hdev, 840 886 const struct hid_device_id *id) 841 887 { ··· 934 860 if (quirks & APPLE_BACKLIGHT_CTL) 935 861 apple_backlight_init(hdev); 936 862 863 + if (quirks & APPLE_MAGIC_BACKLIGHT) { 864 + ret = apple_magic_backlight_init(hdev); 865 + if (ret) 866 + goto out_err; 867 + } 868 + 937 869 return 0; 870 + 871 + out_err: 872 + del_timer_sync(&asc->battery_timer); 873 + hid_hw_stop(hdev); 874 + return ret; 938 875 } 939 876 940 877 static void apple_remove(struct hid_device *hdev) ··· 1158 1073 .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, 1159 1074 { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), 1160 1075 .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, 1076 + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT), 1077 + .driver_data = APPLE_MAGIC_BACKLIGHT }, 1161 1078 1162 1079 { } 1163 1080 };