diff options
Diffstat (limited to 'drivers/char/keyboard.c')
-rw-r--r-- | drivers/char/keyboard.c | 213 |
1 files changed, 114 insertions, 99 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 950837cf9e9c..5619007e7e05 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
@@ -46,8 +46,6 @@ | |||
46 | 46 | ||
47 | extern void ctrl_alt_del(void); | 47 | extern void ctrl_alt_del(void); |
48 | 48 | ||
49 | #define to_handle_h(n) container_of(n, struct input_handle, h_node) | ||
50 | |||
51 | /* | 49 | /* |
52 | * Exported functions/variables | 50 | * Exported functions/variables |
53 | */ | 51 | */ |
@@ -132,6 +130,7 @@ int shift_state = 0; | |||
132 | */ | 130 | */ |
133 | 131 | ||
134 | static struct input_handler kbd_handler; | 132 | static struct input_handler kbd_handler; |
133 | static DEFINE_SPINLOCK(kbd_event_lock); | ||
135 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ | 134 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ |
136 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ | 135 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ |
137 | static int dead_key_next; | 136 | static int dead_key_next; |
@@ -190,78 +189,85 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier); | |||
190 | * etc.). So this means that scancodes for the extra function keys won't | 189 | * etc.). So this means that scancodes for the extra function keys won't |
191 | * be valid for the first event device, but will be for the second. | 190 | * be valid for the first event device, but will be for the second. |
192 | */ | 191 | */ |
192 | |||
193 | struct getset_keycode_data { | ||
194 | unsigned int scancode; | ||
195 | unsigned int keycode; | ||
196 | int error; | ||
197 | }; | ||
198 | |||
199 | static int getkeycode_helper(struct input_handle *handle, void *data) | ||
200 | { | ||
201 | struct getset_keycode_data *d = data; | ||
202 | |||
203 | d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode); | ||
204 | |||
205 | return d->error == 0; /* stop as soon as we successfully get one */ | ||
206 | } | ||
207 | |||
193 | int getkeycode(unsigned int scancode) | 208 | int getkeycode(unsigned int scancode) |
194 | { | 209 | { |
195 | struct input_handle *handle; | 210 | struct getset_keycode_data d = { scancode, 0, -ENODEV }; |
196 | int keycode; | ||
197 | int error = -ENODEV; | ||
198 | 211 | ||
199 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { | 212 | input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper); |
200 | error = input_get_keycode(handle->dev, scancode, &keycode); | ||
201 | if (!error) | ||
202 | return keycode; | ||
203 | } | ||
204 | 213 | ||
205 | return error; | 214 | return d.error ?: d.keycode; |
215 | } | ||
216 | |||
217 | static int setkeycode_helper(struct input_handle *handle, void *data) | ||
218 | { | ||
219 | struct getset_keycode_data *d = data; | ||
220 | |||
221 | d->error = input_set_keycode(handle->dev, d->scancode, d->keycode); | ||
222 | |||
223 | return d->error == 0; /* stop as soon as we successfully set one */ | ||
206 | } | 224 | } |
207 | 225 | ||
208 | int setkeycode(unsigned int scancode, unsigned int keycode) | 226 | int setkeycode(unsigned int scancode, unsigned int keycode) |
209 | { | 227 | { |
210 | struct input_handle *handle; | 228 | struct getset_keycode_data d = { scancode, keycode, -ENODEV }; |
211 | int error = -ENODEV; | ||
212 | 229 | ||
213 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { | 230 | input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper); |
214 | error = input_set_keycode(handle->dev, scancode, keycode); | ||
215 | if (!error) | ||
216 | break; | ||
217 | } | ||
218 | 231 | ||
219 | return error; | 232 | return d.error; |
220 | } | 233 | } |
221 | 234 | ||
222 | /* | 235 | /* |
223 | * Making beeps and bells. | 236 | * Making beeps and bells. |
224 | */ | 237 | */ |
225 | static void kd_nosound(unsigned long ignored) | 238 | |
239 | static int kd_sound_helper(struct input_handle *handle, void *data) | ||
226 | { | 240 | { |
227 | struct input_handle *handle; | 241 | unsigned int *hz = data; |
242 | struct input_dev *dev = handle->dev; | ||
228 | 243 | ||
229 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { | 244 | if (test_bit(EV_SND, dev->evbit)) { |
230 | if (test_bit(EV_SND, handle->dev->evbit)) { | 245 | if (test_bit(SND_TONE, dev->sndbit)) |
231 | if (test_bit(SND_TONE, handle->dev->sndbit)) | 246 | input_inject_event(handle, EV_SND, SND_TONE, *hz); |
232 | input_inject_event(handle, EV_SND, SND_TONE, 0); | 247 | if (test_bit(SND_BELL, handle->dev->sndbit)) |
233 | if (test_bit(SND_BELL, handle->dev->sndbit)) | 248 | input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0); |
234 | input_inject_event(handle, EV_SND, SND_BELL, 0); | ||
235 | } | ||
236 | } | 249 | } |
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static void kd_nosound(unsigned long ignored) | ||
255 | { | ||
256 | static unsigned int zero; | ||
257 | |||
258 | input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper); | ||
237 | } | 259 | } |
238 | 260 | ||
239 | static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); | 261 | static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); |
240 | 262 | ||
241 | void kd_mksound(unsigned int hz, unsigned int ticks) | 263 | void kd_mksound(unsigned int hz, unsigned int ticks) |
242 | { | 264 | { |
243 | struct list_head *node; | 265 | del_timer_sync(&kd_mksound_timer); |
244 | 266 | ||
245 | del_timer(&kd_mksound_timer); | 267 | input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper); |
246 | 268 | ||
247 | if (hz) { | 269 | if (hz && ticks) |
248 | list_for_each_prev(node, &kbd_handler.h_list) { | 270 | mod_timer(&kd_mksound_timer, jiffies + ticks); |
249 | struct input_handle *handle = to_handle_h(node); | ||
250 | if (test_bit(EV_SND, handle->dev->evbit)) { | ||
251 | if (test_bit(SND_TONE, handle->dev->sndbit)) { | ||
252 | input_inject_event(handle, EV_SND, SND_TONE, hz); | ||
253 | break; | ||
254 | } | ||
255 | if (test_bit(SND_BELL, handle->dev->sndbit)) { | ||
256 | input_inject_event(handle, EV_SND, SND_BELL, 1); | ||
257 | break; | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | if (ticks) | ||
262 | mod_timer(&kd_mksound_timer, jiffies + ticks); | ||
263 | } else | ||
264 | kd_nosound(0); | ||
265 | } | 271 | } |
266 | EXPORT_SYMBOL(kd_mksound); | 272 | EXPORT_SYMBOL(kd_mksound); |
267 | 273 | ||
@@ -269,27 +275,34 @@ EXPORT_SYMBOL(kd_mksound); | |||
269 | * Setting the keyboard rate. | 275 | * Setting the keyboard rate. |
270 | */ | 276 | */ |
271 | 277 | ||
272 | int kbd_rate(struct kbd_repeat *rep) | 278 | static int kbd_rate_helper(struct input_handle *handle, void *data) |
273 | { | 279 | { |
274 | struct list_head *node; | 280 | struct input_dev *dev = handle->dev; |
275 | unsigned int d = 0; | 281 | struct kbd_repeat *rep = data; |
276 | unsigned int p = 0; | 282 | |
277 | 283 | if (test_bit(EV_REP, dev->evbit)) { | |
278 | list_for_each(node, &kbd_handler.h_list) { | 284 | |
279 | struct input_handle *handle = to_handle_h(node); | 285 | if (rep[0].delay > 0) |
280 | struct input_dev *dev = handle->dev; | 286 | input_inject_event(handle, |
281 | 287 | EV_REP, REP_DELAY, rep[0].delay); | |
282 | if (test_bit(EV_REP, dev->evbit)) { | 288 | if (rep[0].period > 0) |
283 | if (rep->delay > 0) | 289 | input_inject_event(handle, |
284 | input_inject_event(handle, EV_REP, REP_DELAY, rep->delay); | 290 | EV_REP, REP_PERIOD, rep[0].period); |
285 | if (rep->period > 0) | 291 | |
286 | input_inject_event(handle, EV_REP, REP_PERIOD, rep->period); | 292 | rep[1].delay = dev->rep[REP_DELAY]; |
287 | d = dev->rep[REP_DELAY]; | 293 | rep[1].period = dev->rep[REP_PERIOD]; |
288 | p = dev->rep[REP_PERIOD]; | ||
289 | } | ||
290 | } | 294 | } |
291 | rep->delay = d; | 295 | |
292 | rep->period = p; | 296 | return 0; |
297 | } | ||
298 | |||
299 | int kbd_rate(struct kbd_repeat *rep) | ||
300 | { | ||
301 | struct kbd_repeat data[2] = { *rep }; | ||
302 | |||
303 | input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper); | ||
304 | *rep = data[1]; /* Copy currently used settings */ | ||
305 | |||
293 | return 0; | 306 | return 0; |
294 | } | 307 | } |
295 | 308 | ||
@@ -997,36 +1010,36 @@ static inline unsigned char getleds(void) | |||
997 | return leds; | 1010 | return leds; |
998 | } | 1011 | } |
999 | 1012 | ||
1013 | static int kbd_update_leds_helper(struct input_handle *handle, void *data) | ||
1014 | { | ||
1015 | unsigned char leds = *(unsigned char *)data; | ||
1016 | |||
1017 | if (test_bit(EV_LED, handle->dev->evbit)) { | ||
1018 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); | ||
1019 | input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); | ||
1020 | input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); | ||
1021 | input_inject_event(handle, EV_SYN, SYN_REPORT, 0); | ||
1022 | } | ||
1023 | |||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1000 | /* | 1027 | /* |
1001 | * This routine is the bottom half of the keyboard interrupt | 1028 | * This is the tasklet that updates LED state on all keyboards |
1002 | * routine, and runs with all interrupts enabled. It does | 1029 | * attached to the box. The reason we use tasklet is that we |
1003 | * console changing, led setting and copy_to_cooked, which can | 1030 | * need to handle the scenario when keyboard handler is not |
1004 | * take a reasonably long time. | 1031 | * registered yet but we already getting updates form VT to |
1005 | * | 1032 | * update led state. |
1006 | * Aside from timing (which isn't really that important for | ||
1007 | * keyboard interrupts as they happen often), using the software | ||
1008 | * interrupt routines for this thing allows us to easily mask | ||
1009 | * this when we don't want any of the above to happen. | ||
1010 | * This allows for easy and efficient race-condition prevention | ||
1011 | * for kbd_start => input_inject_event(dev, EV_LED, ...) => ... | ||
1012 | */ | 1033 | */ |
1013 | |||
1014 | static void kbd_bh(unsigned long dummy) | 1034 | static void kbd_bh(unsigned long dummy) |
1015 | { | 1035 | { |
1016 | struct list_head *node; | ||
1017 | unsigned char leds = getleds(); | 1036 | unsigned char leds = getleds(); |
1018 | 1037 | ||
1019 | if (leds != ledstate) { | 1038 | if (leds != ledstate) { |
1020 | list_for_each(node, &kbd_handler.h_list) { | 1039 | input_handler_for_each_handle(&kbd_handler, &leds, |
1021 | struct input_handle *handle = to_handle_h(node); | 1040 | kbd_update_leds_helper); |
1022 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); | 1041 | ledstate = leds; |
1023 | input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); | ||
1024 | input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); | ||
1025 | input_inject_event(handle, EV_SYN, SYN_REPORT, 0); | ||
1026 | } | ||
1027 | } | 1042 | } |
1028 | |||
1029 | ledstate = leds; | ||
1030 | } | 1043 | } |
1031 | 1044 | ||
1032 | DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); | 1045 | DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); |
@@ -1136,7 +1149,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u | |||
1136 | static void kbd_rawcode(unsigned char data) | 1149 | static void kbd_rawcode(unsigned char data) |
1137 | { | 1150 | { |
1138 | struct vc_data *vc = vc_cons[fg_console].d; | 1151 | struct vc_data *vc = vc_cons[fg_console].d; |
1139 | kbd = kbd_table + fg_console; | 1152 | kbd = kbd_table + vc->vc_num; |
1140 | if (kbd->kbdmode == VC_RAW) | 1153 | if (kbd->kbdmode == VC_RAW) |
1141 | put_queue(vc, data); | 1154 | put_queue(vc, data); |
1142 | } | 1155 | } |
@@ -1157,7 +1170,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1157 | tty->driver_data = vc; | 1170 | tty->driver_data = vc; |
1158 | } | 1171 | } |
1159 | 1172 | ||
1160 | kbd = kbd_table + fg_console; | 1173 | kbd = kbd_table + vc->vc_num; |
1161 | 1174 | ||
1162 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) | 1175 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) |
1163 | sysrq_alt = down ? keycode : 0; | 1176 | sysrq_alt = down ? keycode : 0; |
@@ -1296,10 +1309,16 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1296 | static void kbd_event(struct input_handle *handle, unsigned int event_type, | 1309 | static void kbd_event(struct input_handle *handle, unsigned int event_type, |
1297 | unsigned int event_code, int value) | 1310 | unsigned int event_code, int value) |
1298 | { | 1311 | { |
1312 | /* We are called with interrupts disabled, just take the lock */ | ||
1313 | spin_lock(&kbd_event_lock); | ||
1314 | |||
1299 | if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) | 1315 | if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) |
1300 | kbd_rawcode(value); | 1316 | kbd_rawcode(value); |
1301 | if (event_type == EV_KEY) | 1317 | if (event_type == EV_KEY) |
1302 | kbd_keycode(event_code, value, HW_RAW(handle->dev)); | 1318 | kbd_keycode(event_code, value, HW_RAW(handle->dev)); |
1319 | |||
1320 | spin_unlock(&kbd_event_lock); | ||
1321 | |||
1303 | tasklet_schedule(&keyboard_tasklet); | 1322 | tasklet_schedule(&keyboard_tasklet); |
1304 | do_poke_blanked_console = 1; | 1323 | do_poke_blanked_console = 1; |
1305 | schedule_console_callback(); | 1324 | schedule_console_callback(); |
@@ -1363,15 +1382,11 @@ static void kbd_disconnect(struct input_handle *handle) | |||
1363 | */ | 1382 | */ |
1364 | static void kbd_start(struct input_handle *handle) | 1383 | static void kbd_start(struct input_handle *handle) |
1365 | { | 1384 | { |
1366 | unsigned char leds = ledstate; | ||
1367 | |||
1368 | tasklet_disable(&keyboard_tasklet); | 1385 | tasklet_disable(&keyboard_tasklet); |
1369 | if (leds != 0xff) { | 1386 | |
1370 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); | 1387 | if (ledstate != 0xff) |
1371 | input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); | 1388 | kbd_update_leds_helper(handle, &ledstate); |
1372 | input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); | 1389 | |
1373 | input_inject_event(handle, EV_SYN, SYN_REPORT, 0); | ||
1374 | } | ||
1375 | tasklet_enable(&keyboard_tasklet); | 1390 | tasklet_enable(&keyboard_tasklet); |
1376 | } | 1391 | } |
1377 | 1392 | ||