Merge branch 'for-7.4/apple' into for-linus

- power management fix for Apple Touch Bar (Andre Eikmeyer)
- fix for trackpad hanling on T2 Macs (Aditya Garg)
This commit is contained in:
Jiri Kosina 2026-10-21 21:56:34 +02:00
commit 5bb58a6777
2 changed files with 89 additions and 33 deletions

View File

@ -30,7 +30,7 @@
#include "hid-ids.h"
#define APPLE_RDESC_JIS BIT(0)
/* BIT(1) reserved, was: APPLE_IGNORE_MOUSE */
#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)
@ -960,6 +960,9 @@ static int apple_probe(struct hid_device *hdev,
struct apple_sc *asc;
int ret;
if (quirks & APPLE_IGNORE_MOUSE && hdev->type == HID_TYPE_USBMOUSE)
return -ENODEV;
asc = devm_kzalloc(&hdev->dev, sizeof(*asc), GFP_KERNEL);
if (asc == NULL) {
hid_err(hdev, "can't alloc apple descriptor\n");
@ -1185,27 +1188,31 @@ static const struct hid_device_id apple_devices[] = {
{ 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_WELLSPRINGT2_J140K),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK |
APPLE_IGNORE_MOUSE },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK |
APPLE_DISABLE_FKEYS },
APPLE_DISABLE_FKEYS | APPLE_IGNORE_MOUSE },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK |
APPLE_DISABLE_FKEYS },
APPLE_DISABLE_FKEYS | APPLE_IGNORE_MOUSE },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680_ALT),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK |
APPLE_DISABLE_FKEYS },
APPLE_DISABLE_FKEYS | APPLE_IGNORE_MOUSE },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK |
APPLE_DISABLE_FKEYS },
APPLE_DISABLE_FKEYS | APPLE_IGNORE_MOUSE },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_DISABLE_FKEYS },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_DISABLE_FKEYS |
APPLE_IGNORE_MOUSE },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_DISABLE_FKEYS },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_DISABLE_FKEYS |
APPLE_IGNORE_MOUSE },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_IGNORE_MOUSE },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_DISABLE_FKEYS },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_DISABLE_FKEYS |
APPLE_IGNORE_MOUSE },
{ 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),

View File

