hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/input/keyboard/atkbd.c
....@@ -1,14 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * AT and PS/2 keyboard driver
34 *
45 * Copyright (c) 1999-2002 Vojtech Pavlik
56 */
67
7
-/*
8
- * This program is free software; you can redistribute it and/or modify it
9
- * under the terms of the GNU General Public License version 2 as published by
10
- * the Free Software Foundation.
11
- */
128
139 /*
1410 * This driver can handle standard AT keyboards and PS/2 keyboards in
....@@ -28,6 +24,7 @@
2824 #include <linux/libps2.h>
2925 #include <linux/mutex.h>
3026 #include <linux/dmi.h>
27
+#include <linux/property.h>
3128
3229 #define DRIVER_DESC "AT and PS/2 keyboard driver"
3330
....@@ -66,6 +63,11 @@
6663 static bool atkbd_terminal;
6764 module_param_named(terminal, atkbd_terminal, bool, 0);
6865 MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
66
+
67
+#define MAX_FUNCTION_ROW_KEYS 24
68
+
69
+#define SCANCODE(keymap) ((keymap >> 16) & 0xFFFF)
70
+#define KEYCODE(keymap) (keymap & 0xFFFF)
6971
7072 /*
7173 * Scancode to keycode tables. These are just the default setting, and
....@@ -234,6 +236,9 @@
234236
235237 /* Serializes reconnect(), attr->set() and event work */
236238 struct mutex mutex;
239
+
240
+ u32 function_row_physmap[MAX_FUNCTION_ROW_KEYS];
241
+ int num_function_row_keys;
237242 };
238243
239244 /*
....@@ -287,6 +292,7 @@
287292 __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);
288293
289294 ATKBD_DEFINE_RO_ATTR(err_count);
295
+ATKBD_DEFINE_RO_ATTR(function_row_physmap);
290296
291297 static struct attribute *atkbd_attributes[] = {
292298 &atkbd_attr_extra.attr,
....@@ -296,11 +302,42 @@
296302 &atkbd_attr_softrepeat.attr,
297303 &atkbd_attr_softraw.attr,
298304 &atkbd_attr_err_count.attr,
305
+ &atkbd_attr_function_row_physmap.attr,
299306 NULL
300307 };
301308
309
+static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf)
310
+{
311
+ ssize_t size = 0;
312
+ int i;
313
+
314
+ if (!atkbd->num_function_row_keys)
315
+ return 0;
316
+
317
+ for (i = 0; i < atkbd->num_function_row_keys; i++)
318
+ size += scnprintf(buf + size, PAGE_SIZE - size, "%02X ",
319
+ atkbd->function_row_physmap[i]);
320
+ size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
321
+ return size;
322
+}
323
+
324
+static umode_t atkbd_attr_is_visible(struct kobject *kobj,
325
+ struct attribute *attr, int i)
326
+{
327
+ struct device *dev = container_of(kobj, struct device, kobj);
328
+ struct serio *serio = to_serio_port(dev);
329
+ struct atkbd *atkbd = serio_get_drvdata(serio);
330
+
331
+ if (attr == &atkbd_attr_function_row_physmap.attr &&
332
+ !atkbd->num_function_row_keys)
333
+ return 0;
334
+
335
+ return attr->mode;
336
+}
337
+
302338 static struct attribute_group atkbd_attribute_group = {
303339 .attrs = atkbd_attributes,
340
+ .is_visible = atkbd_attr_is_visible,
304341 };
305342
306343 static const unsigned int xl_table[] = {
....@@ -400,6 +437,8 @@
400437 if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
401438 if (ps2_handle_response(&atkbd->ps2dev, data))
402439 goto out;
440
+
441
+ pm_wakeup_event(&serio->dev, 0);
403442
404443 if (!atkbd->enabled)
405444 goto out;
....@@ -841,7 +880,7 @@
841880 if (param[0] != 3) {
842881 param[0] = 2;
843882 if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
844
- return 2;
883
+ return 2;
845884 }
846885
847886 ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
....@@ -996,6 +1035,39 @@
9961035 return code;
9971036 }
9981037
1038
+static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
1039
+{
1040
+ struct device *dev = &atkbd->ps2dev.serio->dev;
1041
+ int i, n;
1042
+ u32 *ptr;
1043
+ u16 scancode, keycode;
1044
+
1045
+ /* Parse "linux,keymap" property */
1046
+ n = device_property_count_u32(dev, "linux,keymap");
1047
+ if (n <= 0 || n > ATKBD_KEYMAP_SIZE)
1048
+ return -ENXIO;
1049
+
1050
+ ptr = kcalloc(n, sizeof(u32), GFP_KERNEL);
1051
+ if (!ptr)
1052
+ return -ENOMEM;
1053
+
1054
+ if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) {
1055
+ dev_err(dev, "problem parsing FW keymap property\n");
1056
+ kfree(ptr);
1057
+ return -EINVAL;
1058
+ }
1059
+
1060
+ memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
1061
+ for (i = 0; i < n; i++) {
1062
+ scancode = SCANCODE(ptr[i]);
1063
+ keycode = KEYCODE(ptr[i]);
1064
+ atkbd->keycode[scancode] = keycode;
1065
+ }
1066
+
1067
+ kfree(ptr);
1068
+ return 0;
1069
+}
1070
+
9991071 /*
10001072 * atkbd_set_keycode_table() initializes keyboard's keycode table
10011073 * according to the selected scancode set
....@@ -1003,13 +1075,16 @@
10031075
10041076 static void atkbd_set_keycode_table(struct atkbd *atkbd)
10051077 {
1078
+ struct device *dev = &atkbd->ps2dev.serio->dev;
10061079 unsigned int scancode;
10071080 int i, j;
10081081
10091082 memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
10101083 bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
10111084
1012
- if (atkbd->translated) {
1085
+ if (!atkbd_get_keymap_from_fwnode(atkbd)) {
1086
+ dev_dbg(dev, "Using FW keymap\n");
1087
+ } else if (atkbd->translated) {
10131088 for (i = 0; i < 128; i++) {
10141089 scancode = atkbd_unxlate_table[i];
10151090 atkbd->keycode[i] = atkbd_set2_keycode[scancode];
....@@ -1123,6 +1198,22 @@
11231198 }
11241199 }
11251200
1201
+static void atkbd_parse_fwnode_data(struct serio *serio)
1202
+{
1203
+ struct atkbd *atkbd = serio_get_drvdata(serio);
1204
+ struct device *dev = &serio->dev;
1205
+ int n;
1206
+
1207
+ /* Parse "function-row-physmap" property */
1208
+ n = device_property_count_u32(dev, "function-row-physmap");
1209
+ if (n > 0 && n <= MAX_FUNCTION_ROW_KEYS &&
1210
+ !device_property_read_u32_array(dev, "function-row-physmap",
1211
+ atkbd->function_row_physmap, n)) {
1212
+ atkbd->num_function_row_keys = n;
1213
+ dev_dbg(dev, "FW reported %d function-row key locations\n", n);
1214
+ }
1215
+}
1216
+
11261217 /*
11271218 * atkbd_connect() is called when the serio module finds an interface
11281219 * that isn't handled yet by an appropriate device driver. We check if
....@@ -1150,7 +1241,7 @@
11501241
11511242 case SERIO_8042_XL:
11521243 atkbd->translated = true;
1153
- /* Fall through */
1244
+ fallthrough;
11541245
11551246 case SERIO_8042:
11561247 if (serio->write)
....@@ -1186,6 +1277,8 @@
11861277 atkbd->id = 0xab00;
11871278 }
11881279
1280
+ atkbd_parse_fwnode_data(serio);
1281
+
11891282 atkbd_set_keycode_table(atkbd);
11901283 atkbd_set_device_attrs(atkbd);
11911284