Skip to content

Commit cc73c6c

Browse files
committed
ib-tb: support magic keyboard backlight
MacBookPro16,1/2/3/4 have the magic keyboard, with the keyboard backlight controlled via the Touch Bar Backlight USB device. We check that the internal keyboard's USB product ID matches that of models with the magic keyboard, and then we create a sysfs led class dev.
1 parent d8411ad commit cc73c6c

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

apple-ib-tb.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676

7777
#define APPLETB_MAX_DIM_TIME 30
7878

79+
#define APPLE_MAGIC_KBD_BL_MAX 60
80+
7981
static int appletb_tb_def_idle_timeout = 5 * 60;
8082
module_param_named(idle_timeout, appletb_tb_def_idle_timeout, int, 0444);
8183
MODULE_PARM_DESC(idle_timeout, "Default touch bar idle timeout:\n"
@@ -199,6 +201,24 @@ static const struct appletb_key_translation appletb_fn_codes[] = {
199201
{ KEY_F12, KEY_VOLUMEUP },
200202
};
201203

204+
struct apple_magic_backlight {
205+
struct led_classdev cdev;
206+
struct usb_device dev;
207+
};
208+
209+
struct apple_magic_keyboard_backlight_report {
210+
u8 report_id; /* 0x01 */
211+
u8 mode; /* If 0x00, brightness can turn off backlight */
212+
u8 brightness;
213+
u8 override_1; /* If these are non-zero, backlight is overridden to max brightness */
214+
u8 override_2;
215+
u8 max; /* The lower this is, the brighter each brightness value is.
216+
* Only takes affect after turning it off and on again. */
217+
u8 rate;
218+
u8 magic_1; /* If these are non-zero, we are ignored. */
219+
u8 magic_2;
220+
};
221+
202222
static struct appletb_device *appletb_dev;
203223

204224
static int appletb_send_usb_ctrl(struct appletb_iface_info *iface_info,
@@ -319,6 +339,77 @@ static int appletb_send_hid_report(struct appletb_iface_info *iface_info,
319339
return rc;
320340
}
321341

342+
static int apple_magic_keyboard_backlight_set(struct apple_magic_backlight *backlight, char brightness, char rate)
343+
{
344+
int tries = 0;
345+
int rc;
346+
struct apple_magic_keyboard_backlight_report *rep;
347+
348+
rep = kmalloc(sizeof(*rep), GFP_KERNEL);
349+
if (rep == NULL)
350+
return -ENOMEM;
351+
352+
rep->report_id = 0x01;
353+
rep->mode = brightness;
354+
rep->brightness = brightness;
355+
rep->max = 0x5e;
356+
rep->rate = rate;
357+
358+
do {
359+
/*
360+
* FIXME: use appletb_send_hid_report, don't hard code all of this
361+
* Need to get apple_tb_send_hid_report to use wIndex=0x01
362+
*/
363+
rc = usb_control_msg(&backlight->dev,
364+
usb_sndctrlpipe(&backlight->dev, 0),
365+
HID_REQ_SET_REPORT, USB_DIR_OUT |
366+
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
367+
0x0301, 0x01, rep, sizeof(*rep),
368+
2000);
369+
if (rc != -EPIPE)
370+
break;
371+
372+
usleep_range(1000 << tries, 3000 << tries);
373+
} while (++tries < 5);
374+
375+
kfree(rep);
376+
return (rc > 0) ? 0 : rc;
377+
}
378+
379+
static int apple_magic_keyboard_backlight_led_set(struct led_classdev *led_cdev,
380+
enum led_brightness brightness)
381+
{
382+
struct apple_magic_backlight *backlight = container_of(led_cdev,
383+
struct apple_magic_backlight, cdev);
384+
385+
return apple_magic_keyboard_backlight_set(backlight, brightness, 1);
386+
}
387+
388+
static int apple_magic_keyboard_backlight_init(struct appletb_device *tb_dev)
389+
{
390+
int ret;
391+
struct apple_magic_backlight *backlight;
392+
393+
backlight = devm_kzalloc(tb_dev->log_dev, sizeof(*backlight), GFP_KERNEL);
394+
if (!backlight)
395+
return -ENOMEM;
396+
397+
backlight->dev = *interface_to_usbdev(tb_dev->disp_iface.usb_iface);
398+
backlight->cdev.name = "apple::kbd_backlight";
399+
backlight->cdev.max_brightness = APPLE_MAGIC_KBD_BL_MAX;
400+
backlight->cdev.brightness_set_blocking = apple_magic_keyboard_backlight_led_set;
401+
402+
ret = apple_magic_keyboard_backlight_set(backlight, 0, 0);
403+
if (ret) {
404+
dev_err(tb_dev->log_dev, "Failed to initialise Magic Keyboard Backlight (%d)\n", ret);
405+
kfree(backlight);
406+
return ret;
407+
}
408+
409+
ret = devm_led_classdev_register(tb_dev->log_dev, &backlight->cdev);
410+
return ret;
411+
}
412+
322413
static int appletb_set_tb_disp(struct appletb_device *tb_dev,
323414
unsigned char disp)
324415
{
@@ -884,6 +975,13 @@ static int appletb_inp_connect(struct input_handler *handler,
884975
if (id->driver_info == APPLETB_DEVID_KEYBOARD) {
885976
handle = &tb_dev->kbd_handle;
886977
handle->name = "tbkbd";
978+
switch(dev->id.product) {
979+
case 0x0340u: /* MacBookPro16,1/4 */
980+
case 0x027eu: /* MacBookPro16,2 */
981+
case 0x027fu: /* MacBookPro16,3 */
982+
apple_magic_keyboard_backlight_init(tb_dev);
983+
break;
984+
}
887985
} else if (id->driver_info == APPLETB_DEVID_TOUCHPAD) {
888986
handle = &tb_dev->tpd_handle;
889987
handle->name = "tbtpad";

0 commit comments

Comments
 (0)