Commit b293d758470e971253eec42b817bc9ef1213b228

Authored by Samuel Thibault
Committed by Linus Torvalds
1 parent fe9d4f5763

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>

Showing 3 changed files with 62 additions and 1 deletions Side-by-side Diff

... ... @@ -99,6 +99,7 @@
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>
... ... @@ -223,6 +224,35 @@
223 224 };
224 225  
225 226 /*
  227 + * Notifier list for console events.
  228 + */
  229 +static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
  230 +
  231 +int register_vt_notifier(struct notifier_block *nb)
  232 +{
  233 + return atomic_notifier_chain_register(&vt_notifier_list, nb);
  234 +}
  235 +EXPORT_SYMBOL_GPL(register_vt_notifier);
  236 +
  237 +int unregister_vt_notifier(struct notifier_block *nb)
  238 +{
  239 + return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
  240 +}
  241 +EXPORT_SYMBOL_GPL(unregister_vt_notifier);
  242 +
  243 +static void notify_write(struct vc_data *vc, unsigned int unicode)
  244 +{
  245 + struct vt_notifier_param param = { .vc = vc, unicode = unicode };
  246 + atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
  247 +}
  248 +
  249 +static void notify_update(struct vc_data *vc)
  250 +{
  251 + struct vt_notifier_param param = { .vc = vc };
  252 + atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
  253 +}
  254 +
  255 +/*
226 256 * Low-Level Functions
227 257 */
228 258  
... ... @@ -718,6 +748,7 @@
718 748 return -ENXIO;
719 749 if (!vc_cons[currcons].d) {
720 750 struct vc_data *vc;
  751 + struct vt_notifier_param param;
721 752  
722 753 /* prevent users from taking too much memory */
723 754 if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
... ... @@ -729,7 +760,7 @@
729 760 /* although the numbers above are not valid since long ago, the
730 761 point is still up-to-date and the comment still has its value
731 762 even if only as a historical artifact. --mj, July 1998 */
732   - vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
  763 + param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
733 764 if (!vc)
734 765 return -ENOMEM;
735 766 vc_cons[currcons].d = vc;
... ... @@ -746,6 +777,7 @@
746 777 }
747 778 vc->vc_kmalloced = 1;
748 779 vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
  780 + atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
749 781 }
750 782 return 0;
751 783 }
... ... @@ -907,6 +939,8 @@
907 939  
908 940 if (vc_cons_allocated(currcons)) {
909 941 struct vc_data *vc = vc_cons[currcons].d;
  942 + struct vt_notifier_param param = { .vc = vc };
  943 + atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
910 944 vc->vc_sw->con_deinit(vc);
911 945 put_pid(vc->vt_pid);
912 946 module_put(vc->vc_sw->owner);
... ... @@ -1019,6 +1053,7 @@
1019 1053 vc->vc_pos += vc->vc_size_row;
1020 1054 }
1021 1055 vc->vc_need_wrap = 0;
  1056 + notify_write(vc, '\n');
1022 1057 }
1023 1058  
1024 1059 static void ri(struct vc_data *vc)
... ... @@ -1039,6 +1074,7 @@
1039 1074 {
1040 1075 vc->vc_pos -= vc->vc_x << 1;
1041 1076 vc->vc_need_wrap = vc->vc_x = 0;
  1077 + notify_write(vc, '\r');
1042 1078 }
1043 1079  
1044 1080 static inline void bs(struct vc_data *vc)
... ... @@ -1047,6 +1083,7 @@
1047 1083 vc->vc_pos -= 2;
1048 1084 vc->vc_x--;
1049 1085 vc->vc_need_wrap = 0;
  1086 + notify_write(vc, '\b');
1050 1087 }
1051 1088 }
1052 1089  
... ... @@ -1593,6 +1630,7 @@
1593 1630 break;
1594 1631 }
1595 1632 vc->vc_pos += (vc->vc_x << 1);
  1633 + notify_write(vc, '\t');
1596 1634 return;
1597 1635 case 10: case 11: case 12:
1598 1636 lf(vc);
... ... @@ -2252,6 +2290,7 @@
2252 2290 tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
2253 2291 if (tc < 0) tc = ' ';
2254 2292 }
  2293 + notify_write(vc, c);
2255 2294  
2256 2295 if (inverse) {
2257 2296 FLUSH
... ... @@ -2274,6 +2313,7 @@
2274 2313 release_console_sem();
2275 2314  
2276 2315 out:
  2316 + notify_update(vc);
2277 2317 return n;
2278 2318 #undef FLUSH
2279 2319 }
... ... @@ -2317,6 +2357,7 @@
2317 2357 do_blank_screen(0);
2318 2358 blank_timer_expired = 0;
2319 2359 }
  2360 + notify_update(vc_cons[fg_console].d);
2320 2361  
2321 2362 release_console_sem();
2322 2363 }
... ... @@ -2418,6 +2459,7 @@
2418 2459 continue;
2419 2460 }
2420 2461 scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
  2462 + notify_write(vc, c);
2421 2463 cnt++;
2422 2464 if (myx == vc->vc_cols - 1) {
2423 2465 vc->vc_need_wrap = 1;
... ... @@ -2436,6 +2478,7 @@
2436 2478 }
2437 2479 }
2438 2480 set_cursor(vc);
  2481 + notify_update(vc);
2439 2482  
2440 2483 quit:
2441 2484 clear_bit(0, &printing);
include/linux/notifier.h
... ... @@ -242,6 +242,12 @@
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 */
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).