diff options
Diffstat (limited to 'drivers/tty/vt/keyboard.c')
| -rw-r--r-- | drivers/tty/vt/keyboard.c | 50 |
1 files changed, 26 insertions, 24 deletions
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 48cc6f25cfd3..681765baef69 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c | |||
| @@ -119,6 +119,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals); | |||
| 119 | 119 | ||
| 120 | static struct input_handler kbd_handler; | 120 | static struct input_handler kbd_handler; |
| 121 | static DEFINE_SPINLOCK(kbd_event_lock); | 121 | static DEFINE_SPINLOCK(kbd_event_lock); |
| 122 | static DEFINE_SPINLOCK(led_lock); | ||
| 122 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ | 123 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ |
| 123 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ | 124 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ |
| 124 | static bool dead_key_next; | 125 | static bool dead_key_next; |
| @@ -310,7 +311,7 @@ static void put_queue(struct vc_data *vc, int ch) | |||
| 310 | 311 | ||
| 311 | if (tty) { | 312 | if (tty) { |
| 312 | tty_insert_flip_char(tty, ch, 0); | 313 | tty_insert_flip_char(tty, ch, 0); |
| 313 | con_schedule_flip(tty); | 314 | tty_schedule_flip(tty); |
| 314 | } | 315 | } |
| 315 | } | 316 | } |
| 316 | 317 | ||
| @@ -325,7 +326,7 @@ static void puts_queue(struct vc_data *vc, char *cp) | |||
| 325 | tty_insert_flip_char(tty, *cp, 0); | 326 | tty_insert_flip_char(tty, *cp, 0); |
| 326 | cp++; | 327 | cp++; |
| 327 | } | 328 | } |
| 328 | con_schedule_flip(tty); | 329 | tty_schedule_flip(tty); |
| 329 | } | 330 | } |
| 330 | 331 | ||
| 331 | static void applkey(struct vc_data *vc, int key, char mode) | 332 | static void applkey(struct vc_data *vc, int key, char mode) |
| @@ -586,7 +587,7 @@ static void fn_send_intr(struct vc_data *vc) | |||
| 586 | if (!tty) | 587 | if (!tty) |
| 587 | return; | 588 | return; |
| 588 | tty_insert_flip_char(tty, 0, TTY_BREAK); | 589 | tty_insert_flip_char(tty, 0, TTY_BREAK); |
| 589 | con_schedule_flip(tty); | 590 | tty_schedule_flip(tty); |
| 590 | } | 591 | } |
| 591 | 592 | ||
| 592 | static void fn_scroll_forw(struct vc_data *vc) | 593 | static void fn_scroll_forw(struct vc_data *vc) |
| @@ -984,7 +985,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) | |||
| 984 | * or (ii) whatever pattern of lights people want to show using KDSETLED, | 985 | * or (ii) whatever pattern of lights people want to show using KDSETLED, |
| 985 | * or (iii) specified bits of specified words in kernel memory. | 986 | * or (iii) specified bits of specified words in kernel memory. |
| 986 | */ | 987 | */ |
| 987 | unsigned char getledstate(void) | 988 | static unsigned char getledstate(void) |
| 988 | { | 989 | { |
| 989 | return ledstate; | 990 | return ledstate; |
| 990 | } | 991 | } |
| @@ -992,7 +993,7 @@ unsigned char getledstate(void) | |||
| 992 | void setledstate(struct kbd_struct *kbd, unsigned int led) | 993 | void setledstate(struct kbd_struct *kbd, unsigned int led) |
| 993 | { | 994 | { |
| 994 | unsigned long flags; | 995 | unsigned long flags; |
| 995 | spin_lock_irqsave(&kbd_event_lock, flags); | 996 | spin_lock_irqsave(&led_lock, flags); |
| 996 | if (!(led & ~7)) { | 997 | if (!(led & ~7)) { |
| 997 | ledioctl = led; | 998 | ledioctl = led; |
| 998 | kbd->ledmode = LED_SHOW_IOCTL; | 999 | kbd->ledmode = LED_SHOW_IOCTL; |
| @@ -1000,7 +1001,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) | |||
| 1000 | kbd->ledmode = LED_SHOW_FLAGS; | 1001 | kbd->ledmode = LED_SHOW_FLAGS; |
| 1001 | 1002 | ||
| 1002 | set_leds(); | 1003 | set_leds(); |
| 1003 | spin_unlock_irqrestore(&kbd_event_lock, flags); | 1004 | spin_unlock_irqrestore(&led_lock, flags); |
| 1004 | } | 1005 | } |
| 1005 | 1006 | ||
| 1006 | static inline unsigned char getleds(void) | 1007 | static inline unsigned char getleds(void) |
| @@ -1049,13 +1050,13 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) | |||
| 1049 | */ | 1050 | */ |
| 1050 | int vt_get_leds(int console, int flag) | 1051 | int vt_get_leds(int console, int flag) |
| 1051 | { | 1052 | { |
| 1052 | unsigned long flags; | ||
| 1053 | struct kbd_struct * kbd = kbd_table + console; | 1053 | struct kbd_struct * kbd = kbd_table + console; |
| 1054 | int ret; | 1054 | int ret; |
| 1055 | unsigned long flags; | ||
| 1055 | 1056 | ||
| 1056 | spin_lock_irqsave(&kbd_event_lock, flags); | 1057 | spin_lock_irqsave(&led_lock, flags); |
| 1057 | ret = vc_kbd_led(kbd, flag); | 1058 | ret = vc_kbd_led(kbd, flag); |
| 1058 | spin_unlock_irqrestore(&kbd_event_lock, flags); | 1059 | spin_unlock_irqrestore(&led_lock, flags); |
| 1059 | 1060 | ||
| 1060 | return ret; | 1061 | return ret; |
| 1061 | } | 1062 | } |
| @@ -1091,11 +1092,11 @@ void vt_set_led_state(int console, int leds) | |||
| 1091 | void vt_kbd_con_start(int console) | 1092 | void vt_kbd_con_start(int console) |
| 1092 | { | 1093 | { |
| 1093 | struct kbd_struct * kbd = kbd_table + console; | 1094 | struct kbd_struct * kbd = kbd_table + console; |
| 1094 | /* unsigned long flags; */ | 1095 | unsigned long flags; |
| 1095 | /* spin_lock_irqsave(&kbd_event_lock, flags); */ | 1096 | spin_lock_irqsave(&led_lock, flags); |
| 1096 | clr_vc_kbd_led(kbd, VC_SCROLLOCK); | 1097 | clr_vc_kbd_led(kbd, VC_SCROLLOCK); |
| 1097 | set_leds(); | 1098 | set_leds(); |
| 1098 | /* spin_unlock_irqrestore(&kbd_event_lock, flags); */ | 1099 | spin_unlock_irqrestore(&led_lock, flags); |
| 1099 | } | 1100 | } |
| 1100 | 1101 | ||
| 1101 | /** | 1102 | /** |
| @@ -1104,21 +1105,15 @@ void vt_kbd_con_start(int console) | |||
| 1104 | * | 1105 | * |
| 1105 | * Handle console stop. This is a wrapper for the VT layer | 1106 | * Handle console stop. This is a wrapper for the VT layer |
| 1106 | * so that we can keep kbd knowledge internal | 1107 | * so that we can keep kbd knowledge internal |
| 1107 | * | ||
| 1108 | * FIXME: We eventually need to hold the kbd lock here to protect | ||
| 1109 | * the LED updating. We can't do it yet because fn_hold calls stop_tty | ||
| 1110 | * and start_tty under the kbd_event_lock, while normal tty paths | ||
| 1111 | * don't hold the lock. We probably need to split out an LED lock | ||
| 1112 | * but not during an -rc release! | ||
| 1113 | */ | 1108 | */ |
| 1114 | void vt_kbd_con_stop(int console) | 1109 | void vt_kbd_con_stop(int console) |
| 1115 | { | 1110 | { |
| 1116 | struct kbd_struct * kbd = kbd_table + console; | 1111 | struct kbd_struct * kbd = kbd_table + console; |
| 1117 | /* unsigned long flags; */ | 1112 | unsigned long flags; |
| 1118 | /* spin_lock_irqsave(&kbd_event_lock, flags); */ | 1113 | spin_lock_irqsave(&led_lock, flags); |
| 1119 | set_vc_kbd_led(kbd, VC_SCROLLOCK); | 1114 | set_vc_kbd_led(kbd, VC_SCROLLOCK); |
| 1120 | set_leds(); | 1115 | set_leds(); |
| 1121 | /* spin_unlock_irqrestore(&kbd_event_lock, flags); */ | 1116 | spin_unlock_irqrestore(&led_lock, flags); |
| 1122 | } | 1117 | } |
| 1123 | 1118 | ||
| 1124 | /* | 1119 | /* |
| @@ -1130,7 +1125,12 @@ void vt_kbd_con_stop(int console) | |||
| 1130 | */ | 1125 | */ |
| 1131 | static void kbd_bh(unsigned long dummy) | 1126 | static void kbd_bh(unsigned long dummy) |
| 1132 | { | 1127 | { |
| 1133 | unsigned char leds = getleds(); | 1128 | unsigned char leds; |
| 1129 | unsigned long flags; | ||
| 1130 | |||
| 1131 | spin_lock_irqsave(&led_lock, flags); | ||
| 1132 | leds = getleds(); | ||
| 1133 | spin_unlock_irqrestore(&led_lock, flags); | ||
| 1134 | 1134 | ||
| 1135 | if (leds != ledstate) { | 1135 | if (leds != ledstate) { |
| 1136 | input_handler_for_each_handle(&kbd_handler, &leds, | 1136 | input_handler_for_each_handle(&kbd_handler, &leds, |
| @@ -2035,11 +2035,11 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) | |||
| 2035 | return -EPERM; | 2035 | return -EPERM; |
| 2036 | if (arg & ~0x77) | 2036 | if (arg & ~0x77) |
| 2037 | return -EINVAL; | 2037 | return -EINVAL; |
| 2038 | spin_lock_irqsave(&kbd_event_lock, flags); | 2038 | spin_lock_irqsave(&led_lock, flags); |
| 2039 | kbd->ledflagstate = (arg & 7); | 2039 | kbd->ledflagstate = (arg & 7); |
| 2040 | kbd->default_ledflagstate = ((arg >> 4) & 7); | 2040 | kbd->default_ledflagstate = ((arg >> 4) & 7); |
| 2041 | set_leds(); | 2041 | set_leds(); |
| 2042 | spin_unlock_irqrestore(&kbd_event_lock, flags); | 2042 | spin_unlock_irqrestore(&led_lock, flags); |
| 2043 | return 0; | 2043 | return 0; |
| 2044 | 2044 | ||
| 2045 | /* the ioctls below only set the lights, not the functions */ | 2045 | /* the ioctls below only set the lights, not the functions */ |
| @@ -2134,8 +2134,10 @@ void vt_reset_keyboard(int console) | |||
| 2134 | clr_vc_kbd_mode(kbd, VC_CRLF); | 2134 | clr_vc_kbd_mode(kbd, VC_CRLF); |
| 2135 | kbd->lockstate = 0; | 2135 | kbd->lockstate = 0; |
| 2136 | kbd->slockstate = 0; | 2136 | kbd->slockstate = 0; |
| 2137 | spin_lock(&led_lock); | ||
| 2137 | kbd->ledmode = LED_SHOW_FLAGS; | 2138 | kbd->ledmode = LED_SHOW_FLAGS; |
| 2138 | kbd->ledflagstate = kbd->default_ledflagstate; | 2139 | kbd->ledflagstate = kbd->default_ledflagstate; |
| 2140 | spin_unlock(&led_lock); | ||
| 2139 | /* do not do set_leds here because this causes an endless tasklet loop | 2141 | /* do not do set_leds here because this causes an endless tasklet loop |
| 2140 | when the keyboard hasn't been initialized yet */ | 2142 | when the keyboard hasn't been initialized yet */ |
| 2141 | spin_unlock_irqrestore(&kbd_event_lock, flags); | 2143 | spin_unlock_irqrestore(&kbd_event_lock, flags); |
