1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include <mos/device/console.hpp>
4#include <mos/lib/structures/list.hpp>
5#include <mos/lib/sync/spinlock.hpp>
6#include <mos/misc/cmdline.hpp>
7#include <mos/misc/setup.hpp>
8#include <mos/syslog/printk.hpp>
9#include <mos_stdio.hpp>
10#include <mos_string.hpp>
11
12static Console *printk_console = NULL;
13static bool printk_quiet = false;
14
15MOS_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 *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
45MOS_EARLY_SETUP("quiet", printk_setup_quiet)
46{
47 printk_quiet = cmdline_string_truthiness(arg, default_value: true);
48 return true;
49}
50
51static 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
66static void print_to_console(Console *con, loglevel_t loglevel, const char *message, size_t len)
67{
68 if (!con)
69 return;
70
71 standard_color_t fg = con->fg, bg = con->bg;
72 deduce_level_color(loglevel, fg: &fg, bg: &bg);
73 con->write_color(data: message, size: len, fg, bg);
74}
75
76void lvprintk(loglevel_t loglevel, const char *fmt, va_list args)
77{
78 // only print warnings and errors if quiet mode is enabled
79 if (printk_quiet && loglevel < MOS_LOG_WARN)
80 return;
81
82 char message[MOS_PRINTK_BUFFER_SIZE];
83 const int len = vsnprintf(buf: message, MOS_PRINTK_BUFFER_SIZE, format: fmt, args);
84
85 if (unlikely(!printk_console))
86 {
87 list_foreach(Console, con, consoles)
88 {
89 printk_console = con; // set the first console as the default
90 break;
91 }
92 }
93
94 print_to_console(con: printk_console, loglevel, message, len);
95}
96
97bool printk_unquiet(void)
98{
99 bool was_quiet = printk_quiet;
100 printk_quiet = false;
101 return was_quiet;
102}
103
104void printk_set_quiet(bool quiet)
105{
106 printk_quiet = quiet;
107}
108
109void lprintk(loglevel_t loglevel, const char *format, ...)
110{
111 va_list args;
112 va_start(args, format);
113 lvprintk(loglevel, fmt: format, args);
114 va_end(args);
115}
116
117void printk(const char *format, ...)
118{
119 va_list args;
120 va_start(args, format);
121 lvprintk(loglevel: MOS_LOG_INFO, fmt: format, args);
122 va_end(args);
123}
124