Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ib-tb: support magic keyboard backlight #4

Open
wants to merge 1 commit into
base: mbp15
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions apple-ib-tb.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@

#define APPLETB_MAX_DIM_TIME 30

#define APPLE_MAGIC_KBD_BL_MAX 60

static int appletb_tb_def_idle_timeout = 5 * 60;
module_param_named(idle_timeout, appletb_tb_def_idle_timeout, int, 0444);
MODULE_PARM_DESC(idle_timeout, "Default touch bar idle timeout:\n"
Expand Down Expand Up @@ -138,6 +140,12 @@ static const struct attribute_group appletb_attr_group = {
.attrs = appletb_attrs,
};

struct apple_magic_backlight {
struct led_classdev cdev;
struct usb_device *dev;
bool powered;
};

struct appletb_device {
bool active;
struct device *log_dev;
Expand Down Expand Up @@ -177,6 +185,8 @@ struct appletb_device {
int fn_mode;

bool is_t2;

struct apple_magic_backlight kbd_backlight;
};

struct appletb_key_translation {
Expand All @@ -199,6 +209,30 @@ static const struct appletb_key_translation appletb_fn_codes[] = {
{ KEY_F12, KEY_VOLUMEUP },
};

struct apple_magic_keyboard_backlight_brightness_report {
u8 report_id; /* 0x01 */
u8 mode; /* If 0x00, brightness can turn off backlight */
u8 brightness;
u8 override_1; /* If these are non-zero, backlight is overridden to max brightness */
u8 override_2;
u8 max; /* Lower is brighter, only takes effect when turning backlight
* on from off, can be unreliable
*/
u8 rate;
u8 magic_1; /* If these are non-zero, we are ignored. */
u8 magic_2;
};

struct apple_magic_keyboard_backlight_power_report {
u8 report_id; /* 0x03 */
u8 power;
u8 max; /* Lower is brighter, only takes effect when turning backlight
* on from off, can be unreliable
*/
u8 rate;
u8 magic_1; /* If these are non-zero, we are ignored. */
u8 magic_2;
};
static struct appletb_device *appletb_dev;

static int appletb_send_usb_ctrl(struct appletb_iface_info *iface_info,
Expand Down Expand Up @@ -319,6 +353,132 @@ static int appletb_send_hid_report(struct appletb_iface_info *iface_info,
return rc;
}

static int apple_magic_keyboard_backlight_power_set(struct apple_magic_backlight *backlight,
char power, char rate)
{
int tries = 0;
int rc;
struct apple_magic_keyboard_backlight_power_report *rep;

rep = kmalloc(sizeof(*rep), GFP_KERNEL);
if (rep == NULL)
return -ENOMEM;

backlight->powered = power ? true : false;

rep->report_id = 0x03;
rep->power = power;
rep->max = 0x5e; /* Windows uses 0x5e when turning on, and 0xf4 when
* turning off. When it's off it doesn't matter, so
* use 0x5e
*/
rep->rate = rate;

do {
/*
* FIXME: use appletb_send_hid_report, don't hard code all of this
* Need to get apple_tb_send_hid_report to use wIndex=0x01
*/
rc = usb_control_msg(backlight->dev,
usb_sndctrlpipe(backlight->dev, 0),
HID_REQ_SET_REPORT, USB_DIR_OUT |
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x0303, 0x01, rep, sizeof(*rep),
2000);
if (rc != -EPIPE)
break;

usleep_range(1000 << tries, 3000 << tries);
} while (++tries < 5);

kfree(rep);
return (rc > 0) ? 0 : rc;
}

static int apple_magic_keyboard_backlight_brightness_set(struct apple_magic_backlight *backlight,
char brightness, char rate)
{
int tries = 0;
int rc;
struct apple_magic_keyboard_backlight_brightness_report *rep;

rep = kmalloc(sizeof(*rep), GFP_KERNEL);
if (rep == NULL)
return -ENOMEM;

rep->report_id = 0x01;
rep->mode = brightness;
rep->brightness = brightness;
rep->max = 0x5e;
rep->rate = rate;

do {
/*
* FIXME: use appletb_send_hid_report, don't hard code all of this
* Need to get apple_tb_send_hid_report to use wIndex=0x01
*/
rc = usb_control_msg(backlight->dev,
usb_sndctrlpipe(backlight->dev, 0),
HID_REQ_SET_REPORT, USB_DIR_OUT |
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x0301, 0x01, rep, sizeof(*rep),
2000);
if (rc != -EPIPE)
break;

usleep_range(1000 << tries, 3000 << tries);
} while (++tries < 5);

kfree(rep);
return (rc > 0) ? 0 : rc;
}

static int apple_magic_keyboard_backlight_set(struct apple_magic_backlight *backlight,
char brightness, char rate)
{
int rc;

if (!brightness)
return apple_magic_keyboard_backlight_power_set(backlight, 0, rate);

rc = apple_magic_keyboard_backlight_brightness_set(backlight, brightness, rate);
if (rc)
return rc;

if (!backlight->powered && brightness)
rc = apple_magic_keyboard_backlight_power_set(backlight, 1, rate);

return (rc > 0) ? 0 : rc;
}

static int apple_magic_keyboard_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);

return apple_magic_keyboard_backlight_set(backlight, brightness, 1);
}

static int apple_magic_keyboard_backlight_init(struct appletb_device *tb_dev)
{
int ret;

tb_dev->kbd_backlight.dev = interface_to_usbdev(tb_dev->disp_iface.usb_iface);
tb_dev->kbd_backlight.cdev.name = "apple::kbd_backlight";
tb_dev->kbd_backlight.cdev.max_brightness = APPLE_MAGIC_KBD_BL_MAX;
tb_dev->kbd_backlight.cdev.brightness_set_blocking = apple_magic_keyboard_backlight_led_set;

ret = apple_magic_keyboard_backlight_set(&tb_dev->kbd_backlight, 0, 0);
if (ret) {
dev_err(tb_dev->log_dev,
"Failed to initialise Magic Keyboard Backlight (%d)\n", ret);
return ret;
}

return devm_led_classdev_register(tb_dev->log_dev, &tb_dev->kbd_backlight.cdev);
}

static int appletb_set_tb_disp(struct appletb_device *tb_dev,
unsigned char disp)
{
Expand Down Expand Up @@ -884,6 +1044,13 @@ static int appletb_inp_connect(struct input_handler *handler,
if (id->driver_info == APPLETB_DEVID_KEYBOARD) {
handle = &tb_dev->kbd_handle;
handle->name = "tbkbd";
switch (dev->id.product) {
case 0x0340u: /* MacBookPro16,1/4 */
case 0x027eu: /* MacBookPro16,2 */
case 0x027fu: /* MacBookPro16,3 */
apple_magic_keyboard_backlight_init(tb_dev);
break;
}
} else if (id->driver_info == APPLETB_DEVID_TOUCHPAD) {
handle = &tb_dev->tpd_handle;
handle->name = "tbtpad";
Expand Down