Message ID | B3762A0A-1355-4345-9040-AF4E5292F188@live.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Jiri Kosina |
Headers | show |
Series | HID: apple: Add support for magic keyboard backlight on T2 Macs | expand |
Apparently this patch is breaking touchbar functionality is some cases. Jiri we previously had sent this as a separate driver, but you asked us to add it to hid-apple. Do you still think a separate driver is bad? > On 1 Jul 2024, at 4:15 PM, Aditya Garg <gargaditya08@live.com> wrote: > > From: Orlando Chamberlain <orlandoch.dev@gmail.com> > > 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 9018eacbe623 > ("HID: apple: Add support for keyboard backlight on certain T2 Macs."). > This patch adds support for the Magic keyboards. > > Co-developed-by: Aditya Garg <gargaditya08@live.com> > Signed-off-by: Aditya Garg <gargaditya08@live.com> > Signed-off-by: Orlando Chamberlain <orlandoch.dev@gmail.com> > --- > drivers/hid/hid-apple.c | 87 ++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 86 insertions(+), 1 deletion(-) > > diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c > index bd022e004..db279948c 100644 > --- a/drivers/hid/hid-apple.c > +++ b/drivers/hid/hid-apple.c > @@ -8,6 +8,8 @@ > * Copyright (c) 2006-2007 Jiri Kosina > * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> > * Copyright (c) 2019 Paul Pawlowski <paul@mrarm.io> > + * Copyright (c) 2023 Orlando Chamberlain <orlandoch.dev@gmail.com> > + * Copyright (c) 2024 Aditya Garg <gargaditya08@live.com> > */ > > /* > @@ -23,6 +25,7 @@ > #include <linux/timer.h> > #include <linux/string.h> > #include <linux/leds.h> > +#include <dt-bindings/leds/common.h> > > #include "hid-ids.h" > > @@ -37,13 +40,18 @@ > #define APPLE_NUMLOCK_EMULATION BIT(8) > #define APPLE_RDESC_BATTERY BIT(9) > #define APPLE_BACKLIGHT_CTL BIT(10) > -#define APPLE_IS_NON_APPLE BIT(11) > +#define APPLE_MAGIC_BACKLIGHT BIT(11) > +#define APPLE_IS_NON_APPLE BIT(12) > > #define APPLE_FLAG_FKEY 0x01 > > #define HID_COUNTRY_INTERNATIONAL_ISO 13 > #define APPLE_BATTERY_TIMEOUT_MS 60000 > > +#define HID_USAGE_MAGIC_BL 0xff00000f > +#define APPLE_MAGIC_REPORT_ID_POWER 3 > +#define APPLE_MAGIC_REPORT_ID_BRIGHTNESS 1 > + > static unsigned int fnmode = 3; > module_param(fnmode, uint, 0644); > MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, " > @@ -81,6 +89,12 @@ struct apple_sc_backlight { > struct hid_device *hdev; > }; > > +struct apple_magic_backlight { > + struct led_classdev cdev; > + struct hid_report *brightness; > + struct hid_report *power; > +}; > + > struct apple_sc { > struct hid_device *hdev; > unsigned long quirks; > @@ -822,6 +836,72 @@ static int apple_backlight_init(struct hid_device *hdev) > return ret; > } > > +static void apple_magic_backlight_report_set(struct hid_report *rep, s32 value, u8 rate) > +{ > + rep->field[0]->value[0] = value; > + rep->field[1]->value[0] = 0x5e; /* Mimic Windows */ > + rep->field[1]->value[0] |= rate << 8; > + > + hid_hw_request(rep->device, rep, HID_REQ_SET_REPORT); > +} > + > +static void apple_magic_backlight_set(struct apple_magic_backlight *backlight, > + int brightness, char rate) > +{ > + apple_magic_backlight_report_set(backlight->power, brightness ? 1 : 0, rate); > + if (brightness) > + apple_magic_backlight_report_set(backlight->brightness, brightness, rate); > +} > + > +static int apple_magic_backlight_led_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + struct apple_magic_backlight *backlight = container_of(led_cdev, > + struct apple_magic_backlight, cdev); > + > + apple_magic_backlight_set(backlight, brightness, 1); > + return 0; > +} > + > +static int apple_magic_backlight_init(struct hid_device *hdev) > +{ > + struct apple_magic_backlight *backlight; > + int rc; > + > + /* > + * Ensure this usb endpoint is for the keyboard backlight, not touchbar > + * backlight. > + */ > + if (hdev->collection[0].usage != HID_USAGE_MAGIC_BL) > + return -ENODEV; > + > + backlight = devm_kzalloc(&hdev->dev, sizeof(*backlight), GFP_KERNEL); > + if (!backlight) > + return -ENOMEM; > + > + backlight->brightness = hid_register_report(hdev, HID_FEATURE_REPORT, > + APPLE_MAGIC_REPORT_ID_BRIGHTNESS, 0); > + backlight->power = hid_register_report(hdev, HID_FEATURE_REPORT, > + APPLE_MAGIC_REPORT_ID_POWER, 0); > + > + if (!backlight->brightness || !backlight->power) { > + rc = -ENODEV; > + goto hw_stop; > + } > + > + backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT; > + backlight->cdev.max_brightness = backlight->brightness->field[0]->logical_maximum; > + backlight->cdev.brightness_set_blocking = apple_magic_backlight_led_set; > + > + apple_magic_backlight_set(backlight, 0, 0); > + > + return devm_led_classdev_register(&hdev->dev, &backlight->cdev); > + > +hw_stop: > + hid_hw_stop(hdev); > + return rc; > +} > + > static int apple_probe(struct hid_device *hdev, > const struct hid_device_id *id) > { > @@ -860,6 +940,9 @@ static int apple_probe(struct hid_device *hdev, > if (quirks & APPLE_BACKLIGHT_CTL) > apple_backlight_init(hdev); > > + if (quirks & APPLE_MAGIC_BACKLIGHT) > + apple_magic_backlight_init(hdev); > + > return 0; > } > > @@ -1073,6 +1156,8 @@ static const struct hid_device_id apple_devices[] = { > .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, > { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), > .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, > + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT), > + .driver_data = APPLE_MAGIC_BACKLIGHT }, > > { } > }; > -- > 2.43.0 >
> On 2 Jul 2024, at 4:19 AM, Aditya Garg <gargaditya08@live.com> wrote: > Apparently this patch is breaking touchbar functionality is some cases. I think this is because apple_magic_backlight_init will return an error when it finds the touchbar interface, but this return value is not checked, so hid-apple still binds to the touchbar backlight. This should be fixable so I don't think we need to still have the separate driver. >> >> static int apple_probe(struct hid_device *hdev, >> const struct hid_device_id *id) >> { >> @@ -860,6 +940,9 @@ static int apple_probe(struct hid_device *hdev, >> if (quirks & APPLE_BACKLIGHT_CTL) >> apple_backlight_init(hdev); >> >> + if (quirks & APPLE_MAGIC_BACKLIGHT) >> + apple_magic_backlight_init(hdev); return value isn't checked here ^, we return 0 unconditionally below. >> + >> return 0; >> }
> On 2 Jul 2024, at 8:48 AM, Orlando Chamberlain <orlandoch.dev@gmail.com> wrote: > >> On 2 Jul 2024, at 4:19 AM, Aditya Garg <gargaditya08@live.com> wrote: >> Apparently this patch is breaking touchbar functionality is some cases. > > I think this is because apple_magic_backlight_init will return an error when it finds the touchbar interface, but this return value is not checked, so hid-apple still binds to the touchbar backlight. We may also need to make sure hid_hw_stop is called in this case. Perhaps we can move this logic from apple_magic_backlight_init to apple_probe? > > This should be fixable so I don't think we need to still have the separate driver. > >>> >>> static int apple_probe(struct hid_device *hdev, >>> const struct hid_device_id *id) >>> { >>> @@ -860,6 +940,9 @@ static int apple_probe(struct hid_device *hdev, >>> if (quirks & APPLE_BACKLIGHT_CTL) >>> apple_backlight_init(hdev); >>> >>> + if (quirks & APPLE_MAGIC_BACKLIGHT) >>> + apple_magic_backlight_init(hdev); > > return value isn't checked here ^, we return 0 unconditionally below. > >>> + >>> return 0; >>> }
Hi Orlando I resubmitted the patch which included only the backlight driver had no replies. Let's see if jiri is fine with the separate driver or not. > On 2 Jul 2024, at 4:27 AM, Orlando Chamberlain <orlandoch.dev@gmail.com> wrote: > > > >>> On 2 Jul 2024, at 8:48 AM, Orlando Chamberlain <orlandoch.dev@gmail.com> wrote: >>> >>>> On 2 Jul 2024, at 4:19 AM, Aditya Garg <gargaditya08@live.com> wrote: >>> Apparently this patch is breaking touchbar functionality is some cases. >> >> I think this is because apple_magic_backlight_init will return an error when it finds the touchbar interface, but this return value is not checked, so hid-apple still binds to the touchbar backlight. > > We may also need to make sure hid_hw_stop is called in this case. Perhaps we can move this logic from apple_magic_backlight_init to apple_probe? > >> >> This should be fixable so I don't think we need to still have the separate driver. >> >>>> >>>> static int apple_probe(struct hid_device *hdev, >>>> const struct hid_device_id *id) >>>> { >>>> @@ -860,6 +940,9 @@ static int apple_probe(struct hid_device *hdev, >>>> if (quirks & APPLE_BACKLIGHT_CTL) >>>> apple_backlight_init(hdev); >>>> >>>> + if (quirks & APPLE_MAGIC_BACKLIGHT) >>>> + apple_magic_backlight_init(hdev); >> >> return value isn't checked here ^, we return 0 unconditionally below. >> >>>> + >>>> return 0; >>>> }
> On 2 Jul 2024, at 4:27 AM, Orlando Chamberlain <orlandoch.dev@gmail.com> wrote: > > > >> On 2 Jul 2024, at 8:48 AM, Orlando Chamberlain <orlandoch.dev@gmail.com> wrote: >> >>> On 2 Jul 2024, at 4:19 AM, Aditya Garg <gargaditya08@live.com> wrote: >>> Apparently this patch is breaking touchbar functionality is some cases. >> >> I think this is because apple_magic_backlight_init will return an error when it finds the touchbar interface, but this return value is not checked, so hid-apple still binds to the touchbar backlight. > > We may also need to make sure hid_hw_stop is called in this case. Perhaps we can move this logic from apple_magic_backlight_init to apple_probe? > Thanks for your help Orlando. Sending a working and well tested version 2 >> >> This should be fixable so I don't think we need to still have the separate driver. >> >>>> >>>> static int apple_probe(struct hid_device *hdev, >>>> const struct hid_device_id *id) >>>> { >>>> @@ -860,6 +940,9 @@ static int apple_probe(struct hid_device *hdev, >>>> if (quirks & APPLE_BACKLIGHT_CTL) >>>> apple_backlight_init(hdev); >>>> >>>> + if (quirks & APPLE_MAGIC_BACKLIGHT) >>>> + apple_magic_backlight_init(hdev); >> >> return value isn't checked here ^, we return 0 unconditionally below. >> >>>> + >>>> return 0; >>>> }
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index bd022e004..db279948c 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -8,6 +8,8 @@ * Copyright (c) 2006-2007 Jiri Kosina * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> * Copyright (c) 2019 Paul Pawlowski <paul@mrarm.io> + * Copyright (c) 2023 Orlando Chamberlain <orlandoch.dev@gmail.com> + * Copyright (c) 2024 Aditya Garg <gargaditya08@live.com> */ /* @@ -23,6 +25,7 @@ #include <linux/timer.h> #include <linux/string.h> #include <linux/leds.h> +#include <dt-bindings/leds/common.h> #include "hid-ids.h" @@ -37,13 +40,18 @@ #define APPLE_NUMLOCK_EMULATION BIT(8) #define APPLE_RDESC_BATTERY BIT(9) #define APPLE_BACKLIGHT_CTL BIT(10) -#define APPLE_IS_NON_APPLE BIT(11) +#define APPLE_MAGIC_BACKLIGHT BIT(11) +#define APPLE_IS_NON_APPLE BIT(12) #define APPLE_FLAG_FKEY 0x01 #define HID_COUNTRY_INTERNATIONAL_ISO 13 #define APPLE_BATTERY_TIMEOUT_MS 60000 +#define HID_USAGE_MAGIC_BL 0xff00000f +#define APPLE_MAGIC_REPORT_ID_POWER 3 +#define APPLE_MAGIC_REPORT_ID_BRIGHTNESS 1 + static unsigned int fnmode = 3; module_param(fnmode, uint, 0644); MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, " @@ -81,6 +89,12 @@ struct apple_sc_backlight { struct hid_device *hdev; }; +struct apple_magic_backlight { + struct led_classdev cdev; + struct hid_report *brightness; + struct hid_report *power; +}; + struct apple_sc { struct hid_device *hdev; unsigned long quirks; @@ -822,6 +836,72 @@ static int apple_backlight_init(struct hid_device *hdev) return ret; } +static void apple_magic_backlight_report_set(struct hid_report *rep, s32 value, u8 rate) +{ + rep->field[0]->value[0] = value; + rep->field[1]->value[0] = 0x5e; /* Mimic Windows */ + rep->field[1]->value[0] |= rate << 8; + + hid_hw_request(rep->device, rep, HID_REQ_SET_REPORT); +} + +static void apple_magic_backlight_set(struct apple_magic_backlight *backlight, + int brightness, char rate) +{ + apple_magic_backlight_report_set(backlight->power, brightness ? 1 : 0, rate); + if (brightness) + apple_magic_backlight_report_set(backlight->brightness, brightness, rate); +} + +static int apple_magic_backlight_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct apple_magic_backlight *backlight = container_of(led_cdev, + struct apple_magic_backlight, cdev); + + apple_magic_backlight_set(backlight, brightness, 1); + return 0; +} + +static int apple_magic_backlight_init(struct hid_device *hdev) +{ + struct apple_magic_backlight *backlight; + int rc; + + /* + * Ensure this usb endpoint is for the keyboard backlight, not touchbar + * backlight. + */ + if (hdev->collection[0].usage != HID_USAGE_MAGIC_BL) + return -ENODEV; + + backlight = devm_kzalloc(&hdev->dev, sizeof(*backlight), GFP_KERNEL); + if (!backlight) + return -ENOMEM; + + backlight->brightness = hid_register_report(hdev, HID_FEATURE_REPORT, + APPLE_MAGIC_REPORT_ID_BRIGHTNESS, 0); + backlight->power = hid_register_report(hdev, HID_FEATURE_REPORT, + APPLE_MAGIC_REPORT_ID_POWER, 0); + + if (!backlight->brightness || !backlight->power) { + rc = -ENODEV; + goto hw_stop; + } + + backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT; + backlight->cdev.max_brightness = backlight->brightness->field[0]->logical_maximum; + backlight->cdev.brightness_set_blocking = apple_magic_backlight_led_set; + + apple_magic_backlight_set(backlight, 0, 0); + + return devm_led_classdev_register(&hdev->dev, &backlight->cdev); + +hw_stop: + hid_hw_stop(hdev); + return rc; +} + static int apple_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -860,6 +940,9 @@ static int apple_probe(struct hid_device *hdev, if (quirks & APPLE_BACKLIGHT_CTL) apple_backlight_init(hdev); + if (quirks & APPLE_MAGIC_BACKLIGHT) + apple_magic_backlight_init(hdev); + return 0; } @@ -1073,6 +1156,8 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT), + .driver_data = APPLE_MAGIC_BACKLIGHT }, { } };