--- zzzz-none-000/linux-3.10.107/drivers/tty/vt/keyboard.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/tty/vt/keyboard.c 2021-02-04 17:41:59.000000000 +0000 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -129,15 +130,9 @@ static int shift_state = 0; -static unsigned char ledstate = 0xff; /* undefined */ +static unsigned int ledstate = -1U; /* undefined */ static unsigned char ledioctl; -static struct ledptr { - unsigned int *addr; - unsigned int mask; - unsigned char valid:1; -} ledptrs[3]; - /* * Notifier list for console keyboard events */ @@ -274,30 +269,30 @@ static int kbd_rate_helper(struct input_handle *handle, void *data) { struct input_dev *dev = handle->dev; - struct kbd_repeat *rep = data; + struct kbd_repeat *rpt = data; if (test_bit(EV_REP, dev->evbit)) { - if (rep[0].delay > 0) + if (rpt[0].delay > 0) input_inject_event(handle, - EV_REP, REP_DELAY, rep[0].delay); - if (rep[0].period > 0) + EV_REP, REP_DELAY, rpt[0].delay); + if (rpt[0].period > 0) input_inject_event(handle, - EV_REP, REP_PERIOD, rep[0].period); + EV_REP, REP_PERIOD, rpt[0].period); - rep[1].delay = dev->rep[REP_DELAY]; - rep[1].period = dev->rep[REP_PERIOD]; + rpt[1].delay = dev->rep[REP_DELAY]; + rpt[1].period = dev->rep[REP_PERIOD]; } return 0; } -int kbd_rate(struct kbd_repeat *rep) +int kbd_rate(struct kbd_repeat *rpt) { - struct kbd_repeat data[2] = { *rep }; + struct kbd_repeat data[2] = { *rpt }; input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper); - *rep = data[1]; /* Copy currently used settings */ + *rpt = data[1]; /* Copy currently used settings */ return 0; } @@ -918,7 +913,7 @@ if (kbd->kbdmode != VC_UNICODE) { if (!up_flag) - pr_warning("keyboard mode must be unicode for braille patterns\n"); + pr_warn("keyboard mode must be unicode for braille patterns\n"); return; } @@ -955,56 +950,98 @@ } } -/* - * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, - * or (ii) whatever pattern of lights people want to show using KDSETLED, - * or (iii) specified bits of specified words in kernel memory. - */ -static unsigned char getledstate(void) +#if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS) + +struct kbd_led_trigger { + struct led_trigger trigger; + unsigned int mask; +}; + +static void kbd_led_trigger_activate(struct led_classdev *cdev) { - return ledstate; + struct kbd_led_trigger *trigger = + container_of(cdev->trigger, struct kbd_led_trigger, trigger); + + tasklet_disable(&keyboard_tasklet); + if (ledstate != -1U) + led_trigger_event(&trigger->trigger, + ledstate & trigger->mask ? + LED_FULL : LED_OFF); + tasklet_enable(&keyboard_tasklet); } -void setledstate(struct kbd_struct *kbd, unsigned int led) +#define KBD_LED_TRIGGER(_led_bit, _name) { \ + .trigger = { \ + .name = _name, \ + .activate = kbd_led_trigger_activate, \ + }, \ + .mask = BIT(_led_bit), \ + } + +#define KBD_LOCKSTATE_TRIGGER(_led_bit, _name) \ + KBD_LED_TRIGGER((_led_bit) + 8, _name) + +static struct kbd_led_trigger kbd_led_triggers[] = { + KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrolllock"), + KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"), + KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"), + KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"), + + KBD_LOCKSTATE_TRIGGER(VC_SHIFTLOCK, "kbd-shiftlock"), + KBD_LOCKSTATE_TRIGGER(VC_ALTGRLOCK, "kbd-altgrlock"), + KBD_LOCKSTATE_TRIGGER(VC_CTRLLOCK, "kbd-ctrllock"), + KBD_LOCKSTATE_TRIGGER(VC_ALTLOCK, "kbd-altlock"), + KBD_LOCKSTATE_TRIGGER(VC_SHIFTLLOCK, "kbd-shiftllock"), + KBD_LOCKSTATE_TRIGGER(VC_SHIFTRLOCK, "kbd-shiftrlock"), + KBD_LOCKSTATE_TRIGGER(VC_CTRLLLOCK, "kbd-ctrlllock"), + KBD_LOCKSTATE_TRIGGER(VC_CTRLRLOCK, "kbd-ctrlrlock"), +}; + +static void kbd_propagate_led_state(unsigned int old_state, + unsigned int new_state) { - unsigned long flags; - spin_lock_irqsave(&led_lock, flags); - if (!(led & ~7)) { - ledioctl = led; - kbd->ledmode = LED_SHOW_IOCTL; - } else - kbd->ledmode = LED_SHOW_FLAGS; + struct kbd_led_trigger *trigger; + unsigned int changed = old_state ^ new_state; + int i; - set_leds(); - spin_unlock_irqrestore(&led_lock, flags); + for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) { + trigger = &kbd_led_triggers[i]; + + if (changed & trigger->mask) + led_trigger_event(&trigger->trigger, + new_state & trigger->mask ? + LED_FULL : LED_OFF); + } } -static inline unsigned char getleds(void) +static int kbd_update_leds_helper(struct input_handle *handle, void *data) { - struct kbd_struct *kbd = kbd_table + fg_console; - unsigned char leds; - int i; + unsigned int led_state = *(unsigned int *)data; - if (kbd->ledmode == LED_SHOW_IOCTL) - return ledioctl; + if (test_bit(EV_LED, handle->dev->evbit)) + kbd_propagate_led_state(~led_state, led_state); - leds = kbd->ledflagstate; + return 0; +} - if (kbd->ledmode == LED_SHOW_MEM) { - for (i = 0; i < 3; i++) - if (ledptrs[i].valid) { - if (*ledptrs[i].addr & ledptrs[i].mask) - leds |= (1 << i); - else - leds &= ~(1 << i); - } +static void kbd_init_leds(void) +{ + int error; + int i; + + for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) { + error = led_trigger_register(&kbd_led_triggers[i].trigger); + if (error) + pr_err("error %d while registering trigger %s\n", + error, kbd_led_triggers[i].trigger.name); } - return leds; } +#else + static int kbd_update_leds_helper(struct input_handle *handle, void *data) { - unsigned char leds = *(unsigned char *)data; + unsigned int leds = *(unsigned int *)data; if (test_bit(EV_LED, handle->dev->evbit)) { input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); @@ -1016,6 +1053,53 @@ return 0; } +static void kbd_propagate_led_state(unsigned int old_state, + unsigned int new_state) +{ + input_handler_for_each_handle(&kbd_handler, &new_state, + kbd_update_leds_helper); +} + +static void kbd_init_leds(void) +{ +} + +#endif + +/* + * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, + * or (ii) whatever pattern of lights people want to show using KDSETLED, + * or (iii) specified bits of specified words in kernel memory. + */ +static unsigned char getledstate(void) +{ + return ledstate & 0xff; +} + +void setledstate(struct kbd_struct *kb, unsigned int led) +{ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); + if (!(led & ~7)) { + ledioctl = led; + kb->ledmode = LED_SHOW_IOCTL; + } else + kb->ledmode = LED_SHOW_FLAGS; + + set_leds(); + spin_unlock_irqrestore(&led_lock, flags); +} + +static inline unsigned char getleds(void) +{ + struct kbd_struct *kb = kbd_table + fg_console; + + if (kb->ledmode == LED_SHOW_IOCTL) + return ledioctl; + + return kb->ledflagstate; +} + /** * vt_get_leds - helper for braille console * @console: console to read @@ -1025,12 +1109,12 @@ */ int vt_get_leds(int console, int flag) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; int ret; unsigned long flags; spin_lock_irqsave(&led_lock, flags); - ret = vc_kbd_led(kbd, flag); + ret = vc_kbd_led(kb, flag); spin_unlock_irqrestore(&led_lock, flags); return ret; @@ -1047,8 +1131,8 @@ */ void vt_set_led_state(int console, int leds) { - struct kbd_struct * kbd = kbd_table + console; - setledstate(kbd, leds); + struct kbd_struct *kb = kbd_table + console; + setledstate(kb, leds); } /** @@ -1066,10 +1150,10 @@ */ void vt_kbd_con_start(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&led_lock, flags); - clr_vc_kbd_led(kbd, VC_SCROLLOCK); + clr_vc_kbd_led(kb, VC_SCROLLOCK); set_leds(); spin_unlock_irqrestore(&led_lock, flags); } @@ -1083,33 +1167,32 @@ */ void vt_kbd_con_stop(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&led_lock, flags); - set_vc_kbd_led(kbd, VC_SCROLLOCK); + set_vc_kbd_led(kb, VC_SCROLLOCK); set_leds(); spin_unlock_irqrestore(&led_lock, flags); } /* - * This is the tasklet that updates LED state on all keyboards - * attached to the box. The reason we use tasklet is that we - * need to handle the scenario when keyboard handler is not - * registered yet but we already getting updates from the VT to - * update led state. + * This is the tasklet that updates LED state of LEDs using standard + * keyboard triggers. The reason we use tasklet is that we need to + * handle the scenario when keyboard handler is not registered yet + * but we already getting updates from the VT to update led state. */ static void kbd_bh(unsigned long dummy) { - unsigned char leds; + unsigned int leds; unsigned long flags; - + spin_lock_irqsave(&led_lock, flags); leds = getleds(); + leds |= (unsigned int)kbd->lockstate << 8; spin_unlock_irqrestore(&led_lock, flags); if (leds != ledstate) { - input_handler_for_each_handle(&kbd_handler, &leds, - kbd_update_leds_helper); + kbd_propagate_led_state(ledstate, leds); ledstate = leds; } } @@ -1260,8 +1343,8 @@ if (raw_mode && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) if (keycode < BTN_MISC && printk_ratelimit()) - pr_warning("can't emulate rawmode for keycode %d\n", - keycode); + pr_warn("can't emulate rawmode for keycode %d\n", + keycode); #ifdef CONFIG_SPARC if (keycode == KEY_A && sparc_l1_a_state) { @@ -1457,7 +1540,7 @@ { tasklet_disable(&keyboard_tasklet); - if (ledstate != 0xff) + if (ledstate != -1U) kbd_update_leds_helper(handle, &ledstate); tasklet_enable(&keyboard_tasklet); @@ -1504,6 +1587,8 @@ kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; } + kbd_init_leds(); + error = input_register_handler(&kbd_handler); if (error) return error; @@ -1519,15 +1604,14 @@ /** * vt_do_diacrit - diacritical table updates * @cmd: ioctl request - * @up: pointer to user data for ioctl + * @udp: pointer to user data for ioctl * @perm: permissions check computed by caller * * Update the diacritical tables atomically and safely. Lock them * against simultaneous keypresses */ -int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) +int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) { - struct kbdiacrs __user *a = up; unsigned long flags; int asize; int ret = 0; @@ -1535,12 +1619,13 @@ switch (cmd) { case KDGKBDIACR: { - struct kbdiacr *diacr; + struct kbdiacrs __user *a = udp; + struct kbdiacr *dia; int i; - diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr), + dia = kmalloc(MAX_DIACR * sizeof(struct kbdiacr), GFP_KERNEL); - if (diacr == NULL) + if (!dia) return -ENOMEM; /* Lock the diacriticals table, make a copy and then @@ -1549,26 +1634,26 @@ asize = accent_table_size; for (i = 0; i < asize; i++) { - diacr[i].diacr = conv_uni_to_8bit( + dia[i].diacr = conv_uni_to_8bit( accent_table[i].diacr); - diacr[i].base = conv_uni_to_8bit( + dia[i].base = conv_uni_to_8bit( accent_table[i].base); - diacr[i].result = conv_uni_to_8bit( + dia[i].result = conv_uni_to_8bit( accent_table[i].result); } spin_unlock_irqrestore(&kbd_event_lock, flags); if (put_user(asize, &a->kb_cnt)) ret = -EFAULT; - else if (copy_to_user(a->kbdiacr, diacr, + else if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr))) ret = -EFAULT; - kfree(diacr); + kfree(dia); return ret; } case KDGKBDIACRUC: { - struct kbdiacrsuc __user *a = up; + struct kbdiacrsuc __user *a = udp; void *buf; buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc), @@ -1596,8 +1681,8 @@ case KDSKBDIACR: { - struct kbdiacrs __user *a = up; - struct kbdiacr *diacr = NULL; + struct kbdiacrs __user *a = udp; + struct kbdiacr *dia = NULL; unsigned int ct; int i; @@ -1609,14 +1694,14 @@ return -EINVAL; if (ct) { - diacr = kmalloc(sizeof(struct kbdiacr) * ct, + dia = kmalloc(sizeof(struct kbdiacr) * ct, GFP_KERNEL); - if (diacr == NULL) + if (!dia) return -ENOMEM; - if (copy_from_user(diacr, a->kbdiacr, + if (copy_from_user(dia, a->kbdiacr, sizeof(struct kbdiacr) * ct)) { - kfree(diacr); + kfree(dia); return -EFAULT; } } @@ -1625,20 +1710,20 @@ accent_table_size = ct; for (i = 0; i < ct; i++) { accent_table[i].diacr = - conv_8bit_to_uni(diacr[i].diacr); + conv_8bit_to_uni(dia[i].diacr); accent_table[i].base = - conv_8bit_to_uni(diacr[i].base); + conv_8bit_to_uni(dia[i].base); accent_table[i].result = - conv_8bit_to_uni(diacr[i].result); + conv_8bit_to_uni(dia[i].result); } spin_unlock_irqrestore(&kbd_event_lock, flags); - kfree(diacr); + kfree(dia); return 0; } case KDSKBDIACRUC: { - struct kbdiacrsuc __user *a = up; + struct kbdiacrsuc __user *a = udp; unsigned int ct; void *buf = NULL; @@ -1686,28 +1771,28 @@ */ int vt_do_kdskbmode(int console, unsigned int arg) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; int ret = 0; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); switch(arg) { case K_RAW: - kbd->kbdmode = VC_RAW; + kb->kbdmode = VC_RAW; break; case K_MEDIUMRAW: - kbd->kbdmode = VC_MEDIUMRAW; + kb->kbdmode = VC_MEDIUMRAW; break; case K_XLATE: - kbd->kbdmode = VC_XLATE; + kb->kbdmode = VC_XLATE; do_compute_shiftstate(); break; case K_UNICODE: - kbd->kbdmode = VC_UNICODE; + kb->kbdmode = VC_UNICODE; do_compute_shiftstate(); break; case K_OFF: - kbd->kbdmode = VC_OFF; + kb->kbdmode = VC_OFF; break; default: ret = -EINVAL; @@ -1726,17 +1811,17 @@ */ int vt_do_kdskbmeta(int console, unsigned int arg) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; int ret = 0; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); switch(arg) { case K_METABIT: - clr_vc_kbd_mode(kbd, VC_META); + clr_vc_kbd_mode(kb, VC_META); break; case K_ESCPREFIX: - set_vc_kbd_mode(kbd, VC_META); + set_vc_kbd_mode(kb, VC_META); break; default: ret = -EINVAL; @@ -1775,7 +1860,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; struct kbentry tmp; ushort *key_map, *new_map, val, ov; unsigned long flags; @@ -1793,7 +1878,7 @@ key_map = key_maps[s]; if (key_map) { val = U(key_map[i]); - if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) val = K_HOLE; } else val = (i ? K_HOLE : K_NOSUCHMAP); @@ -1821,7 +1906,7 @@ if (KVAL(v) > max_vals[KTYP(v)]) return -EINVAL; } else - if (kbd->kbdmode != VC_UNICODE) + if (kb->kbdmode != VC_UNICODE) return -EINVAL; /* ++Geert: non-PC keyboards may generate keycode zero */ @@ -1992,7 +2077,7 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; unsigned char ucval; @@ -2001,7 +2086,7 @@ /* don't use them - they will go away without warning */ case KDGKBLED: spin_lock_irqsave(&kbd_event_lock, flags); - ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); + ucval = kb->ledflagstate | (kb->default_ledflagstate << 4); spin_unlock_irqrestore(&kbd_event_lock, flags); return put_user(ucval, (char __user *)arg); @@ -2011,8 +2096,8 @@ if (arg & ~0x77) return -EINVAL; spin_lock_irqsave(&led_lock, flags); - kbd->ledflagstate = (arg & 7); - kbd->default_ledflagstate = ((arg >> 4) & 7); + kb->ledflagstate = (arg & 7); + kb->default_ledflagstate = ((arg >> 4) & 7); set_leds(); spin_unlock_irqrestore(&led_lock, flags); return 0; @@ -2026,7 +2111,7 @@ case KDSETLED: if (!perm) return -EPERM; - setledstate(kbd, arg); + setledstate(kb, arg); return 0; } return -ENOIOCTLCMD; @@ -2034,9 +2119,9 @@ int vt_do_kdgkbmode(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; /* This is a spot read so needs no locking */ - switch (kbd->kbdmode) { + switch (kb->kbdmode) { case VC_RAW: return K_RAW; case VC_MEDIUMRAW: @@ -2058,9 +2143,9 @@ */ int vt_do_kdgkbmeta(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; /* Again a spot read so no locking */ - return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT; + return vc_kbd_mode(kb, VC_META) ? K_ESCPREFIX : K_METABIT; } /** @@ -2099,19 +2184,19 @@ */ void vt_reset_keyboard(int console) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); - set_vc_kbd_mode(kbd, VC_REPEAT); - clr_vc_kbd_mode(kbd, VC_CKMODE); - clr_vc_kbd_mode(kbd, VC_APPLIC); - clr_vc_kbd_mode(kbd, VC_CRLF); - kbd->lockstate = 0; - kbd->slockstate = 0; + set_vc_kbd_mode(kb, VC_REPEAT); + clr_vc_kbd_mode(kb, VC_CKMODE); + clr_vc_kbd_mode(kb, VC_APPLIC); + clr_vc_kbd_mode(kb, VC_CRLF); + kb->lockstate = 0; + kb->slockstate = 0; spin_lock(&led_lock); - kbd->ledmode = LED_SHOW_FLAGS; - kbd->ledflagstate = kbd->default_ledflagstate; + kb->ledmode = LED_SHOW_FLAGS; + kb->ledflagstate = kb->default_ledflagstate; spin_unlock(&led_lock); /* do not do set_leds here because this causes an endless tasklet loop when the keyboard hasn't been initialized yet */ @@ -2129,8 +2214,8 @@ int vt_get_kbd_mode_bit(int console, int bit) { - struct kbd_struct * kbd = kbd_table + console; - return vc_kbd_mode(kbd, bit); + struct kbd_struct *kb = kbd_table + console; + return vc_kbd_mode(kb, bit); } /** @@ -2144,11 +2229,11 @@ void vt_set_kbd_mode_bit(int console, int bit) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); - set_vc_kbd_mode(kbd, bit); + set_vc_kbd_mode(kb, bit); spin_unlock_irqrestore(&kbd_event_lock, flags); } @@ -2163,10 +2248,10 @@ void vt_clr_kbd_mode_bit(int console, int bit) { - struct kbd_struct * kbd = kbd_table + console; + struct kbd_struct *kb = kbd_table + console; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); - clr_vc_kbd_mode(kbd, bit); + clr_vc_kbd_mode(kb, bit); spin_unlock_irqrestore(&kbd_event_lock, flags); }