diff options
Diffstat (limited to 'drivers/hid/hid-apple.c')
-rw-r--r-- | drivers/hid/hid-apple.c | 146 |
1 files changed, 133 insertions, 13 deletions
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 2c9c5faa74a9..24802a4a636e 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -16,24 +16,28 @@ #include <linux/device.h> #include <linux/hid.h> +#include <linux/jiffies.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/timer.h> #include "hid-ids.h" -#define APPLE_RDESC_JIS 0x0001 -#define APPLE_IGNORE_MOUSE 0x0002 -#define APPLE_HAS_FN 0x0004 -/* 0x0008 reserved, was: APPLE_HIDDEV */ -#define APPLE_ISO_TILDE_QUIRK 0x0010 -#define APPLE_MIGHTYMOUSE 0x0020 -#define APPLE_INVERT_HWHEEL 0x0040 -/* 0x0080 reserved, was: APPLE_IGNORE_HIDINPUT */ -#define APPLE_NUMLOCK_EMULATION 0x0100 +#define APPLE_RDESC_JIS BIT(0) +#define APPLE_IGNORE_MOUSE BIT(1) +#define APPLE_HAS_FN BIT(2) +/* BIT(3) reserved, was: APPLE_HIDDEV */ +#define APPLE_ISO_TILDE_QUIRK BIT(4) +#define APPLE_MIGHTYMOUSE BIT(5) +#define APPLE_INVERT_HWHEEL BIT(6) +/* BIT(7) reserved, was: APPLE_IGNORE_HIDINPUT */ +#define APPLE_NUMLOCK_EMULATION BIT(8) +#define APPLE_RDESC_BATTERY BIT(9) #define APPLE_FLAG_FKEY 0x01 #define HID_COUNTRY_INTERNATIONAL_ISO 13 +#define APPLE_BATTERY_TIMEOUT_MS 60000 static unsigned int fnmode = 1; module_param(fnmode, uint, 0644); @@ -58,10 +62,12 @@ MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. " "[0] = as-is, Mac layout, 1 = swapped, PC layout)"); struct apple_sc { + struct hid_device *hdev; unsigned long quirks; unsigned int fn_on; unsigned int fn_found; DECLARE_BITMAP(pressed_numlock, KEY_CNT); + struct timer_list battery_timer; }; struct apple_key_translation { @@ -70,6 +76,28 @@ struct apple_key_translation { u8 flags; }; +static const struct apple_key_translation apple2021_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_ENTER, KEY_INSERT }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, + { KEY_F4, KEY_SEARCH, APPLE_FLAG_FKEY }, + { KEY_F5, KEY_MICMUTE, APPLE_FLAG_FKEY }, + { KEY_F6, KEY_SLEEP, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + static const struct apple_key_translation macbookair_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, { KEY_ENTER, KEY_INSERT }, @@ -214,7 +242,11 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } if (fnmode) { - if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && + if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 || + hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 || + hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021) + table = apple2021_fn_keys; + else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) table = macbookair_fn_keys; else if (hid->product < 0x21d || hid->product >= 0x300) @@ -333,6 +365,43 @@ static int apple_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static int apple_fetch_battery(struct hid_device *hdev) +{ +#ifdef CONFIG_HID_BATTERY_STRENGTH + struct apple_sc *asc = hid_get_drvdata(hdev); + struct hid_report_enum *report_enum; + struct hid_report *report; + + if (!(asc->quirks & APPLE_RDESC_BATTERY) || !hdev->battery) + return -1; + + report_enum = &hdev->report_enum[hdev->battery_report_type]; + report = report_enum->report_id_hash[hdev->battery_report_id]; + + if (!report || report->maxfield < 1) + return -1; + + if (hdev->battery_capacity == hdev->battery_max) + return -1; + + hid_hw_request(hdev, report, HID_REQ_GET_REPORT); + return 0; +#else + return -1; +#endif +} + +static void apple_battery_timer_tick(struct timer_list *t) +{ + struct apple_sc *asc = from_timer(asc, t, battery_timer); + struct hid_device *hdev = asc->hdev; + + if (apple_fetch_battery(hdev) == 0) { + mod_timer(&asc->battery_timer, + jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS)); + } +} + /* * MacBook JIS keyboard has wrong logical maximum * Magic Keyboard JIS has wrong logical maximum @@ -354,6 +423,30 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, "fixing up MacBook JIS keyboard report descriptor\n"); rdesc[53] = rdesc[59] = 0xe7; } + + /* + * Change the usage from: + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 0 + * 0x09, 0x0b, // Usage (Vendor Usage 0x0b) 3 + * To: + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 + * 0x09, 0x06, // Usage (Keyboard) 2 + */ + if ((asc->quirks & APPLE_RDESC_BATTERY) && *rsize == 83 && + rdesc[46] == 0x84 && rdesc[58] == 0x85) { + hid_info(hdev, + "fixing up Magic Keyboard battery report descriptor\n"); + *rsize = *rsize - 1; + rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL); + if (!rdesc) + return NULL; + + rdesc[0] = 0x05; + rdesc[1] = 0x01; + rdesc[2] = 0x09; + rdesc[3] = 0x06; + } + return rdesc; } @@ -376,6 +469,9 @@ static void apple_setup_input(struct input_dev *input) for (trans = apple_iso_keyboard; trans->from; trans++) set_bit(trans->to, input->keybit); + for (trans = apple2021_fn_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + if (swap_fn_leftctrl) { for (trans = swapped_fn_leftctrl_keys; trans->from; trans++) set_bit(trans->to, input->keybit); @@ -428,7 +524,7 @@ static int apple_input_configured(struct hid_device *hdev, if ((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) { hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n"); - asc->quirks = 0; + asc->quirks &= ~APPLE_HAS_FN; } return 0; @@ -447,6 +543,7 @@ static int apple_probe(struct hid_device *hdev, return -ENOMEM; } + asc->hdev = hdev; asc->quirks = quirks; hid_set_drvdata(hdev, asc); @@ -463,9 +560,23 @@ static int apple_probe(struct hid_device *hdev, return ret; } + timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0); + mod_timer(&asc->battery_timer, + jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS)); + apple_fetch_battery(hdev); + return 0; } +static void apple_remove(struct hid_device *hdev) +{ + struct apple_sc *asc = hid_get_drvdata(hdev); + + del_timer_sync(&asc->battery_timer); + + hid_hw_stop(hdev); +} + 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 }, @@ -540,11 +651,11 @@ static const struct hid_device_id apple_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015), - .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + .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_2015), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015), - .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + .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_2015), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), @@ -640,6 +751,14 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021), + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021), + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { } }; @@ -650,6 +769,7 @@ static struct hid_driver apple_driver = { .id_table = apple_devices, .report_fixup = apple_report_fixup, .probe = apple_probe, + .remove = apple_remove, .event = apple_event, .input_mapping = apple_input_mapping, .input_mapped = apple_input_mapped, |