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

Console events and accessibility

Some external modules like Speakup need to monitor console output.

This adds a VT notifier that such modules can use to get console output events:
allocation, deallocation, writes, other updates (cursor position, switch, etc.)

[akpm@linux-foundation.org: fix headers_check]
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Cc: Dmitry Torokhov <dtor@mail.ru>
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
b293d758 fe9d4f57

+62 -1
+44 -1
drivers/char/vt.c
··· 99 99 #include <linux/pm.h> 100 100 #include <linux/font.h> 101 101 #include <linux/bitops.h> 102 + #include <linux/notifier.h> 102 103 103 104 #include <asm/io.h> 104 105 #include <asm/system.h> ··· 222 221 blank_normal_wait, 223 222 blank_vesa_wait, 224 223 }; 224 + 225 + /* 226 + * Notifier list for console events. 227 + */ 228 + static ATOMIC_NOTIFIER_HEAD(vt_notifier_list); 229 + 230 + int register_vt_notifier(struct notifier_block *nb) 231 + { 232 + return atomic_notifier_chain_register(&vt_notifier_list, nb); 233 + } 234 + EXPORT_SYMBOL_GPL(register_vt_notifier); 235 + 236 + int unregister_vt_notifier(struct notifier_block *nb) 237 + { 238 + return atomic_notifier_chain_unregister(&vt_notifier_list, nb); 239 + } 240 + EXPORT_SYMBOL_GPL(unregister_vt_notifier); 241 + 242 + static void notify_write(struct vc_data *vc, unsigned int unicode) 243 + { 244 + struct vt_notifier_param param = { .vc = vc, unicode = unicode }; 245 + atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param); 246 + } 247 + 248 + static void notify_update(struct vc_data *vc) 249 + { 250 + struct vt_notifier_param param = { .vc = vc }; 251 + atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param); 252 + } 225 253 226 254 /* 227 255 * Low-Level Functions ··· 748 718 return -ENXIO; 749 719 if (!vc_cons[currcons].d) { 750 720 struct vc_data *vc; 721 + struct vt_notifier_param param; 751 722 752 723 /* prevent users from taking too much memory */ 753 724 if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) ··· 760 729 /* although the numbers above are not valid since long ago, the 761 730 point is still up-to-date and the comment still has its value 762 731 even if only as a historical artifact. --mj, July 1998 */ 763 - vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL); 732 + param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL); 764 733 if (!vc) 765 734 return -ENOMEM; 766 735 vc_cons[currcons].d = vc; ··· 777 746 } 778 747 vc->vc_kmalloced = 1; 779 748 vc_init(vc, vc->vc_rows, vc->vc_cols, 1); 749 + atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param); 780 750 } 781 751 return 0; 782 752 } ··· 939 907 940 908 if (vc_cons_allocated(currcons)) { 941 909 struct vc_data *vc = vc_cons[currcons].d; 910 + struct vt_notifier_param param = { .vc = vc }; 911 + atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param); 942 912 vc->vc_sw->con_deinit(vc); 943 913 put_pid(vc->vt_pid); 944 914 module_put(vc->vc_sw->owner); ··· 1053 1019 vc->vc_pos += vc->vc_size_row; 1054 1020 } 1055 1021 vc->vc_need_wrap = 0; 1022 + notify_write(vc, '\n'); 1056 1023 } 1057 1024 1058 1025 static void ri(struct vc_data *vc) ··· 1074 1039 { 1075 1040 vc->vc_pos -= vc->vc_x << 1; 1076 1041 vc->vc_need_wrap = vc->vc_x = 0; 1042 + notify_write(vc, '\r'); 1077 1043 } 1078 1044 1079 1045 static inline void bs(struct vc_data *vc) ··· 1083 1047 vc->vc_pos -= 2; 1084 1048 vc->vc_x--; 1085 1049 vc->vc_need_wrap = 0; 1050 + notify_write(vc, '\b'); 1086 1051 } 1087 1052 } 1088 1053 ··· 1630 1593 break; 1631 1594 } 1632 1595 vc->vc_pos += (vc->vc_x << 1); 1596 + notify_write(vc, '\t'); 1633 1597 return; 1634 1598 case 10: case 11: case 12: 1635 1599 lf(vc); ··· 2290 2252 tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ 2291 2253 if (tc < 0) tc = ' '; 2292 2254 } 2255 + notify_write(vc, c); 2293 2256 2294 2257 if (inverse) { 2295 2258 FLUSH ··· 2313 2274 release_console_sem(); 2314 2275 2315 2276 out: 2277 + notify_update(vc); 2316 2278 return n; 2317 2279 #undef FLUSH 2318 2280 } ··· 2357 2317 do_blank_screen(0); 2358 2318 blank_timer_expired = 0; 2359 2319 } 2320 + notify_update(vc_cons[fg_console].d); 2360 2321 2361 2322 release_console_sem(); 2362 2323 } ··· 2459 2418 continue; 2460 2419 } 2461 2420 scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos); 2421 + notify_write(vc, c); 2462 2422 cnt++; 2463 2423 if (myx == vc->vc_cols - 1) { 2464 2424 vc->vc_need_wrap = 1; ··· 2478 2436 } 2479 2437 } 2480 2438 set_cursor(vc); 2439 + notify_update(vc); 2481 2440 2482 2441 quit: 2483 2442 clear_bit(0, &printing);
+6
include/linux/notifier.h
··· 242 242 243 243 extern struct blocking_notifier_head reboot_notifier_list; 244 244 245 + /* Virtual Terminal events. */ 246 + #define VT_ALLOCATE 0x0001 /* Console got allocated */ 247 + #define VT_DEALLOCATE 0x0002 /* Console will be deallocated */ 248 + #define VT_WRITE 0x0003 /* A char got output */ 249 + #define VT_UPDATE 0x0004 /* A bigger update occurred */ 250 + 245 251 #endif /* __KERNEL__ */ 246 252 #endif /* _LINUX_NOTIFIER_H */
+12
include/linux/vt.h
··· 1 1 #ifndef _LINUX_VT_H 2 2 #define _LINUX_VT_H 3 3 4 + #ifdef __KERNEL__ 5 + struct notifier_block; 6 + 7 + struct vt_notifier_param { 8 + struct vc_data *vc; /* VC on which the update happened */ 9 + unsigned int c; /* Printed char */ 10 + }; 11 + 12 + extern int register_vt_notifier(struct notifier_block *nb); 13 + extern int unregister_vt_notifier(struct notifier_block *nb); 14 + #endif 15 + 4 16 /* 5 17 * These constants are also useful for user-level apps (e.g., VC 6 18 * resizing).