X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fchar%2Fvt.c;h=7a5badfb7d846e00d85dbbd2c082461264b7a660;hb=9b73e76f3cf63379dcf45fcd4f112f5812418d0a;hp=6650ae1c088f05d132325c1f64cffa7a255f4851;hpb=71d441ddb51941d9d8279bdc858f965711b85c14;p=linux-2.6 diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 6650ae1c08..7a5badfb7d 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -99,6 +99,7 @@ #include #include #include +#include #include #include @@ -158,7 +159,7 @@ static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); static int printable; /* Is console ready for printing? */ -static int default_utf8; +int default_utf8 = true; module_param(default_utf8, int, S_IRUGO | S_IWUSR); /* @@ -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, ¶m); +} + +static void notify_update(struct vc_data *vc) +{ + struct vt_notifier_param param = { .vc = vc }; + atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, ¶m); +} + /* * Low-Level Functions */ @@ -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)) @@ -729,10 +760,9 @@ 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 = kmalloc(sizeof(struct vc_data), GFP_KERNEL); + param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL); if (!vc) return -ENOMEM; - memset(vc, 0, sizeof(*vc)); vc_cons[currcons].d = vc; INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); visual_init(vc, currcons, 1); @@ -747,17 +777,20 @@ 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, ¶m); } return 0; } -static inline int resize_screen(struct vc_data *vc, int width, int height) +static inline int resize_screen(struct vc_data *vc, int width, int height, + int user) { /* Resizes the resolution of the display adapater */ int err = 0; if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize) - err = vc->vc_sw->con_resize(vc, width, height); + err = vc->vc_sw->con_resize(vc, width, height, user); + return err; } @@ -773,7 +806,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; unsigned int old_cols, old_rows, old_row_size, old_screen_size; unsigned int new_cols, new_rows, new_row_size, new_screen_size; - unsigned int end; + unsigned int end, user; unsigned short *newscreen; WARN_CONSOLE_UNLOCKED(); @@ -781,6 +814,9 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) if (!vc) return -ENXIO; + user = vc->vc_resize_user; + vc->vc_resize_user = 0; + if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) return -EINVAL; @@ -801,7 +837,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) old_row_size = vc->vc_size_row; old_screen_size = vc->vc_screenbuf_size; - err = resize_screen(vc, new_cols, new_rows); + err = resize_screen(vc, new_cols, new_rows, user); if (err) { kfree(newscreen); return err; @@ -903,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, ¶m); vc->vc_sw->con_deinit(vc); put_pid(vc->vt_pid); module_put(vc->vc_sw->owner); @@ -1015,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) @@ -1035,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) @@ -1043,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'); } } @@ -1589,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); @@ -1991,8 +2033,7 @@ static int is_double_width(uint32_t ucs) { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD } }; - return bisearch(ucs, double_width, - sizeof(double_width) / sizeof(*double_width) - 1); + return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1); } /* acquires console_sem */ @@ -2249,6 +2290,7 @@ rescan_last_byte: 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 @@ -2271,6 +2313,7 @@ rescan_last_byte: release_console_sem(); out: + notify_update(vc); return n; #undef FLUSH } @@ -2314,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(); } @@ -2415,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; @@ -2433,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); @@ -2989,8 +3035,24 @@ static int con_is_graphics(const struct consw *csw, int first, int last) return retval; } -static int unbind_con_driver(const struct consw *csw, int first, int last, - int deflt) +/** + * unbind_con_driver - unbind a console driver + * @csw: pointer to console driver to unregister + * @first: first in range of consoles that @csw should be unbound from + * @last: last in range of consoles that @csw should be unbound from + * @deflt: should next bound console driver be default after @csw is unbound? + * + * To unbind a driver from all possible consoles, pass 0 as @first and + * %MAX_NR_CONSOLES as @last. + * + * @deflt controls whether the console that ends up replacing @csw should be + * the default console. + * + * RETURNS: + * -ENODEV if @csw isn't a registered console driver or can't be unregistered + * or 0 on success. + */ +int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) { struct module *owner = csw->owner; const struct consw *defcsw = NULL; @@ -3075,6 +3137,7 @@ err: return retval; } +EXPORT_SYMBOL(unbind_con_driver); static int vt_bind(struct con_driver *con) { @@ -3491,9 +3554,6 @@ void do_blank_screen(int entering_gfx) } return; } - if (blank_state != blank_normal_wait) - return; - blank_state = blank_off; /* entering graphics mode? */ if (entering_gfx) { @@ -3501,10 +3561,15 @@ void do_blank_screen(int entering_gfx) save_screen(vc); vc->vc_sw->con_blank(vc, -1, 1); console_blanked = fg_console + 1; + blank_state = blank_off; set_origin(vc); return; } + if (blank_state != blank_normal_wait) + return; + blank_state = blank_off; + /* don't blank graphics */ if (vc->vc_mode != KD_TEXT) { console_blanked = fg_console + 1;