diff --git a/include/print.h b/include/print.h index 1823ab2..9e583f4 100644 --- a/include/print.h +++ b/include/print.h @@ -21,7 +21,9 @@ #ifndef PRINT_H #define PRINT_H -void print_init(int (*putc)(char)); +int print_register_func_early(int (*putc)(char)); +int print_register_func(int (*putc)(char)); +int print_unregister_func(int (*putc)(char)); int print(char *fmt, ...); int print_func(int (putcf)(char), char *fmt, ...); diff --git a/kernel/print.c b/kernel/print.c index 94b8df8..3f6e3b1 100644 --- a/kernel/print.c +++ b/kernel/print.c @@ -18,25 +18,77 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include +#include +#include #include #include -/* This function exists solely so crashes don't happen if putc() gets - * called before it is initialized. */ -int putc_initial(char c) { - (void)c; +struct dlist_node print_funcs_list; + +struct print_func { + int (*putc)(char); + struct dlist_node list; +}; + +/* + * On startup, we'd like to have print capabilities before kmalloc is + * initialized, so statically allocate one struct print_func to allow for the + * registration of one print 'sink' before kmalloc is initialized. + */ +struct print_func print_func_early; +int print_register_func_early(int (*putc)(char)) { + if (list_empty(&print_funcs_list)) { + print_func_early.putc = putc; + insert_before(&print_funcs_list, &print_func_early.list); + return 0; + } + return -1; +} + +int print_register_func(int (*putc)(char)) { + struct print_func *pf; + if (!(pf = kmalloc(sizeof(struct print_func)))) + return -1; + + pf->putc = putc; + insert_before(&print_funcs_list, &pf->list); return 0; } -int (*print_putc)(char) = &putc_initial; -void print_init(int (*putcfn)(char)) { - if (putcfn) - print_putc = putcfn; +int print_unregister_func(int (*putc)(char)) { + struct print_func *it; + + if (list_empty(&print_funcs_list)) + return -1; + + for_each_list(it, &print_funcs_list, struct print_func, list) { + if (it->putc == putc) { + remove(&it->list); + + //only kfree if it was kmalloced + if (it != &print_func_early) + kfree(it); + return 0; + } + } + return -1; } - + +int print_putc(char c) { + struct print_func *it; + + if (list_empty(&print_funcs_list)) + return -1; + + for_each_list(it, &print_funcs_list, struct print_func, list) + it->putc(c); + return 0; +} + void puts(int (*putc)(char), const char *s) { - while (*s) putc (*s++); + while (*s) putc(*s++); } void puti(int (*putc)(char), int i) @@ -132,7 +184,7 @@ int print(char *fmt, ...) { va_list arg; va_start(arg, fmt); - ret = _print(print_putc, fmt, arg); + ret = _print(&print_putc, fmt, arg); va_end(arg); return ret; @@ -149,3 +201,9 @@ int print_func(int (*putc)(char), char *fmt, ...) { return ret; } + +void print_init() { + init_list(&print_funcs_list); +} + +early_initcall(print_init); diff --git a/kernel/start_kernel.c b/kernel/start_kernel.c index 08fc3a0..27e6d6c 100644 --- a/kernel/start_kernel.c +++ b/kernel/start_kernel.c @@ -59,6 +59,7 @@ void video_console_init(void) { if ((console_init(&console_fb))) return; + print_register_func(&console_putc); print_console_logo(); print_func(&console_putc, "Successfully initialized video console on %s.\n", fbdev->name); @@ -70,7 +71,7 @@ void serial_console_init() { if (!sdev) return; - print_init(sdev->putc); + print_register_func_early(sdev->putc); print("Successfully initialized serial console on %s\n", sdev->name); }