-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Patch: hid keyboard backlight support
* integrated patch provided by @MCMrARM to enable keyboard backlight for `MacBookPro15,x` and `MacBookAir8,x` as well * see: https://github.com/MCMrARM/mbp2018-etc/tree/master/apple-hid * see: Dunedan/mbp-2016-linux#110 (comment)
- Loading branch information
1 parent
0bdb968
commit 01ab827
Showing
1 changed file
with
164 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,194 @@ | ||
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c | ||
index 1cb41992a..58197f729 100644 | ||
index 1cb41992a..d12b33d43 100644 | ||
--- a/drivers/hid/hid-apple.c | ||
+++ b/drivers/hid/hid-apple.c | ||
@@ -557,6 +557,10 @@ static const struct hid_device_id apple_devices[] = { | ||
@@ -6,6 +6,7 @@ | ||
* Copyright (c) 2005 Michael Haboustak <[email protected]> for Concept2, Inc | ||
* Copyright (c) 2006-2007 Jiri Kosina | ||
* Copyright (c) 2008 Jiri Slaby <[email protected]> | ||
+ * Copyright (c) 2019 Paul Pawlowski <[email protected]> | ||
*/ | ||
|
||
/* | ||
@@ -33,6 +34,7 @@ | ||
#define APPLE_INVERT_HWHEEL 0x0040 | ||
#define APPLE_IGNORE_HIDINPUT 0x0080 | ||
#define APPLE_NUMLOCK_EMULATION 0x0100 | ||
+#define APPLE_BACKLIGHT_CTL 0x0200 | ||
|
||
#define APPLE_FLAG_FKEY 0x01 | ||
|
||
@@ -54,11 +56,18 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\") | ||
"(For people who want to keep Windows PC keyboard muscle memory. " | ||
"[0] = as-is, Mac layout. 1 = swapped, Windows layout.)"); | ||
|
||
+struct apple_sc_backlight; | ||
struct apple_sc { | ||
unsigned long quirks; | ||
unsigned int fn_on; | ||
DECLARE_BITMAP(pressed_fn, KEY_CNT); | ||
DECLARE_BITMAP(pressed_numlock, KEY_CNT); | ||
+ struct apple_sc_backlight *backlight; | ||
+}; | ||
+struct apple_sc_backlight { | ||
+ struct led_classdev cdev; | ||
+ struct hid_device *hdev; | ||
+ unsigned short backlight_off, backlight_on_min, backlight_on_max; | ||
}; | ||
|
||
struct apple_key_translation { | ||
@@ -366,6 +375,11 @@ static int apple_input_mapped(struct hid_device *hdev, struct hid_input *hi, | ||
return 0; | ||
} | ||
|
||
+static int apple_init_backlight(struct hid_device *hdev); | ||
+static int apple_set_backlight(struct hid_device *hdev, u16 value, u16 rate); | ||
+static int apple_led_set_backlight(struct led_classdev *led_cdev, | ||
+ enum led_brightness brightness); | ||
+ | ||
static int apple_probe(struct hid_device *hdev, | ||
const struct hid_device_id *id) | ||
{ | ||
@@ -401,9 +415,106 @@ static int apple_probe(struct hid_device *hdev, | ||
return ret; | ||
} | ||
|
||
+ if (quirks & APPLE_BACKLIGHT_CTL) | ||
+ apple_init_backlight(hdev); | ||
+ | ||
return 0; | ||
} | ||
|
||
+struct apple_backlight_config_report { | ||
+ u8 report_id; | ||
+ u8 version; | ||
+ u16 backlight_off, backlight_on_min, backlight_on_max; | ||
+}; | ||
+struct apple_backlight_set_report { | ||
+ u8 report_id; | ||
+ u8 version; | ||
+ u16 backlight; | ||
+ u16 rate; | ||
+}; | ||
+ | ||
+static bool apple_check_backlight_support(struct hid_device *hdev) | ||
+{ | ||
+ int i; | ||
+ unsigned hid; | ||
+ struct hid_report *report; | ||
+ | ||
+ list_for_each_entry(report, &hdev->report_enum[HID_INPUT_REPORT].report_list, list) { | ||
+ for (i = 0; i < report->maxfield; i++) { | ||
+ hid = report->field[i]->usage->hid; | ||
+ if ((hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR && (hid & HID_USAGE) == 0xf) | ||
+ return true; | ||
+ } | ||
+ } | ||
+ return false; | ||
+} | ||
+ | ||
+static int apple_init_backlight(struct hid_device *hdev) | ||
+{ | ||
+ int ret; | ||
+ struct apple_sc *asc = hid_get_drvdata(hdev); | ||
+ struct apple_backlight_config_report *rep; | ||
+ | ||
+ if (!apple_check_backlight_support(hdev)) | ||
+ return -EINVAL; | ||
+ | ||
+ rep = kmalloc(0x200, GFP_KERNEL); | ||
+ ret = hid_hw_raw_request(hdev, 0xBFu, (u8 *) rep, sizeof(*rep), HID_FEATURE_REPORT, HID_REQ_GET_REPORT); | ||
+ if (ret < 0) { | ||
+ hid_err(hdev, "backlight request failed\n"); | ||
+ return ret; | ||
+ } | ||
+ if (ret < 8 || rep->version != 1) { | ||
+ hid_err(hdev, "backlight config struct: bad version %i\n", rep->version); | ||
+ kfree(rep); | ||
+ return -EINVAL; | ||
+ } | ||
+ | ||
+ hid_dbg(hdev, "backlight config: off=%u, on_min=%u, on_max=%u\n", | ||
+ rep->backlight_off, rep->backlight_on_min, rep->backlight_on_max); | ||
+ | ||
+ asc->backlight = devm_kzalloc(&hdev->dev, sizeof(*asc->backlight), GFP_KERNEL); | ||
+ if (!asc->backlight) { | ||
+ kfree(rep); | ||
+ return -ENOMEM; | ||
+ } | ||
+ | ||
+ asc->backlight->hdev = hdev; | ||
+ asc->backlight->cdev.name = "apple::kbd_backlight"; | ||
+ asc->backlight->cdev.max_brightness = rep->backlight_on_max; | ||
+ asc->backlight->cdev.brightness_set_blocking = apple_led_set_backlight; | ||
+ kfree(rep); | ||
+ | ||
+ apple_set_backlight(hdev, 0, 0); | ||
+ | ||
+ return devm_led_classdev_register(&hdev->dev, &asc->backlight->cdev); | ||
+} | ||
+ | ||
+static int apple_set_backlight(struct hid_device *hdev, u16 value, u16 rate) | ||
+{ | ||
+ int ret; | ||
+ struct apple_backlight_set_report *rep; | ||
+ | ||
+ rep = kmalloc(sizeof(*rep), GFP_KERNEL); | ||
+ rep->report_id = 0xB0; | ||
+ rep->version = 1; | ||
+ rep->backlight = value; | ||
+ rep->rate = rate; | ||
+ | ||
+ ret = hid_hw_raw_request(hdev, 0xB0u, (u8 *) rep, sizeof(*rep), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); | ||
+ kfree(rep); | ||
+ if (ret) | ||
+ return ret; | ||
+ return 0; | ||
+} | ||
+ | ||
+static int apple_led_set_backlight(struct led_classdev *led_cdev, | ||
+ enum led_brightness brightness) | ||
+{ | ||
+ struct apple_sc_backlight *backlight = container_of(led_cdev, struct apple_sc_backlight, cdev); | ||
+ return apple_set_backlight(backlight->hdev, brightness, 0); | ||
+} | ||
+ | ||
static const struct hid_device_id apple_devices[] = { | ||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), | ||
.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, | ||
@@ -557,6 +668,10 @@ static const struct hid_device_id apple_devices[] = { | ||
.driver_data = APPLE_HAS_FN }, | ||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS), | ||
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, | ||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MBA8_1), | ||
+ .driver_data = APPLE_HAS_FN }, | ||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MBA8_X), | ||
+ .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL }, | ||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MBP15_X), | ||
+ .driver_data = APPLE_HAS_FN }, | ||
+ .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL }, | ||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), | ||
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, | ||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), | ||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h | ||
index adce58f24..1ee41d05c 100644 | ||
index adce58f24..1c3150d40 100644 | ||
--- a/drivers/hid/hid-ids.h | ||
+++ b/drivers/hid/hid-ids.h | ||
@@ -170,6 +170,8 @@ | ||
#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI 0x0272 | ||
#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273 | ||
#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274 | ||
+#define USB_DEVICE_ID_APPLE_MBA8_1 0x027a | ||
+#define USB_DEVICE_ID_APPLE_MBA8_X 0x027a | ||
+#define USB_DEVICE_ID_APPLE_MBP15_X 0x027b | ||
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a | ||
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b | ||
#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 | ||
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c | ||
index 77ffba48c..3853d11d3 100644 | ||
index 77ffba48c..93c5f0297 100644 | ||
--- a/drivers/hid/hid-quirks.c | ||
+++ b/drivers/hid/hid-quirks.c | ||
@@ -269,6 +269,8 @@ static const struct hid_device_id hid_have_special_driver[] = { | ||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, | ||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, | ||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, | ||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MBA8_1) }, | ||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MBA8_X) }, | ||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MBP15_X) }, | ||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, | ||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, | ||
|
@@ -43,7 +197,7 @@ index 77ffba48c..3853d11d3 100644 | |
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, | ||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, | ||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, | ||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MBA8_1) }, | ||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MBA8_X) }, | ||
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MBP15_X) }, | ||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, | ||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, | ||
|