Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Basic braille screen reader support

This adds a minimalistic braille screen reader support. This is meant to
be used by blind people e.g. on boot failures or when / cannot be mounted
etc and thus the userland screen readers can not work.

[akpm@linux-foundation.org: fix exports]
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Cc: Jiri Kosina <jikos@jikos.cz>
Cc: Dmitry Torokhov <dtor@mail.ru>
Acked-by: Alan Cox <alan@redhat.com>
Cc: Randy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Samuel Thibault and committed by
Linus Torvalds
f7511d5f 730f412c

+538 -30
+34
Documentation/braille-console.txt
··· 1 + Linux Braille Console 2 + 3 + To get early boot messages on a braille device (before userspace screen 4 + readers can start), you first need to compile the support for the usual serial 5 + console (see serial-console.txt), and for braille device (in Device Drivers - 6 + Accessibility). 7 + 8 + Then you need to specify a console=brl, option on the kernel command line, the 9 + format is: 10 + 11 + console=brl,serial_options... 12 + 13 + where serial_options... are the same as described in serial-console.txt 14 + 15 + So for instance you can use console=brl,ttyS0 if the braille device is connected 16 + to the first serial port, and console=brl,ttyS0,115200 to override the baud rate 17 + to 115200, etc. 18 + 19 + By default, the braille device will just show the last kernel message (console 20 + mode). To review previous messages, press the Insert key to switch to the VT 21 + review mode. In review mode, the arrow keys permit to browse in the VT content, 22 + page up/down keys go at the top/bottom of the screen, and the home key goes back 23 + to the cursor, hence providing very basic screen reviewing facility. 24 + 25 + Sound feedback can be obtained by adding the braille_console.sound=1 kernel 26 + parameter. 27 + 28 + For simplicity, only one braille console can be enabled, other uses of 29 + console=brl,... will be discarded. Also note that it does not interfere with 30 + the console selection mecanism described in serial-console.txt 31 + 32 + For now, only the VisioBraille device is supported. 33 + 34 + Samuel Thibault <samuel.thibault@ens-lyon.org>
+5
Documentation/kernel-parameters.txt
··· 496 496 switching to the matching ttyS device later. The 497 497 options are the same as for ttyS, above. 498 498 499 + If the device connected to the port is not a TTY but a braille 500 + device, prepend "brl," before the device type, for instance 501 + console=brl,ttyS0 502 + For now, only VisioBraille is supported. 503 + 499 504 earlycon= [KNL] Output early console device and options. 500 505 uart[8250],io,<addr>[,options] 501 506 uart[8250],mmio,<addr>[,options]
-3
arch/powerpc/kernel/ppc_ksyms.c
··· 133 133 EXPORT_SYMBOL(cuda_request); 134 134 EXPORT_SYMBOL(cuda_poll); 135 135 #endif /* CONFIG_ADB_CUDA */ 136 - #ifdef CONFIG_VT 137 - EXPORT_SYMBOL(kd_mksound); 138 - #endif 139 136 EXPORT_SYMBOL(to_tm); 140 137 141 138 #ifdef CONFIG_PPC32
-3
arch/ppc/kernel/ppc_ksyms.c
··· 183 183 #if defined(CONFIG_BOOTX_TEXT) 184 184 EXPORT_SYMBOL(btext_update_display); 185 185 #endif 186 - #ifdef CONFIG_VT 187 - EXPORT_SYMBOL(kd_mksound); 188 - #endif 189 186 EXPORT_SYMBOL(to_tm); 190 187 191 188 EXPORT_SYMBOL(pm_power_off);
+2
drivers/Kconfig
··· 84 84 85 85 source "drivers/leds/Kconfig" 86 86 87 + source "drivers/accessibility/Kconfig" 88 + 87 89 source "drivers/infiniband/Kconfig" 88 90 89 91 source "drivers/edac/Kconfig"
+1
drivers/Makefile
··· 70 70 obj-$(CONFIG_PHONE) += telephony/ 71 71 obj-$(CONFIG_MD) += md/ 72 72 obj-$(CONFIG_BT) += bluetooth/ 73 + obj-$(CONFIG_ACCESSIBILITY) += accessibility/ 73 74 obj-$(CONFIG_ISDN) += isdn/ 74 75 obj-$(CONFIG_EDAC) += edac/ 75 76 obj-$(CONFIG_MCA) += mca/
+23
drivers/accessibility/Kconfig
··· 1 + menuconfig ACCESSIBILITY 2 + bool "Accessibility support" 3 + ---help--- 4 + Enable a submenu where accessibility items may be enabled. 5 + 6 + If unsure, say N. 7 + 8 + if ACCESSIBILITY 9 + config A11Y_BRAILLE_CONSOLE 10 + bool "Console on braille device" 11 + depends on VT 12 + depends on SERIAL_CORE_CONSOLE 13 + ---help--- 14 + Enables console output on a braille device connected to a 8250 15 + serial port. For now only the VisioBraille device is supported. 16 + 17 + To actually enable it, you need to pass option 18 + console=brl,ttyS0 19 + to the kernel. Options are the same as for serial console. 20 + 21 + If unsure, say N. 22 + 23 + endif # ACCESSIBILITY
+1
drivers/accessibility/Makefile
··· 1 + obj-y += braille/
+1
drivers/accessibility/braille/Makefile
··· 1 + obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille_console.o
+397
drivers/accessibility/braille/braille_console.c
··· 1 + /* 2 + * Minimalistic braille device kernel support. 3 + * 4 + * By default, shows console messages on the braille device. 5 + * Pressing Insert switches to VC browsing. 6 + * 7 + * Copyright (C) Samuel Thibault <samuel.thibault@ens-lyon.org> 8 + * 9 + * This program is free software ; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation ; either version 2 of the License, or 12 + * (at your option) any later version. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY ; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * GNU General Public License for more details. 18 + * 19 + * You should have received a copy of the GNU General Public License 20 + * along with the program ; if not, write to the Free Software 21 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 + */ 23 + 24 + #include <linux/autoconf.h> 25 + #include <linux/kernel.h> 26 + #include <linux/module.h> 27 + #include <linux/moduleparam.h> 28 + #include <linux/console.h> 29 + #include <linux/notifier.h> 30 + 31 + #include <linux/selection.h> 32 + #include <linux/vt_kern.h> 33 + #include <linux/consolemap.h> 34 + 35 + #include <linux/keyboard.h> 36 + #include <linux/kbd_kern.h> 37 + #include <linux/input.h> 38 + 39 + MODULE_AUTHOR("samuel.thibault@ens-lyon.org"); 40 + MODULE_DESCRIPTION("braille device"); 41 + MODULE_LICENSE("GPL"); 42 + 43 + /* 44 + * Braille device support part. 45 + */ 46 + 47 + /* Emit various sounds */ 48 + static int sound; 49 + module_param(sound, bool, 0); 50 + MODULE_PARM_DESC(sound, "emit sounds"); 51 + 52 + static void beep(unsigned int freq) 53 + { 54 + if (sound) 55 + kd_mksound(freq, HZ/10); 56 + } 57 + 58 + /* mini console */ 59 + #define WIDTH 40 60 + #define BRAILLE_KEY KEY_INSERT 61 + static u16 console_buf[WIDTH]; 62 + static int console_cursor; 63 + 64 + /* mini view of VC */ 65 + static int vc_x, vc_y, lastvc_x, lastvc_y; 66 + 67 + /* show console ? (or show VC) */ 68 + static int console_show = 1; 69 + /* pending newline ? */ 70 + static int console_newline = 1; 71 + static int lastVC = -1; 72 + 73 + static struct console *braille_co; 74 + 75 + /* Very VisioBraille-specific */ 76 + static void braille_write(u16 *buf) 77 + { 78 + static u16 lastwrite[WIDTH]; 79 + unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c; 80 + u16 out; 81 + int i; 82 + 83 + if (!braille_co) 84 + return; 85 + 86 + if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf))) 87 + return; 88 + memcpy(lastwrite, buf, WIDTH * sizeof(*buf)); 89 + 90 + #define SOH 1 91 + #define STX 2 92 + #define ETX 2 93 + #define EOT 4 94 + #define ENQ 5 95 + data[0] = STX; 96 + data[1] = '>'; 97 + csum ^= '>'; 98 + c = &data[2]; 99 + for (i = 0; i < WIDTH; i++) { 100 + out = buf[i]; 101 + if (out >= 0x100) 102 + out = '?'; 103 + else if (out == 0x00) 104 + out = ' '; 105 + csum ^= out; 106 + if (out <= 0x05) { 107 + *c++ = SOH; 108 + out |= 0x40; 109 + } 110 + *c++ = out; 111 + } 112 + 113 + if (csum <= 0x05) { 114 + *c++ = SOH; 115 + csum |= 0x40; 116 + } 117 + *c++ = csum; 118 + *c++ = ETX; 119 + 120 + braille_co->write(braille_co, data, c - data); 121 + } 122 + 123 + /* Follow the VC cursor*/ 124 + static void vc_follow_cursor(struct vc_data *vc) 125 + { 126 + vc_x = vc->vc_x - (vc->vc_x % WIDTH); 127 + vc_y = vc->vc_y; 128 + lastvc_x = vc->vc_x; 129 + lastvc_y = vc->vc_y; 130 + } 131 + 132 + /* Maybe the VC cursor moved, if so follow it */ 133 + static void vc_maybe_cursor_moved(struct vc_data *vc) 134 + { 135 + if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y) 136 + vc_follow_cursor(vc); 137 + } 138 + 139 + /* Show portion of VC at vc_x, vc_y */ 140 + static void vc_refresh(struct vc_data *vc) 141 + { 142 + u16 buf[WIDTH]; 143 + int i; 144 + 145 + for (i = 0; i < WIDTH; i++) { 146 + u16 glyph = screen_glyph(vc, 147 + 2 * (vc_x + i) + vc_y * vc->vc_size_row); 148 + buf[i] = inverse_translate(vc, glyph, 1); 149 + } 150 + braille_write(buf); 151 + } 152 + 153 + /* 154 + * Link to keyboard 155 + */ 156 + 157 + static int keyboard_notifier_call(struct notifier_block *blk, 158 + unsigned long code, void *_param) 159 + { 160 + struct keyboard_notifier_param *param = _param; 161 + struct vc_data *vc = param->vc; 162 + int ret = NOTIFY_OK; 163 + 164 + if (!param->down) 165 + return ret; 166 + 167 + switch (code) { 168 + case KBD_KEYCODE: 169 + if (console_show) { 170 + if (param->value == BRAILLE_KEY) { 171 + console_show = 0; 172 + beep(880); 173 + vc_maybe_cursor_moved(vc); 174 + vc_refresh(vc); 175 + ret = NOTIFY_STOP; 176 + } 177 + } else { 178 + ret = NOTIFY_STOP; 179 + switch (param->value) { 180 + case KEY_INSERT: 181 + beep(440); 182 + console_show = 1; 183 + lastVC = -1; 184 + braille_write(console_buf); 185 + break; 186 + case KEY_LEFT: 187 + if (vc_x > 0) { 188 + vc_x -= WIDTH; 189 + if (vc_x < 0) 190 + vc_x = 0; 191 + } else if (vc_y >= 1) { 192 + beep(880); 193 + vc_y--; 194 + vc_x = vc->vc_cols-WIDTH; 195 + } else 196 + beep(220); 197 + break; 198 + case KEY_RIGHT: 199 + if (vc_x + WIDTH < vc->vc_cols) { 200 + vc_x += WIDTH; 201 + } else if (vc_y + 1 < vc->vc_rows) { 202 + beep(880); 203 + vc_y++; 204 + vc_x = 0; 205 + } else 206 + beep(220); 207 + break; 208 + case KEY_DOWN: 209 + if (vc_y + 1 < vc->vc_rows) 210 + vc_y++; 211 + else 212 + beep(220); 213 + break; 214 + case KEY_UP: 215 + if (vc_y >= 1) 216 + vc_y--; 217 + else 218 + beep(220); 219 + break; 220 + case KEY_HOME: 221 + vc_follow_cursor(vc); 222 + break; 223 + case KEY_PAGEUP: 224 + vc_x = 0; 225 + vc_y = 0; 226 + break; 227 + case KEY_PAGEDOWN: 228 + vc_x = 0; 229 + vc_y = vc->vc_rows-1; 230 + break; 231 + default: 232 + ret = NOTIFY_OK; 233 + break; 234 + } 235 + if (ret == NOTIFY_STOP) 236 + vc_refresh(vc); 237 + } 238 + break; 239 + case KBD_POST_KEYSYM: 240 + { 241 + unsigned char type = KTYP(param->value) - 0xf0; 242 + if (type == KT_SPEC) { 243 + unsigned char val = KVAL(param->value); 244 + int on_off = -1; 245 + 246 + switch (val) { 247 + case KVAL(K_CAPS): 248 + on_off = vc_kbd_led(kbd_table + fg_console, 249 + VC_CAPSLOCK); 250 + break; 251 + case KVAL(K_NUM): 252 + on_off = vc_kbd_led(kbd_table + fg_console, 253 + VC_NUMLOCK); 254 + break; 255 + case KVAL(K_HOLD): 256 + on_off = vc_kbd_led(kbd_table + fg_console, 257 + VC_SCROLLOCK); 258 + break; 259 + } 260 + if (on_off == 1) 261 + beep(880); 262 + else if (on_off == 0) 263 + beep(440); 264 + } 265 + } 266 + case KBD_UNBOUND_KEYCODE: 267 + case KBD_UNICODE: 268 + case KBD_KEYSYM: 269 + /* Unused */ 270 + break; 271 + } 272 + return ret; 273 + } 274 + 275 + static struct notifier_block keyboard_notifier_block = { 276 + .notifier_call = keyboard_notifier_call, 277 + }; 278 + 279 + static int vt_notifier_call(struct notifier_block *blk, 280 + unsigned long code, void *_param) 281 + { 282 + struct vt_notifier_param *param = _param; 283 + struct vc_data *vc = param->vc; 284 + switch (code) { 285 + case VT_ALLOCATE: 286 + break; 287 + case VT_DEALLOCATE: 288 + break; 289 + case VT_WRITE: 290 + { 291 + unsigned char c = param->c; 292 + if (vc->vc_num != fg_console) 293 + break; 294 + switch (c) { 295 + case '\b': 296 + case 127: 297 + if (console_cursor > 0) { 298 + console_cursor--; 299 + console_buf[console_cursor] = ' '; 300 + } 301 + break; 302 + case '\n': 303 + case '\v': 304 + case '\f': 305 + case '\r': 306 + console_newline = 1; 307 + break; 308 + case '\t': 309 + c = ' '; 310 + /* Fallthrough */ 311 + default: 312 + if (c < 32) 313 + /* Ignore other control sequences */ 314 + break; 315 + if (console_newline) { 316 + memset(console_buf, 0, sizeof(console_buf)); 317 + console_cursor = 0; 318 + console_newline = 0; 319 + } 320 + if (console_cursor == WIDTH) 321 + memmove(console_buf, &console_buf[1], 322 + (WIDTH-1) * sizeof(*console_buf)); 323 + else 324 + console_cursor++; 325 + console_buf[console_cursor-1] = c; 326 + break; 327 + } 328 + if (console_show) 329 + braille_write(console_buf); 330 + else { 331 + vc_maybe_cursor_moved(vc); 332 + vc_refresh(vc); 333 + } 334 + break; 335 + } 336 + case VT_UPDATE: 337 + /* Maybe a VT switch, flush */ 338 + if (console_show) { 339 + if (vc->vc_num != lastVC) { 340 + lastVC = vc->vc_num; 341 + memset(console_buf, 0, sizeof(console_buf)); 342 + console_cursor = 0; 343 + braille_write(console_buf); 344 + } 345 + } else { 346 + vc_maybe_cursor_moved(vc); 347 + vc_refresh(vc); 348 + } 349 + break; 350 + } 351 + return NOTIFY_OK; 352 + } 353 + 354 + static struct notifier_block vt_notifier_block = { 355 + .notifier_call = vt_notifier_call, 356 + }; 357 + 358 + /* 359 + * Called from printk.c when console=brl is given 360 + */ 361 + 362 + int braille_register_console(struct console *console, int index, 363 + char *console_options, char *braille_options) 364 + { 365 + int ret; 366 + if (!console_options) 367 + /* Only support VisioBraille for now */ 368 + console_options = "57600o8"; 369 + if (braille_co) 370 + return -ENODEV; 371 + if (console->setup) { 372 + ret = console->setup(console, console_options); 373 + if (ret != 0) 374 + return ret; 375 + } 376 + console->flags |= CON_ENABLED; 377 + console->index = index; 378 + braille_co = console; 379 + return 0; 380 + } 381 + 382 + int braille_unregister_console(struct console *console) 383 + { 384 + if (braille_co != console) 385 + return -EINVAL; 386 + braille_co = NULL; 387 + return 0; 388 + } 389 + 390 + static int __init braille_init(void) 391 + { 392 + register_keyboard_notifier(&keyboard_notifier_block); 393 + register_vt_notifier(&vt_notifier_block); 394 + return 0; 395 + } 396 + 397 + console_initcall(braille_init);
+1
drivers/char/consolemap.c
··· 277 277 return p->inverse_translations[m][glyph]; 278 278 } 279 279 } 280 + EXPORT_SYMBOL_GPL(inverse_translate); 280 281 281 282 static void update_user_maps(void) 282 283 {
+2
drivers/char/keyboard.c
··· 110 110 const int NR_TYPES = ARRAY_SIZE(max_vals); 111 111 112 112 struct kbd_struct kbd_table[MAX_NR_CONSOLES]; 113 + EXPORT_SYMBOL_GPL(kbd_table); 113 114 static struct kbd_struct *kbd = kbd_table; 114 115 115 116 struct vt_spawn_console vt_spawn_con = { ··· 261 260 } else 262 261 kd_nosound(0); 263 262 } 263 + EXPORT_SYMBOL(kd_mksound); 264 264 265 265 /* 266 266 * Setting the keyboard rate.
+1
drivers/char/vt.c
··· 4004 4004 c |= 0x100; 4005 4005 return c; 4006 4006 } 4007 + EXPORT_SYMBOL_GPL(screen_glyph); 4007 4008 4008 4009 /* used by vcs - note the word offset */ 4009 4010 unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
+4
include/linux/console.h
··· 91 91 #define CON_ENABLED (4) 92 92 #define CON_BOOT (8) 93 93 #define CON_ANYTIME (16) /* Safe to call when cpu is offline */ 94 + #define CON_BRL (32) /* Used for a braille device */ 94 95 95 96 struct console { 96 97 char name[16]; ··· 122 121 extern void console_stop(struct console *); 123 122 extern void console_start(struct console *); 124 123 extern int is_console_locked(void); 124 + extern int braille_register_console(struct console *, int index, 125 + char *console_options, char *braille_options); 126 + extern int braille_unregister_console(struct console *); 125 127 126 128 extern int console_suspend_enabled; 127 129
+66 -24
kernel/printk.c
··· 111 111 char name[8]; /* Name of the driver */ 112 112 int index; /* Minor dev. to use */ 113 113 char *options; /* Options for the driver */ 114 + #ifdef CONFIG_A11Y_BRAILLE_CONSOLE 115 + char *brl_options; /* Options for braille driver */ 116 + #endif 114 117 }; 115 118 116 119 #define MAX_CMDLINECONSOLES 8 ··· 811 808 812 809 #endif 813 810 811 + static int __add_preferred_console(char *name, int idx, char *options, 812 + char *brl_options) 813 + { 814 + struct console_cmdline *c; 815 + int i; 816 + 817 + /* 818 + * See if this tty is not yet registered, and 819 + * if we have a slot free. 820 + */ 821 + for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) 822 + if (strcmp(console_cmdline[i].name, name) == 0 && 823 + console_cmdline[i].index == idx) { 824 + if (!brl_options) 825 + selected_console = i; 826 + return 0; 827 + } 828 + if (i == MAX_CMDLINECONSOLES) 829 + return -E2BIG; 830 + if (!brl_options) 831 + selected_console = i; 832 + c = &console_cmdline[i]; 833 + strlcpy(c->name, name, sizeof(c->name)); 834 + c->options = options; 835 + #ifdef CONFIG_A11Y_BRAILLE_CONSOLE 836 + c->brl_options = brl_options; 837 + #endif 838 + c->index = idx; 839 + return 0; 840 + } 814 841 /* 815 842 * Set up a list of consoles. Called from init/main.c 816 843 */ 817 844 static int __init console_setup(char *str) 818 845 { 819 846 char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */ 820 - char *s, *options; 847 + char *s, *options, *brl_options = NULL; 821 848 int idx; 849 + 850 + #ifdef CONFIG_A11Y_BRAILLE_CONSOLE 851 + if (!memcmp(str, "brl,", 4)) { 852 + brl_options = ""; 853 + str += 4; 854 + } else if (!memcmp(str, "brl=", 4)) { 855 + brl_options = str + 4; 856 + str = strchr(brl_options, ','); 857 + if (!str) { 858 + printk(KERN_ERR "need port name after brl=\n"); 859 + return 1; 860 + } 861 + *(str++) = 0; 862 + } 863 + #endif 822 864 823 865 /* 824 866 * Decode str into name, index, options. ··· 889 841 idx = simple_strtoul(s, NULL, 10); 890 842 *s = 0; 891 843 892 - add_preferred_console(buf, idx, options); 844 + __add_preferred_console(buf, idx, options, brl_options); 893 845 return 1; 894 846 } 895 847 __setup("console=", console_setup); ··· 909 861 */ 910 862 int add_preferred_console(char *name, int idx, char *options) 911 863 { 912 - struct console_cmdline *c; 913 - int i; 914 - 915 - /* 916 - * See if this tty is not yet registered, and 917 - * if we have a slot free. 918 - */ 919 - for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) 920 - if (strcmp(console_cmdline[i].name, name) == 0 && 921 - console_cmdline[i].index == idx) { 922 - selected_console = i; 923 - return 0; 924 - } 925 - if (i == MAX_CMDLINECONSOLES) 926 - return -E2BIG; 927 - selected_console = i; 928 - c = &console_cmdline[i]; 929 - memcpy(c->name, name, sizeof(c->name)); 930 - c->name[sizeof(c->name) - 1] = 0; 931 - c->options = options; 932 - c->index = idx; 933 - return 0; 864 + return __add_preferred_console(name, idx, options, NULL); 934 865 } 935 866 936 867 int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options) ··· 1190 1163 continue; 1191 1164 if (console->index < 0) 1192 1165 console->index = console_cmdline[i].index; 1166 + #ifdef CONFIG_A11Y_BRAILLE_CONSOLE 1167 + if (console_cmdline[i].brl_options) { 1168 + console->flags |= CON_BRL; 1169 + braille_register_console(console, 1170 + console_cmdline[i].index, 1171 + console_cmdline[i].options, 1172 + console_cmdline[i].brl_options); 1173 + return; 1174 + } 1175 + #endif 1193 1176 if (console->setup && 1194 1177 console->setup(console, console_cmdline[i].options) != 0) 1195 1178 break; ··· 1257 1220 { 1258 1221 struct console *a, *b; 1259 1222 int res = 1; 1223 + 1224 + #ifdef CONFIG_A11Y_BRAILLE_CONSOLE 1225 + if (console->flags & CON_BRL) 1226 + return braille_unregister_console(console); 1227 + #endif 1260 1228 1261 1229 acquire_console_sem(); 1262 1230 if (console_drivers == console) {