@ -56,6 +56,12 @@ static int appletb_tb_idle_timeout = 15;
module_param_named(idle_timeout, appletb_tb_idle_timeout, int, 0644);
MODULE_PARM_DESC(idle_timeout, "Idle timeout in sec");
static int appletb_tb_double_press_switch_time;
module_param_named(double_press_switch_time,
appletb_tb_double_press_switch_time, int, 0644);
MODULE_PARM_DESC(double_press_switch_time,
"Fn double-press interval in ms (0 disables layer switching)");
struct appletb_kbd {
struct hid_field *mode_field;
struct input_handler inp_handler;
@ -68,6 +74,7 @@ struct appletb_kbd {
bool has_turned_off;
u8 saved_mode;
u8 current_mode;
unsigned long last_fn_press;
};
static const struct key_entry appletb_kbd_keymap[] = {
@ -87,29 +94,37 @@ static const struct key_entry appletb_kbd_keymap[] = {
{ KE_END, 0 }
};
static int appletb_kbd_set_mode(struct appletb_kbd *kbd, u8 mode)
static int appletb_kbd_set_mode_active(struct appletb_kbd *kbd, u8 mode)
{
struct hid_report *report = kbd->mode_field->report;
struct hid_device *hdev = report->device;
int ret;
ret = hid_set_field(kbd->mode_field, 0, mode);
if (ret) {
hid_err(hdev, "Failed to set mode field to %u (%pe)\n", mode, ERR_PTR(ret));
return ret;
}
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
kbd->current_mode = mode;
return 0;
}
static int appletb_kbd_set_mode(struct appletb_kbd *kbd, u8 mode)
{
struct hid_device *hdev = kbd->mode_field->report->device;
int ret;
ret = hid_hw_power(hdev, PM_HINT_FULLON);
if (ret) {
hid_err(hdev, "Device didn't resume (%pe)\n", ERR_PTR(ret));
return ret;
}
ret = hid_set_field(kbd->mode_field, 0, mode);
if (ret) {
hid_err(hdev, "Failed to set mode field to %u (%pe)\n", mode, ERR_PTR(ret));
goto power_normal;
}
ret = appletb_kbd_set_mode_active(kbd, mode);
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
kbd->current_mode = mode;
power_normal:
hid_hw_power(hdev, PM_HINT_NORMAL);
return ret;
@ -243,6 +258,18 @@ static int appletb_kbd_hid_event(struct hid_device *hdev, struct hid_field *fiel
return kbd->current_mode == APPLETB_KBD_MODE_OFF;
}
static u8 appletb_switch_mode(u8 mode)
{
switch (mode) {
case APPLETB_KBD_MODE_SPCL:
return APPLETB_KBD_MODE_FN;
case APPLETB_KBD_MODE_FN:
return APPLETB_KBD_MODE_SPCL;
default:
return mode;
}
}
static void appletb_kbd_inp_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
@ -250,15 +277,36 @@ static void appletb_kbd_inp_event(struct input_handle *handle, unsigned int type
reset_inactivity_timer(kbd);
if (type == EV_KEY && code == KEY_FN && appletb_tb_fn_toggle &&
(kbd->current_mode == APPLETB_KBD_MODE_SPCL ||
kbd->current_mode == APPLETB_KBD_MODE_FN)) {
if (type == EV_KEY && code == KEY_FN &&
(kbd->current_mode == APPLETB_KBD_MODE_SPCL ||
kbd->current_mode == APPLETB_KBD_MODE_FN)) {
if (value == 1) {
kbd->saved_mode = kbd->current_mode;
appletb_kbd_set_mode(kbd, kbd->current_mode == APPLETB_KBD_MODE_SPCL
? APPLETB_KBD_MODE_FN : APPLETB_KBD_MODE_SPCL);
if (appletb_tb_double_press_switch_time > 0) {
unsigned long now = jiffies;
if (time_before(now, kbd->last_fn_press +
msecs_to_jiffies(appletb_tb_double_press_switch_time))) {
appletb_tb_def_mode =
appletb_switch_mode(appletb_tb_def_mode);
appletb_kbd_set_mode(kbd, appletb_tb_def_mode);
kbd->saved_mode = appletb_tb_def_mode;
kbd->last_fn_press = 0;
return;
}
kbd->last_fn_press = now;
}
if (appletb_tb_fn_toggle) {
kbd->saved_mode = kbd->current_mode;
appletb_kbd_set_mode(kbd, appletb_switch_mode(kbd->current_mode));
}
} else if (value == 0) {
if (kbd->saved_mode != kbd->current_mode)
if (appletb_tb_fn_toggle &&
kbd->saved_mode != kbd->current_mode)
appletb_kbd_set_mode(kbd, kbd->saved_mode);
}
}
@ -487,18 +535,19 @@ static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg)
struct appletb_kbd *kbd = hid_get_drvdata(hdev);
kbd->saved_mode = kbd->current_mode;
appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
return 0;
/* This callback already runs as part of a USB PM transition. Taking a
* nested runtime-PM reference would wait for that transition to complete
* and deadlock the USB PM state machine.
*/
return appletb_kbd_set_mode_active(kbd, APPLETB_KBD_MODE_OFF);
}
static int appletb_kbd_resume(struct hid_device *hdev)
{
struct appletb_kbd *kbd = hid_get_drvdata(hdev);
appletb_kbd_set_mode(kbd, kbd->saved_mode);
return 0;
return appletb_kbd_set_mode_active(kbd, kbd->saved_mode);
}
static const struct hid_device_id appletb_kbd_hid_ids[] = {