diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2007-10-19 02:39:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-19 14:53:34 -0400 |
commit | b293d758470e971253eec42b817bc9ef1213b228 (patch) | |
tree | aafc6011762436cf3076798fee7140145908852c /drivers/char | |
parent | fe9d4f576324999ac521c931f3b3eee0c8e45544 (diff) |
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>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/vt.c | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1764c67b585f..7a5badfb7d84 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -99,6 +99,7 @@ | |||
99 | #include <linux/pm.h> | 99 | #include <linux/pm.h> |
100 | #include <linux/font.h> | 100 | #include <linux/font.h> |
101 | #include <linux/bitops.h> | 101 | #include <linux/bitops.h> |
102 | #include <linux/notifier.h> | ||
102 | 103 | ||
103 | #include <asm/io.h> | 104 | #include <asm/io.h> |
104 | #include <asm/system.h> | 105 | #include <asm/system.h> |
@@ -223,6 +224,35 @@ enum { | |||
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, ¶m); | ||
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, ¶m); | ||
253 | } | ||
254 | |||
255 | /* | ||
226 | * Low-Level Functions | 256 | * Low-Level Functions |
227 | */ | 257 | */ |
228 | 258 | ||
@@ -718,6 +748,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ | |||
718 | return -ENXIO; | 748 | return -ENXIO; |
719 | if (!vc_cons[currcons].d) { | 749 | if (!vc_cons[currcons].d) { |
720 | struct vc_data *vc; | 750 | struct vc_data *vc; |
751 | struct vt_notifier_param param; | ||
721 | 752 | ||
722 | /* prevent users from taking too much memory */ | 753 | /* prevent users from taking too much memory */ |
723 | if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) | 754 | if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) |
@@ -729,7 +760,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ | |||
729 | /* although the numbers above are not valid since long ago, the | 760 | /* although the numbers above are not valid since long ago, the |
730 | point is still up-to-date and the comment still has its value | 761 | point is still up-to-date and the comment still has its value |
731 | even if only as a historical artifact. --mj, July 1998 */ | 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 | if (!vc) | 764 | if (!vc) |
734 | return -ENOMEM; | 765 | return -ENOMEM; |
735 | vc_cons[currcons].d = vc; | 766 | vc_cons[currcons].d = vc; |
@@ -746,6 +777,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ | |||
746 | } | 777 | } |
747 | vc->vc_kmalloced = 1; | 778 | vc->vc_kmalloced = 1; |
748 | vc_init(vc, vc->vc_rows, vc->vc_cols, 1); | 779 | vc_init(vc, vc->vc_rows, vc->vc_cols, 1); |
780 | atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m); | ||
749 | } | 781 | } |
750 | return 0; | 782 | return 0; |
751 | } | 783 | } |
@@ -907,6 +939,8 @@ void vc_deallocate(unsigned int currcons) | |||
907 | 939 | ||
908 | if (vc_cons_allocated(currcons)) { | 940 | if (vc_cons_allocated(currcons)) { |
909 | struct vc_data *vc = vc_cons[currcons].d; | 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, ¶m); | ||
910 | vc->vc_sw->con_deinit(vc); | 944 | vc->vc_sw->con_deinit(vc); |
911 | put_pid(vc->vt_pid); | 945 | put_pid(vc->vt_pid); |
912 | module_put(vc->vc_sw->owner); | 946 | module_put(vc->vc_sw->owner); |
@@ -1019,6 +1053,7 @@ static void lf(struct vc_data *vc) | |||
1019 | vc->vc_pos += vc->vc_size_row; | 1053 | vc->vc_pos += vc->vc_size_row; |
1020 | } | 1054 | } |
1021 | vc->vc_need_wrap = 0; | 1055 | vc->vc_need_wrap = 0; |
1056 | notify_write(vc, '\n'); | ||
1022 | } | 1057 | } |
1023 | 1058 | ||
1024 | static void ri(struct vc_data *vc) | 1059 | static void ri(struct vc_data *vc) |
@@ -1039,6 +1074,7 @@ static inline void cr(struct vc_data *vc) | |||
1039 | { | 1074 | { |
1040 | vc->vc_pos -= vc->vc_x << 1; | 1075 | vc->vc_pos -= vc->vc_x << 1; |
1041 | vc->vc_need_wrap = vc->vc_x = 0; | 1076 | vc->vc_need_wrap = vc->vc_x = 0; |
1077 | notify_write(vc, '\r'); | ||
1042 | } | 1078 | } |
1043 | 1079 | ||
1044 | static inline void bs(struct vc_data *vc) | 1080 | static inline void bs(struct vc_data *vc) |
@@ -1047,6 +1083,7 @@ static inline void bs(struct vc_data *vc) | |||
1047 | vc->vc_pos -= 2; | 1083 | vc->vc_pos -= 2; |
1048 | vc->vc_x--; | 1084 | vc->vc_x--; |
1049 | vc->vc_need_wrap = 0; | 1085 | vc->vc_need_wrap = 0; |
1086 | notify_write(vc, '\b'); | ||
1050 | } | 1087 | } |
1051 | } | 1088 | } |
1052 | 1089 | ||
@@ -1593,6 +1630,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) | |||
1593 | break; | 1630 | break; |
1594 | } | 1631 | } |
1595 | vc->vc_pos += (vc->vc_x << 1); | 1632 | vc->vc_pos += (vc->vc_x << 1); |
1633 | notify_write(vc, '\t'); | ||
1596 | return; | 1634 | return; |
1597 | case 10: case 11: case 12: | 1635 | case 10: case 11: case 12: |
1598 | lf(vc); | 1636 | lf(vc); |
@@ -2252,6 +2290,7 @@ rescan_last_byte: | |||
2252 | tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ | 2290 | tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ |
2253 | if (tc < 0) tc = ' '; | 2291 | if (tc < 0) tc = ' '; |
2254 | } | 2292 | } |
2293 | notify_write(vc, c); | ||
2255 | 2294 | ||
2256 | if (inverse) { | 2295 | if (inverse) { |
2257 | FLUSH | 2296 | FLUSH |
@@ -2274,6 +2313,7 @@ rescan_last_byte: | |||
2274 | release_console_sem(); | 2313 | release_console_sem(); |
2275 | 2314 | ||
2276 | out: | 2315 | out: |
2316 | notify_update(vc); | ||
2277 | return n; | 2317 | return n; |
2278 | #undef FLUSH | 2318 | #undef FLUSH |
2279 | } | 2319 | } |
@@ -2317,6 +2357,7 @@ static void console_callback(struct work_struct *ignored) | |||
2317 | do_blank_screen(0); | 2357 | do_blank_screen(0); |
2318 | blank_timer_expired = 0; | 2358 | blank_timer_expired = 0; |
2319 | } | 2359 | } |
2360 | notify_update(vc_cons[fg_console].d); | ||
2320 | 2361 | ||
2321 | release_console_sem(); | 2362 | release_console_sem(); |
2322 | } | 2363 | } |
@@ -2418,6 +2459,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) | |||
2418 | continue; | 2459 | continue; |
2419 | } | 2460 | } |
2420 | scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos); | 2461 | scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos); |
2462 | notify_write(vc, c); | ||
2421 | cnt++; | 2463 | cnt++; |
2422 | if (myx == vc->vc_cols - 1) { | 2464 | if (myx == vc->vc_cols - 1) { |
2423 | vc->vc_need_wrap = 1; | 2465 | vc->vc_need_wrap = 1; |
@@ -2436,6 +2478,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) | |||
2436 | } | 2478 | } |
2437 | } | 2479 | } |
2438 | set_cursor(vc); | 2480 | set_cursor(vc); |
2481 | notify_update(vc); | ||
2439 | 2482 | ||
2440 | quit: | 2483 | quit: |
2441 | clear_bit(0, &printing); | 2484 | clear_bit(0, &printing); |