diff options
-rw-r--r-- | drivers/char/vt.c | 45 | ||||
-rw-r--r-- | include/linux/notifier.h | 6 | ||||
-rw-r--r-- | include/linux/vt.h | 12 |
3 files changed, 62 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); |
diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 6ec7e21a3699..0c40cc0b4a36 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h | |||
@@ -242,5 +242,11 @@ static inline int notifier_to_errno(int ret) | |||
242 | 242 | ||
243 | extern struct blocking_notifier_head reboot_notifier_list; | 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 | #endif /* __KERNEL__ */ | 251 | #endif /* __KERNEL__ */ |
246 | #endif /* _LINUX_NOTIFIER_H */ | 252 | #endif /* _LINUX_NOTIFIER_H */ |
diff --git a/include/linux/vt.h b/include/linux/vt.h index ba806e8711be..02c1c0288770 100644 --- a/include/linux/vt.h +++ b/include/linux/vt.h | |||
@@ -1,6 +1,18 @@ | |||
1 | #ifndef _LINUX_VT_H | 1 | #ifndef _LINUX_VT_H |
2 | #define _LINUX_VT_H | 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 | * These constants are also useful for user-level apps (e.g., VC | 17 | * These constants are also useful for user-level apps (e.g., VC |
6 | * resizing). | 18 | * resizing). |