diff options
Diffstat (limited to 'drivers/char/keyboard.c')
-rw-r--r-- | drivers/char/keyboard.c | 219 |
1 files changed, 119 insertions, 100 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 737be953cc58..f706b1dffdb3 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,89 @@ 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. Note that we prefer beeps to bells, but when |
237 | * shutting the sound off we do both. | ||
224 | */ | 238 | */ |
225 | static void kd_nosound(unsigned long ignored) | 239 | |
240 | static int kd_sound_helper(struct input_handle *handle, void *data) | ||
226 | { | 241 | { |
227 | struct input_handle *handle; | 242 | unsigned int *hz = data; |
243 | struct input_dev *dev = handle->dev; | ||
228 | 244 | ||
229 | list_for_each_entry(handle, &kbd_handler.h_list, h_node) { | 245 | if (test_bit(EV_SND, dev->evbit)) { |
230 | if (test_bit(EV_SND, handle->dev->evbit)) { | 246 | if (test_bit(SND_TONE, dev->sndbit)) { |
231 | if (test_bit(SND_TONE, handle->dev->sndbit)) | 247 | input_inject_event(handle, EV_SND, SND_TONE, *hz); |
232 | input_inject_event(handle, EV_SND, SND_TONE, 0); | 248 | if (*hz) |
233 | if (test_bit(SND_BELL, handle->dev->sndbit)) | 249 | return 0; |
234 | input_inject_event(handle, EV_SND, SND_BELL, 0); | ||
235 | } | 250 | } |
251 | if (test_bit(SND_BELL, dev->sndbit)) | ||
252 | input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0); | ||
236 | } | 253 | } |
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static void kd_nosound(unsigned long ignored) | ||
259 | { | ||
260 | static unsigned int zero; | ||
261 | |||
262 | input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper); | ||
237 | } | 263 | } |
238 | 264 | ||
239 | static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); | 265 | static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); |
240 | 266 | ||
241 | void kd_mksound(unsigned int hz, unsigned int ticks) | 267 | void kd_mksound(unsigned int hz, unsigned int ticks) |
242 | { | 268 | { |
243 | struct list_head *node; | 269 | del_timer_sync(&kd_mksound_timer); |
244 | 270 | ||
245 | del_timer(&kd_mksound_timer); | 271 | input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper); |
246 | 272 | ||
247 | if (hz) { | 273 | if (hz && ticks) |
248 | list_for_each_prev(node, &kbd_handler.h_list) { | 274 | 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 | } | 275 | } |
266 | EXPORT_SYMBOL(kd_mksound); | 276 | EXPORT_SYMBOL(kd_mksound); |
267 | 277 | ||
@@ -269,27 +279,34 @@ EXPORT_SYMBOL(kd_mksound); | |||
269 | * Setting the keyboard rate. | 279 | * Setting the keyboard rate. |
270 | */ | 280 | */ |
271 | 281 | ||
272 | int kbd_rate(struct kbd_repeat *rep) | 282 | static int kbd_rate_helper(struct input_handle *handle, void *data) |
273 | { | 283 | { |
274 | struct list_head *node; | 284 | struct input_dev *dev = handle->dev; |
275 | unsigned int d = 0; | 285 | struct kbd_repeat *rep = data; |
276 | unsigned int p = 0; | 286 | |
277 | 287 | if (test_bit(EV_REP, dev->evbit)) { | |
278 | list_for_each(node, &kbd_handler.h_list) { | 288 | |
279 | struct input_handle *handle = to_handle_h(node); | 289 | if (rep[0].delay > 0) |
280 | struct input_dev *dev = handle->dev; | 290 | input_inject_event(handle, |
281 | 291 | EV_REP, REP_DELAY, rep[0].delay); | |
282 | if (test_bit(EV_REP, dev->evbit)) { | 292 | if (rep[0].period > 0) |
283 | if (rep->delay > 0) | 293 | input_inject_event(handle, |
284 | input_inject_event(handle, EV_REP, REP_DELAY, rep->delay); | 294 | EV_REP, REP_PERIOD, rep[0].period); |
285 | if (rep->period > 0) | 295 | |
286 | input_inject_event(handle, EV_REP, REP_PERIOD, rep->period); | 296 | rep[1].delay = dev->rep[REP_DELAY]; |
287 | d = dev->rep[REP_DELAY]; | 297 | rep[1].period = dev->rep[REP_PERIOD]; |
288 | p = dev->rep[REP_PERIOD]; | ||
289 | } | ||
290 | } | 298 | } |
291 | rep->delay = d; | 299 | |
292 | rep->period = p; | 300 | return 0; |
301 | } | ||
302 | |||
303 | int kbd_rate(struct kbd_repeat *rep) | ||
304 | { | ||
305 | struct kbd_repeat data[2] = { *rep }; | ||
306 | |||
307 | input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper); | ||
308 | *rep = data[1]; /* Copy currently used settings */ | ||
309 | |||
293 | return 0; | 310 | return 0; |
294 | } | 311 | } |
295 | 312 | ||
@@ -997,36 +1014,36 @@ static inline unsigned char getleds(void) | |||
997 | return leds; | 1014 | return leds; |
998 | } | 1015 | } |
999 | 1016 | ||
1017 | static int kbd_update_leds_helper(struct input_handle *handle, void *data) | ||
1018 | { | ||
1019 | unsigned char leds = *(unsigned char *)data; | ||
1020 | |||
1021 | if (test_bit(EV_LED, handle->dev->evbit)) { | ||
1022 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); | ||
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 | |||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1000 | /* | 1031 | /* |
1001 | * This routine is the bottom half of the keyboard interrupt | 1032 | * This is the tasklet that updates LED state on all keyboards |
1002 | * routine, and runs with all interrupts enabled. It does | 1033 | * attached to the box. The reason we use tasklet is that we |
1003 | * console changing, led setting and copy_to_cooked, which can | 1034 | * need to handle the scenario when keyboard handler is not |
1004 | * take a reasonably long time. | 1035 | * registered yet but we already getting updates form VT to |
1005 | * | 1036 | * 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 | */ | 1037 | */ |
1013 | |||
1014 | static void kbd_bh(unsigned long dummy) | 1038 | static void kbd_bh(unsigned long dummy) |
1015 | { | 1039 | { |
1016 | struct list_head *node; | ||
1017 | unsigned char leds = getleds(); | 1040 | unsigned char leds = getleds(); |
1018 | 1041 | ||
1019 | if (leds != ledstate) { | 1042 | if (leds != ledstate) { |
1020 | list_for_each(node, &kbd_handler.h_list) { | 1043 | input_handler_for_each_handle(&kbd_handler, &leds, |
1021 | struct input_handle *handle = to_handle_h(node); | 1044 | kbd_update_leds_helper); |
1022 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); | 1045 | 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 | } | 1046 | } |
1028 | |||
1029 | ledstate = leds; | ||
1030 | } | 1047 | } |
1031 | 1048 | ||
1032 | DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); | 1049 | DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); |
@@ -1136,7 +1153,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u | |||
1136 | static void kbd_rawcode(unsigned char data) | 1153 | static void kbd_rawcode(unsigned char data) |
1137 | { | 1154 | { |
1138 | struct vc_data *vc = vc_cons[fg_console].d; | 1155 | struct vc_data *vc = vc_cons[fg_console].d; |
1139 | kbd = kbd_table + fg_console; | 1156 | kbd = kbd_table + vc->vc_num; |
1140 | if (kbd->kbdmode == VC_RAW) | 1157 | if (kbd->kbdmode == VC_RAW) |
1141 | put_queue(vc, data); | 1158 | put_queue(vc, data); |
1142 | } | 1159 | } |
@@ -1157,7 +1174,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1157 | tty->driver_data = vc; | 1174 | tty->driver_data = vc; |
1158 | } | 1175 | } |
1159 | 1176 | ||
1160 | kbd = kbd_table + fg_console; | 1177 | kbd = kbd_table + vc->vc_num; |
1161 | 1178 | ||
1162 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) | 1179 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) |
1163 | sysrq_alt = down ? keycode : 0; | 1180 | sysrq_alt = down ? keycode : 0; |
@@ -1249,7 +1266,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1249 | 1266 | ||
1250 | if (keycode >= NR_KEYS) | 1267 | if (keycode >= NR_KEYS) |
1251 | if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) | 1268 | if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) |
1252 | keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1); | 1269 | keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1)); |
1253 | else | 1270 | else |
1254 | return; | 1271 | return; |
1255 | else | 1272 | else |
@@ -1296,10 +1313,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, | 1313 | static void kbd_event(struct input_handle *handle, unsigned int event_type, |
1297 | unsigned int event_code, int value) | 1314 | unsigned int event_code, int value) |
1298 | { | 1315 | { |
1316 | /* We are called with interrupts disabled, just take the lock */ | ||
1317 | spin_lock(&kbd_event_lock); | ||
1318 | |||
1299 | if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) | 1319 | if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) |
1300 | kbd_rawcode(value); | 1320 | kbd_rawcode(value); |
1301 | if (event_type == EV_KEY) | 1321 | if (event_type == EV_KEY) |
1302 | kbd_keycode(event_code, value, HW_RAW(handle->dev)); | 1322 | kbd_keycode(event_code, value, HW_RAW(handle->dev)); |
1323 | |||
1324 | spin_unlock(&kbd_event_lock); | ||
1325 | |||
1303 | tasklet_schedule(&keyboard_tasklet); | 1326 | tasklet_schedule(&keyboard_tasklet); |
1304 | do_poke_blanked_console = 1; | 1327 | do_poke_blanked_console = 1; |
1305 | schedule_console_callback(); | 1328 | schedule_console_callback(); |
@@ -1363,15 +1386,11 @@ static void kbd_disconnect(struct input_handle *handle) | |||
1363 | */ | 1386 | */ |
1364 | static void kbd_start(struct input_handle *handle) | 1387 | static void kbd_start(struct input_handle *handle) |
1365 | { | 1388 | { |
1366 | unsigned char leds = ledstate; | ||
1367 | |||
1368 | tasklet_disable(&keyboard_tasklet); | 1389 | tasklet_disable(&keyboard_tasklet); |
1369 | if (leds != 0xff) { | 1390 | |
1370 | input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); | 1391 | if (ledstate != 0xff) |
1371 | input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); | 1392 | kbd_update_leds_helper(handle, &ledstate); |
1372 | input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); | 1393 | |
1373 | input_inject_event(handle, EV_SYN, SYN_REPORT, 0); | ||
1374 | } | ||
1375 | tasklet_enable(&keyboard_tasklet); | 1394 | tasklet_enable(&keyboard_tasklet); |
1376 | } | 1395 | } |
1377 | 1396 | ||