Skip to content

Commit

Permalink
Console events and accessibility
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
sthibaul authored and Linus Torvalds committed Oct 19, 2007
1 parent fe9d4f5 commit b293d75
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 1 deletion.
45 changes: 44 additions & 1 deletion drivers/char/vt.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
#include <linux/pm.h>
#include <linux/font.h>
#include <linux/bitops.h>
#include <linux/notifier.h>

#include <asm/io.h>
#include <asm/system.h>
Expand Down Expand Up @@ -222,6 +223,35 @@ enum {
blank_vesa_wait,
};

/*
* Notifier list for console events.
*/
static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);

int register_vt_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&vt_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(register_vt_notifier);

int unregister_vt_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(unregister_vt_notifier);

static void notify_write(struct vc_data *vc, unsigned int unicode)
{
struct vt_notifier_param param = { .vc = vc, unicode = unicode };
atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
}

static void notify_update(struct vc_data *vc)
{
struct vt_notifier_param param = { .vc = vc };
atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
}

/*
* Low-Level Functions
*/
Expand Down Expand Up @@ -718,6 +748,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
return -ENXIO;
if (!vc_cons[currcons].d) {
struct vc_data *vc;
struct vt_notifier_param param;

/* prevent users from taking too much memory */
if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
Expand All @@ -729,7 +760,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
/* although the numbers above are not valid since long ago, the
point is still up-to-date and the comment still has its value
even if only as a historical artifact. --mj, July 1998 */
vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
if (!vc)
return -ENOMEM;
vc_cons[currcons].d = vc;
Expand All @@ -746,6 +777,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
}
vc->vc_kmalloced = 1;
vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
}
return 0;
}
Expand Down Expand Up @@ -907,6 +939,8 @@ void vc_deallocate(unsigned int currcons)

if (vc_cons_allocated(currcons)) {
struct vc_data *vc = vc_cons[currcons].d;
struct vt_notifier_param param = { .vc = vc };
atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
vc->vc_sw->con_deinit(vc);
put_pid(vc->vt_pid);
module_put(vc->vc_sw->owner);
Expand Down Expand Up @@ -1019,6 +1053,7 @@ static void lf(struct vc_data *vc)
vc->vc_pos += vc->vc_size_row;
}
vc->vc_need_wrap = 0;
notify_write(vc, '\n');
}

static void ri(struct vc_data *vc)
Expand All @@ -1039,6 +1074,7 @@ static inline void cr(struct vc_data *vc)
{
vc->vc_pos -= vc->vc_x << 1;
vc->vc_need_wrap = vc->vc_x = 0;
notify_write(vc, '\r');
}

static inline void bs(struct vc_data *vc)
Expand All @@ -1047,6 +1083,7 @@ static inline void bs(struct vc_data *vc)
vc->vc_pos -= 2;
vc->vc_x--;
vc->vc_need_wrap = 0;
notify_write(vc, '\b');
}
}

Expand Down Expand Up @@ -1593,6 +1630,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
break;
}
vc->vc_pos += (vc->vc_x << 1);
notify_write(vc, '\t');
return;
case 10: case 11: case 12:
lf(vc);
Expand Down Expand Up @@ -2252,6 +2290,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
if (tc < 0) tc = ' ';
}
notify_write(vc, c);

if (inverse) {
FLUSH
Expand All @@ -2274,6 +2313,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
release_console_sem();

out:
notify_update(vc);
return n;
#undef FLUSH
}
Expand Down Expand Up @@ -2317,6 +2357,7 @@ static void console_callback(struct work_struct *ignored)
do_blank_screen(0);
blank_timer_expired = 0;
}
notify_update(vc_cons[fg_console].d);

release_console_sem();
}
Expand Down Expand Up @@ -2418,6 +2459,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
continue;
}
scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
notify_write(vc, c);
cnt++;
if (myx == vc->vc_cols - 1) {
vc->vc_need_wrap = 1;
Expand All @@ -2436,6 +2478,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
}
}
set_cursor(vc);
notify_update(vc);

quit:
clear_bit(0, &printing);
Expand Down
6 changes: 6 additions & 0 deletions include/linux/notifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,5 +242,11 @@ static inline int notifier_to_errno(int ret)

extern struct blocking_notifier_head reboot_notifier_list;

/* Virtual Terminal events. */
#define VT_ALLOCATE 0x0001 /* Console got allocated */
#define VT_DEALLOCATE 0x0002 /* Console will be deallocated */
#define VT_WRITE 0x0003 /* A char got output */
#define VT_UPDATE 0x0004 /* A bigger update occurred */

#endif /* __KERNEL__ */
#endif /* _LINUX_NOTIFIER_H */
12 changes: 12 additions & 0 deletions include/linux/vt.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
#ifndef _LINUX_VT_H
#define _LINUX_VT_H

#ifdef __KERNEL__
struct notifier_block;

struct vt_notifier_param {
struct vc_data *vc; /* VC on which the update happened */
unsigned int c; /* Printed char */
};

extern int register_vt_notifier(struct notifier_block *nb);
extern int unregister_vt_notifier(struct notifier_block *nb);
#endif

/*
* These constants are also useful for user-level apps (e.g., VC
* resizing).
Expand Down

0 comments on commit b293d75

Please sign in to comment.