-
Notifications
You must be signed in to change notification settings - Fork 11
/
1017-HID-hid-appletb-kbd-add-support-for-fn-toggle-betwee.patch
196 lines (182 loc) · 5.58 KB
/
1017-HID-hid-appletb-kbd-add-support-for-fn-toggle-betwee.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
From 006a51516285ebaa8333d19fb76efbc81e5cdb3e Mon Sep 17 00:00:00 2001
From: Aditya Garg <[email protected]>
Date: Fri, 9 Aug 2024 19:40:53 +0530
Subject: [PATCH] HID: hid-appletb-kbd: add support for fn toggle between media
and function mode
This patch adds support for the switching between the Media and Function
keys on the touchbar by pressing the Fn key on Apple Internal Keyboard.
Signed-off-by: Aditya Garg <[email protected]>
---
drivers/hid/hid-appletb-kbd.c | 128 ++++++++++++++++++++++++++++++++++
1 file changed, 128 insertions(+)
diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
index ecac68fc7..442c4d884 100644
--- a/drivers/hid/hid-appletb-kbd.c
+++ b/drivers/hid/hid-appletb-kbd.c
@@ -26,6 +26,8 @@
#define APPLETB_KBD_MODE_OFF 3
#define APPLETB_KBD_MODE_MAX APPLETB_KBD_MODE_OFF
+#define APPLETB_DEVID_KEYBOARD 1
+
#define HID_USAGE_MODE 0x00ff0004
static int appletb_tb_def_mode = APPLETB_KBD_MODE_SPCL;
@@ -35,11 +37,18 @@ MODULE_PARM_DESC(mode, "Default touchbar mode:\n"
" 1 - function-keys\n"
" [2] - special keys");
+static bool appletb_tb_fn_toggle = true;
+module_param_named(fntoggle, appletb_tb_fn_toggle, bool, 0644);
+MODULE_PARM_DESC(fntoggle, "Switch between Fn and media controls on pressing Fn key");
+
struct appletb_kbd {
struct hid_field *mode_field;
u8 saved_mode;
u8 current_mode;
+ struct input_handler inp_handler;
+ struct input_handle kbd_handle;
+
};
static const struct key_entry appletb_kbd_keymap[] = {
@@ -172,6 +181,75 @@ static int appletb_kbd_hid_event(struct hid_device *hdev, struct hid_field *fiel
return kbd->current_mode == APPLETB_KBD_MODE_OFF;
}
+static void appletb_kbd_inp_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int value)
+{
+ struct appletb_kbd *kbd = handle->private;
+
+ if (type == EV_KEY && code == KEY_FN && appletb_tb_fn_toggle) {
+ if (value == 1) {
+ kbd->saved_mode = kbd->current_mode;
+ if (kbd->current_mode == APPLETB_KBD_MODE_SPCL)
+ appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_FN);
+ else if (kbd->current_mode == APPLETB_KBD_MODE_FN)
+ appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_SPCL);
+ } else if (value == 0) {
+ if (kbd->saved_mode != kbd->current_mode)
+ appletb_kbd_set_mode(kbd, kbd->saved_mode);
+ }
+ }
+}
+
+static int appletb_kbd_inp_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ struct appletb_kbd *kbd = handler->private;
+ struct input_handle *handle;
+ int rc;
+
+ if (id->driver_info == APPLETB_DEVID_KEYBOARD) {
+ handle = &kbd->kbd_handle;
+ handle->name = "tbkbd";
+ } else {
+ return -ENOENT;
+ }
+
+ if (handle->dev)
+ return -EEXIST;
+
+ handle->open = 0;
+ handle->dev = input_get_device(dev);
+ handle->handler = handler;
+ handle->private = kbd;
+
+ rc = input_register_handle(handle);
+ if (rc)
+ goto err_free_dev;
+
+ rc = input_open_device(handle);
+ if (rc)
+ goto err_unregister_handle;
+
+ return 0;
+
+ err_unregister_handle:
+ input_unregister_handle(handle);
+ err_free_dev:
+ input_put_device(handle->dev);
+ handle->dev = NULL;
+ return rc;
+}
+
+static void appletb_kbd_inp_disconnect(struct input_handle *handle)
+{
+ input_close_device(handle);
+ input_unregister_handle(handle);
+
+ input_put_device(handle->dev);
+ handle->dev = NULL;
+}
+
static int appletb_kbd_input_configured(struct hid_device *hdev, struct hid_input *hidinput)
{
int idx;
@@ -196,6 +274,40 @@ static int appletb_kbd_input_configured(struct hid_device *hdev, struct hid_inpu
return 0;
}
+static const struct input_device_id appletb_kbd_input_devices[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_BUS |
+ INPUT_DEVICE_ID_MATCH_VENDOR |
+ INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .bustype = BUS_USB,
+ .vendor = USB_VENDOR_ID_APPLE,
+ .keybit = { [BIT_WORD(KEY_FN)] = BIT_MASK(KEY_FN) },
+ .driver_info = APPLETB_DEVID_KEYBOARD,
+ },
+ { }
+};
+
+static bool appletb_kbd_match_internal_device(struct input_handler *handler,
+ struct input_dev *inp_dev)
+{
+ struct device *dev = &inp_dev->dev;
+
+ /* in kernel: dev && !is_usb_device(dev) */
+ while (dev && !(dev->type && dev->type->name &&
+ !strcmp(dev->type->name, "usb_device")))
+ dev = dev->parent;
+
+ /*
+ * Apple labels all their internal keyboards and trackpads as such,
+ * instead of maintaining an ever expanding list of product-id's we
+ * just look at the device's product name.
+ */
+ if (dev)
+ return !!strstr(to_usb_device(dev)->product, "Internal Keyboard");
+
+ return false;
+}
+
static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct appletb_kbd *kbd;
@@ -228,6 +340,20 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
goto stop_hw;
}
+ kbd->inp_handler.event = appletb_kbd_inp_event;
+ kbd->inp_handler.connect = appletb_kbd_inp_connect;
+ kbd->inp_handler.disconnect = appletb_kbd_inp_disconnect;
+ kbd->inp_handler.name = "appletb";
+ kbd->inp_handler.id_table = appletb_kbd_input_devices;
+ kbd->inp_handler.match = appletb_kbd_match_internal_device;
+ kbd->inp_handler.private = kbd;
+
+ ret = input_register_handler(&kbd->inp_handler);
+ if (ret) {
+ dev_err_probe(dev, ret, "Unable to register keyboard handler\n");
+ goto close_hw;
+ }
+
ret = appletb_kbd_set_mode(kbd, appletb_tb_def_mode);
if (ret) {
dev_err_probe(dev, ret, "Failed to set touchbar mode\n");
@@ -251,6 +377,8 @@ static void appletb_kbd_remove(struct hid_device *hdev)
appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
+ input_unregister_handler(&kbd->inp_handler);
+
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
--
2.43.0