Skip to content

Commit a07ead3

Browse files
author
Benjamin Tissoires
committed
Merge branch 'for-6.11/apple' into for-linus
Add support for the magic keyboard backlight (Orlando Chamberlain)
2 parents 3c69140 + 394ba61 commit a07ead3

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

drivers/hid/hid-apple.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
* Copyright (c) 2006-2007 Jiri Kosina
99
* Copyright (c) 2008 Jiri Slaby <[email protected]>
1010
* Copyright (c) 2019 Paul Pawlowski <[email protected]>
11+
* Copyright (c) 2023 Orlando Chamberlain <[email protected]>
12+
* Copyright (c) 2024 Aditya Garg <[email protected]>
1113
*/
1214

1315
/*
@@ -23,6 +25,7 @@
2325
#include <linux/timer.h>
2426
#include <linux/string.h>
2527
#include <linux/leds.h>
28+
#include <dt-bindings/leds/common.h>
2629

2730
#include "hid-ids.h"
2831

@@ -38,12 +41,17 @@
3841
#define APPLE_RDESC_BATTERY BIT(9)
3942
#define APPLE_BACKLIGHT_CTL BIT(10)
4043
#define APPLE_IS_NON_APPLE BIT(11)
44+
#define APPLE_MAGIC_BACKLIGHT BIT(12)
4145

4246
#define APPLE_FLAG_FKEY 0x01
4347

4448
#define HID_COUNTRY_INTERNATIONAL_ISO 13
4549
#define APPLE_BATTERY_TIMEOUT_MS 60000
4650

51+
#define HID_USAGE_MAGIC_BL 0xff00000f
52+
#define APPLE_MAGIC_REPORT_ID_POWER 3
53+
#define APPLE_MAGIC_REPORT_ID_BRIGHTNESS 1
54+
4755
static unsigned int fnmode = 3;
4856
module_param(fnmode, uint, 0644);
4957
MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
@@ -81,6 +89,12 @@ struct apple_sc_backlight {
8189
struct hid_device *hdev;
8290
};
8391

92+
struct apple_magic_backlight {
93+
struct led_classdev cdev;
94+
struct hid_report *brightness;
95+
struct hid_report *power;
96+
};
97+
8498
struct apple_sc {
8599
struct hid_device *hdev;
86100
unsigned long quirks;
@@ -822,6 +836,66 @@ static int apple_backlight_init(struct hid_device *hdev)
822836
return ret;
823837
}
824838

839+
static void apple_magic_backlight_report_set(struct hid_report *rep, s32 value, u8 rate)
840+
{
841+
rep->field[0]->value[0] = value;
842+
rep->field[1]->value[0] = 0x5e; /* Mimic Windows */
843+
rep->field[1]->value[0] |= rate << 8;
844+
845+
hid_hw_request(rep->device, rep, HID_REQ_SET_REPORT);
846+
}
847+
848+
static void apple_magic_backlight_set(struct apple_magic_backlight *backlight,
849+
int brightness, char rate)
850+
{
851+
apple_magic_backlight_report_set(backlight->power, brightness ? 1 : 0, rate);
852+
if (brightness)
853+
apple_magic_backlight_report_set(backlight->brightness, brightness, rate);
854+
}
855+
856+
static int apple_magic_backlight_led_set(struct led_classdev *led_cdev,
857+
enum led_brightness brightness)
858+
{
859+
struct apple_magic_backlight *backlight = container_of(led_cdev,
860+
struct apple_magic_backlight, cdev);
861+
862+
apple_magic_backlight_set(backlight, brightness, 1);
863+
return 0;
864+
}
865+
866+
static int apple_magic_backlight_init(struct hid_device *hdev)
867+
{
868+
struct apple_magic_backlight *backlight;
869+
struct hid_report_enum *report_enum;
870+
871+
/*
872+
* Ensure this usb endpoint is for the keyboard backlight, not touchbar
873+
* backlight.
874+
*/
875+
if (hdev->collection[0].usage != HID_USAGE_MAGIC_BL)
876+
return -ENODEV;
877+
878+
backlight = devm_kzalloc(&hdev->dev, sizeof(*backlight), GFP_KERNEL);
879+
if (!backlight)
880+
return -ENOMEM;
881+
882+
report_enum = &hdev->report_enum[HID_FEATURE_REPORT];
883+
backlight->brightness = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_BRIGHTNESS];
884+
backlight->power = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_POWER];
885+
886+
if (!backlight->brightness || !backlight->power)
887+
return -ENODEV;
888+
889+
backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT;
890+
backlight->cdev.max_brightness = backlight->brightness->field[0]->logical_maximum;
891+
backlight->cdev.brightness_set_blocking = apple_magic_backlight_led_set;
892+
893+
apple_magic_backlight_set(backlight, 0, 0);
894+
895+
return devm_led_classdev_register(&hdev->dev, &backlight->cdev);
896+
897+
}
898+
825899
static int apple_probe(struct hid_device *hdev,
826900
const struct hid_device_id *id)
827901
{
@@ -860,7 +934,18 @@ static int apple_probe(struct hid_device *hdev,
860934
if (quirks & APPLE_BACKLIGHT_CTL)
861935
apple_backlight_init(hdev);
862936

937+
if (quirks & APPLE_MAGIC_BACKLIGHT) {
938+
ret = apple_magic_backlight_init(hdev);
939+
if (ret)
940+
goto out_err;
941+
}
942+
863943
return 0;
944+
945+
out_err:
946+
del_timer_sync(&asc->battery_timer);
947+
hid_hw_stop(hdev);
948+
return ret;
864949
}
865950

866951
static void apple_remove(struct hid_device *hdev)
@@ -1073,6 +1158,8 @@ static const struct hid_device_id apple_devices[] = {
10731158
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
10741159
{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
10751160
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
1161+
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT),
1162+
.driver_data = APPLE_MAGIC_BACKLIGHT },
10761163

10771164
{ }
10781165
};

0 commit comments

Comments
 (0)