2626#define APPLETB_KBD_MODE_OFF 3
2727#define APPLETB_KBD_MODE_MAX APPLETB_KBD_MODE_OFF
2828
29+ #define APPLETB_DEVID_KEYBOARD 1
30+
2931#define HID_USAGE_MODE 0x00ff0004
3032
3133static int appletb_tb_def_mode = APPLETB_KBD_MODE_SPCL ;
@@ -35,11 +37,18 @@ MODULE_PARM_DESC(mode, "Default touchbar mode:\n"
3537 " 1 - function-keys\n"
3638 " [2] - special keys" );
3739
40+ static bool appletb_tb_fn_toggle = true;
41+ module_param_named (fntoggle , appletb_tb_fn_toggle , bool , 0644 );
42+ MODULE_PARM_DESC (fntoggle , "Switch between Fn and media controls on pressing Fn key" );
43+
3844struct appletb_kbd {
3945 struct hid_field * mode_field ;
4046
4147 u8 saved_mode ;
4248 u8 current_mode ;
49+ struct input_handler inp_handler ;
50+ struct input_handle kbd_handle ;
51+
4352};
4453
4554static 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
172181 return kbd -> current_mode == APPLETB_KBD_MODE_OFF ;
173182}
174183
184+ static void appletb_kbd_inp_event (struct input_handle * handle , unsigned int type ,
185+ unsigned int code , int value )
186+ {
187+ struct appletb_kbd * kbd = handle -> private ;
188+
189+ if (type == EV_KEY && code == KEY_FN && appletb_tb_fn_toggle ) {
190+ if (value == 1 ) {
191+ kbd -> saved_mode = kbd -> current_mode ;
192+ if (kbd -> current_mode == APPLETB_KBD_MODE_SPCL )
193+ appletb_kbd_set_mode (kbd , APPLETB_KBD_MODE_FN );
194+ else if (kbd -> current_mode == APPLETB_KBD_MODE_FN )
195+ appletb_kbd_set_mode (kbd , APPLETB_KBD_MODE_SPCL );
196+ } else if (value == 0 ) {
197+ if (kbd -> saved_mode != kbd -> current_mode )
198+ appletb_kbd_set_mode (kbd , kbd -> saved_mode );
199+ }
200+ }
201+ }
202+
203+ static int appletb_kbd_inp_connect (struct input_handler * handler ,
204+ struct input_dev * dev ,
205+ const struct input_device_id * id )
206+ {
207+ struct appletb_kbd * kbd = handler -> private ;
208+ struct input_handle * handle ;
209+ int rc ;
210+
211+ if (id -> driver_info == APPLETB_DEVID_KEYBOARD ) {
212+ handle = & kbd -> kbd_handle ;
213+ handle -> name = "tbkbd" ;
214+ } else {
215+ return - ENOENT ;
216+ }
217+
218+ if (handle -> dev )
219+ return - EEXIST ;
220+
221+ handle -> open = 0 ;
222+ handle -> dev = input_get_device (dev );
223+ handle -> handler = handler ;
224+ handle -> private = kbd ;
225+
226+ rc = input_register_handle (handle );
227+ if (rc )
228+ goto err_free_dev ;
229+
230+ rc = input_open_device (handle );
231+ if (rc )
232+ goto err_unregister_handle ;
233+
234+ return 0 ;
235+
236+ err_unregister_handle :
237+ input_unregister_handle (handle );
238+ err_free_dev :
239+ input_put_device (handle -> dev );
240+ handle -> dev = NULL ;
241+ return rc ;
242+ }
243+
244+ static void appletb_kbd_inp_disconnect (struct input_handle * handle )
245+ {
246+ input_close_device (handle );
247+ input_unregister_handle (handle );
248+
249+ input_put_device (handle -> dev );
250+ handle -> dev = NULL ;
251+ }
252+
175253static int appletb_kbd_input_configured (struct hid_device * hdev , struct hid_input * hidinput )
176254{
177255 int idx ;
@@ -195,6 +273,40 @@ static int appletb_kbd_input_configured(struct hid_device *hdev, struct hid_inpu
195273 return 0 ;
196274}
197275
276+ static const struct input_device_id appletb_kbd_input_devices [] = {
277+ {
278+ .flags = INPUT_DEVICE_ID_MATCH_BUS |
279+ INPUT_DEVICE_ID_MATCH_VENDOR |
280+ INPUT_DEVICE_ID_MATCH_KEYBIT ,
281+ .bustype = BUS_USB ,
282+ .vendor = USB_VENDOR_ID_APPLE ,
283+ .keybit = { [BIT_WORD (KEY_FN )] = BIT_MASK (KEY_FN ) },
284+ .driver_info = APPLETB_DEVID_KEYBOARD ,
285+ },
286+ { }
287+ };
288+
289+ static bool appletb_kbd_match_internal_device (struct input_handler * handler ,
290+ struct input_dev * inp_dev )
291+ {
292+ struct device * dev = & inp_dev -> dev ;
293+
294+ /* in kernel: dev && !is_usb_device(dev) */
295+ while (dev && !(dev -> type && dev -> type -> name &&
296+ !strcmp (dev -> type -> name , "usb_device" )))
297+ dev = dev -> parent ;
298+
299+ /*
300+ * Apple labels all their internal keyboards and trackpads as such,
301+ * instead of maintaining an ever expanding list of product-id's we
302+ * just look at the device's product name.
303+ */
304+ if (dev )
305+ return !!strstr (to_usb_device (dev )-> product , "Internal Keyboard" );
306+
307+ return false;
308+ }
309+
198310static int appletb_kbd_probe (struct hid_device * hdev , const struct hid_device_id * id )
199311{
200312 struct appletb_kbd * kbd ;
@@ -227,6 +339,20 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
227339 goto stop_hw ;
228340 }
229341
342+ kbd -> inp_handler .event = appletb_kbd_inp_event ;
343+ kbd -> inp_handler .connect = appletb_kbd_inp_connect ;
344+ kbd -> inp_handler .disconnect = appletb_kbd_inp_disconnect ;
345+ kbd -> inp_handler .name = "appletb" ;
346+ kbd -> inp_handler .id_table = appletb_kbd_input_devices ;
347+ kbd -> inp_handler .match = appletb_kbd_match_internal_device ;
348+ kbd -> inp_handler .private = kbd ;
349+
350+ ret = input_register_handler (& kbd -> inp_handler );
351+ if (ret ) {
352+ dev_err_probe (dev , ret , "Unable to register keyboard handler\n" );
353+ goto close_hw ;
354+ }
355+
230356 ret = appletb_kbd_set_mode (kbd , appletb_tb_def_mode );
231357 if (ret ) {
232358 dev_err_probe (dev , ret , "Failed to set touchbar mode\n" );
@@ -250,6 +376,8 @@ static void appletb_kbd_remove(struct hid_device *hdev)
250376
251377 appletb_kbd_set_mode (kbd , APPLETB_KBD_MODE_OFF );
252378
379+ input_unregister_handler (& kbd -> inp_handler );
380+
253381 hid_hw_close (hdev );
254382 hid_hw_stop (hdev );
255383}
0 commit comments