In order to ease the addition of the ability of an input to use a
different key configuration (keycode to keysym map), the operations of
getting and setting an entry in a key map is moved in respective
functions.

Signed-off-by: Remi Pommarel <r...@triplefau.lt>
Tested-by: Elie Roudninski <xade...@gmail.com>
---
 drivers/tty/vt/keyboard.c | 201 ++++++++++++++++++++++----------------
 1 file changed, 118 insertions(+), 83 deletions(-)

diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 88312c6c92cc..89fabb8ae04e 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1874,115 +1874,150 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode 
__user *user_kbkc,
        return kc;
 }
 
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
+#define i (kbe->kb_index)
+#define s (kbe->kb_table)
+#define v (kbe->kb_value)
 
-int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
-                                               int console)
+/*
+ * Get a keysym value from a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to find in key map
+ */
+static ushort __kdsk_getent(struct kbd_struct const *kb, ushort **kmaps,
+               struct kbentry const *kbe)
 {
-       struct kbd_struct *kb = kbd_table + console;
-       struct kbentry tmp;
-       ushort *key_map, *new_map, val, ov;
+       ushort *key_map, val;
        unsigned long flags;
 
-       if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
-               return -EFAULT;
+       /* Ensure another thread doesn't free it under us */
+       spin_lock_irqsave(&kbd_event_lock, flags);
+       key_map = kmaps[s];
+       if (key_map) {
+               val = U(key_map[i]);
+               if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+                       val = K_HOLE;
+       } else
+               val = (i ? K_HOLE : K_NOSUCHMAP);
+       spin_unlock_irqrestore(&kbd_event_lock, flags);
 
-       if (!capable(CAP_SYS_TTY_CONFIG))
-               perm = 0;
+       return val;
+}
 
-       switch (cmd) {
-       case KDGKBENT:
-               /* Ensure another thread doesn't free it under us */
+/*
+ * Set a keysym value in a key map
+ *
+ * @kb: Virtual console structure
+ * @kmaps: Key map array
+ * @kbe : Entry to set in key map
+ */
+static int __kdsk_setent(struct kbd_struct const *kb, ushort **kmaps,
+               struct kbentry const *kbe)
+{
+       ushort *key_map, *new_map, ov;
+       unsigned long flags;
+
+       if (!i && v == K_NOSUCHMAP) {
                spin_lock_irqsave(&kbd_event_lock, flags);
-               key_map = key_maps[s];
-               if (key_map) {
-                   val = U(key_map[i]);
-                   if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-                       val = K_HOLE;
-               } else
-                   val = (i ? K_HOLE : K_NOSUCHMAP);
-               spin_unlock_irqrestore(&kbd_event_lock, flags);
-               return put_user(val, &user_kbe->kb_value);
-       case KDSKBENT:
-               if (!perm)
-                       return -EPERM;
-               if (!i && v == K_NOSUCHMAP) {
-                       spin_lock_irqsave(&kbd_event_lock, flags);
-                       /* deallocate map */
-                       key_map = key_maps[s];
-                       if (s && key_map) {
-                           key_maps[s] = NULL;
-                           if (key_map[0] == U(K_ALLOCATED)) {
-                                       kfree(key_map);
-                                       keymap_count--;
-                           }
+               /* deallocate map */
+               key_map = kmaps[s];
+               if (s && key_map) {
+                       kmaps[s] = NULL;
+                       if (key_map[0] == U(K_ALLOCATED)) {
+                               kfree(key_map);
+                               keymap_count--;
                        }
-                       spin_unlock_irqrestore(&kbd_event_lock, flags);
-                       break;
                }
+               spin_unlock_irqrestore(&kbd_event_lock, flags);
+               return 0;
+       }
 
-               if (KTYP(v) < NR_TYPES) {
-                   if (KVAL(v) > max_vals[KTYP(v)])
-                               return -EINVAL;
-               } else
-                   if (kb->kbdmode != VC_UNICODE)
-                               return -EINVAL;
+       if (KTYP(v) < NR_TYPES) {
+               if (KVAL(v) > max_vals[KTYP(v)])
+                       return -EINVAL;
+       } else if (kb->kbdmode != VC_UNICODE)
+               return -EINVAL;
 
-               /* ++Geert: non-PC keyboards may generate keycode zero */
+       /* ++Geert: non-PC keyboards may generate keycode zero */
 #if !defined(__mc68000__) && !defined(__powerpc__)
-               /* assignment to entry 0 only tests validity of args */
-               if (!i)
-                       break;
+       /* assignment to entry 0 only tests validity of args */
+       if (!i)
+               return 0;
 #endif
 
-               new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
-               if (!new_map)
-                       return -ENOMEM;
-               spin_lock_irqsave(&kbd_event_lock, flags);
-               key_map = key_maps[s];
-               if (key_map == NULL) {
-                       int j;
-
-                       if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
-                           !capable(CAP_SYS_RESOURCE)) {
-                               spin_unlock_irqrestore(&kbd_event_lock, flags);
-                               kfree(new_map);
-                               return -EPERM;
-                       }
-                       key_maps[s] = new_map;
-                       key_map = new_map;
-                       key_map[0] = U(K_ALLOCATED);
-                       for (j = 1; j < NR_KEYS; j++)
-                               key_map[j] = U(K_HOLE);
-                       keymap_count++;
-               } else
-                       kfree(new_map);
+       new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
+       if (!new_map)
+               return -ENOMEM;
+       spin_lock_irqsave(&kbd_event_lock, flags);
+       key_map = kmaps[s];
+       if (key_map == NULL) {
+               int j;
 
-               ov = U(key_map[i]);
-               if (v == ov)
-                       goto out;
-               /*
-                * Attention Key.
-                */
-               if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) 
{
+               if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
+                               !capable(CAP_SYS_RESOURCE)) {
                        spin_unlock_irqrestore(&kbd_event_lock, flags);
+                       kfree(new_map);
                        return -EPERM;
                }
-               key_map[i] = U(v);
-               if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
-                       do_compute_shiftstate();
-out:
+               kmaps[s] = new_map;
+               key_map = new_map;
+               key_map[0] = U(K_ALLOCATED);
+               for (j = 1; j < NR_KEYS; j++)
+                       key_map[j] = U(K_HOLE);
+               keymap_count++;
+       } else
+               kfree(new_map);
+
+       ov = U(key_map[i]);
+       if (v == ov)
+               goto out;
+       /*
+        * Attention Key.
+        */
+       if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) {
                spin_unlock_irqrestore(&kbd_event_lock, flags);
-               break;
+               return -EPERM;
        }
+       key_map[i] = U(v);
+       if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
+               do_compute_shiftstate();
+out:
+       spin_unlock_irqrestore(&kbd_event_lock, flags);
        return 0;
 }
 #undef i
 #undef s
 #undef v
 
+int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
+                                               int console)
+{
+       struct kbd_struct *kb = kbd_table + console;
+       struct kbentry tmp;
+       ushort val;
+       int ret = 0;
+
+       if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
+               return -EFAULT;
+
+       if (!capable(CAP_SYS_TTY_CONFIG))
+               perm = 0;
+
+       switch (cmd) {
+       case KDGKBENT:
+               val = __kdsk_getent(kb, key_maps, &tmp);
+               ret = put_user(val, &user_kbe->kb_value);
+               break;
+       case KDSKBENT:
+               if (!perm)
+                       return -EPERM;
+               ret = __kdsk_setent(kb, key_maps, &tmp);
+               break;
+       }
+       return ret;
+}
+
 /* FIXME: This one needs untangling and locking */
 int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
 {
-- 
2.18.0

Reply via email to