1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include <mos/device/console.h> |
4 | #include <mos/lib/structures/list.h> |
5 | #include <mos/lib/sync/spinlock.h> |
6 | #include <mos/misc/cmdline.h> |
7 | #include <mos/misc/setup.h> |
8 | #include <mos/syslog/printk.h> |
9 | #include <mos_stdio.h> |
10 | #include <mos_string.h> |
11 | |
12 | static console_t *printk_console = NULL; |
13 | static bool printk_quiet = false; |
14 | |
15 | MOS_SETUP("printk_console" , printk_setup_console) |
16 | { |
17 | const char *kcon_name = arg; |
18 | if (!kcon_name || !strlen(str: kcon_name)) |
19 | { |
20 | pr_warn("No console name given for printk" ); |
21 | return false; |
22 | } |
23 | |
24 | console_t *console = console_get(name: kcon_name); |
25 | if (console) |
26 | { |
27 | pr_emph("Selected console '%s' for future printk\n" , kcon_name); |
28 | printk_console = console; |
29 | return true; |
30 | } |
31 | |
32 | console = console_get_by_prefix(prefix: kcon_name); |
33 | if (console) |
34 | { |
35 | pr_emph("Selected console '%s' for future printk (prefix-based)\n" , console->name); |
36 | printk_console = console; |
37 | return true; |
38 | } |
39 | |
40 | mos_warn("No console found for printk based on given name or prefix '%s'" , kcon_name); |
41 | printk_console = NULL; |
42 | return false; |
43 | } |
44 | |
45 | MOS_EARLY_SETUP("quiet" , printk_setup_quiet) |
46 | { |
47 | printk_quiet = cmdline_string_truthiness(arg, default_value: true); |
48 | return true; |
49 | } |
50 | |
51 | static inline void deduce_level_color(int loglevel, standard_color_t *fg, standard_color_t *bg) |
52 | { |
53 | *bg = Black; |
54 | switch (loglevel) |
55 | { |
56 | case MOS_LOG_INFO2: *fg = DarkGray; break; |
57 | case MOS_LOG_INFO: *fg = Gray; break; |
58 | case MOS_LOG_EMPH: *fg = Cyan; break; |
59 | case MOS_LOG_WARN: *fg = Brown; break; |
60 | case MOS_LOG_EMERG: *fg = Red; break; |
61 | case MOS_LOG_FATAL: *fg = White, *bg = Red; break; |
62 | default: break; // do not change the color |
63 | } |
64 | } |
65 | |
66 | static void print_to_console(console_t *con, loglevel_t loglevel, const char *message, size_t len) |
67 | { |
68 | if (!con) |
69 | return; |
70 | |
71 | static standard_color_t fg, bg; // declared static to use previous values |
72 | if (once()) |
73 | con->ops->get_color(con, &fg, &bg); // only fill the colors once |
74 | deduce_level_color(loglevel, fg: &fg, bg: &bg); |
75 | console_write_color(con, data: message, size: len, fg, bg); |
76 | } |
77 | |
78 | void lvprintk(loglevel_t loglevel, const char *fmt, va_list args) |
79 | { |
80 | // only print warnings and errors if quiet mode is enabled |
81 | if (printk_quiet && loglevel < MOS_LOG_WARN) |
82 | return; |
83 | |
84 | char message[MOS_PRINTK_BUFFER_SIZE]; |
85 | const int len = vsnprintf(buf: message, MOS_PRINTK_BUFFER_SIZE, format: fmt, args); |
86 | |
87 | if (unlikely(!printk_console)) |
88 | { |
89 | list_foreach(console_t, con, consoles) |
90 | { |
91 | printk_console = con; // set the first console as the default |
92 | break; |
93 | } |
94 | } |
95 | |
96 | print_to_console(con: printk_console, loglevel, message, len); |
97 | } |
98 | |
99 | bool printk_unquiet(void) |
100 | { |
101 | bool was_quiet = printk_quiet; |
102 | printk_quiet = false; |
103 | return was_quiet; |
104 | } |
105 | |
106 | void printk_set_quiet(bool quiet) |
107 | { |
108 | printk_quiet = quiet; |
109 | } |
110 | |
111 | void lprintk(loglevel_t loglevel, const char *format, ...) |
112 | { |
113 | va_list args; |
114 | va_start(args, format); |
115 | lvprintk(loglevel, fmt: format, args); |
116 | va_end(args); |
117 | } |
118 | |
119 | void printk(const char *format, ...) |
120 | { |
121 | va_list args; |
122 | va_start(args, format); |
123 | lvprintk(loglevel: MOS_LOG_INFO, fmt: format, args); |
124 | va_end(args); |
125 | } |
126 | |