]>
Commit | Line | Data |
---|---|---|
56f94be3 WD |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * Detlev Zundel, DENX Software Engineering, dzu@denx.de. | |
4 | * | |
228f29ac WD |
5 | * Code used from linux/kernel/printk.c |
6 | * Copyright (C) 1991, 1992 Linus Torvalds | |
7 | * | |
56f94be3 WD |
8 | * See file CREDITS for list of people who contributed to this |
9 | * project. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License as | |
13 | * published by the Free Software Foundation; either version 2 of | |
14 | * the License, or (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
24 | * MA 02111-1307 USA | |
228f29ac WD |
25 | * |
26 | * Comments: | |
27 | * | |
28 | * After relocating the code, the environment variable "loglevel" is | |
29 | * copied to console_loglevel. The functionality is similar to the | |
30 | * handling in the Linux kernel, i.e. messages logged with a priority | |
31 | * less than console_loglevel are also output to stdout. | |
32 | * | |
33 | * If you want messages with the default level (e.g. POST messages) to | |
34 | * appear on stdout also, make sure the environment variable | |
35 | * "loglevel" is set at boot time to a number higher than | |
36 | * default_message_loglevel below. | |
56f94be3 WD |
37 | */ |
38 | ||
39 | /* | |
40 | * Logbuffer handling routines | |
41 | */ | |
42 | ||
43 | #include <common.h> | |
44 | #include <command.h> | |
45 | #include <devices.h> | |
228f29ac | 46 | #include <post.h> |
56f94be3 WD |
47 | #include <logbuff.h> |
48 | ||
49 | #if defined(CONFIG_LOGBUFFER) | |
50 | ||
56f94be3 WD |
51 | /* Local prototypes */ |
52 | static void logbuff_putc (const char c); | |
53 | static void logbuff_puts (const char *s); | |
54 | static int logbuff_printk(const char *line); | |
55 | ||
56 | static char buf[1024]; | |
57 | ||
228f29ac | 58 | /* This combination will not print messages with the default loglevel */ |
56f94be3 WD |
59 | static unsigned console_loglevel = 3; |
60 | static unsigned default_message_loglevel = 4; | |
228f29ac WD |
61 | static unsigned char *log_buf = NULL; |
62 | static unsigned long *ext_log_size; | |
63 | static unsigned long *ext_log_start; | |
64 | static unsigned long *ext_logged_chars; | |
65 | #define log_size (*ext_log_size) | |
56f94be3 WD |
66 | #define log_start (*ext_log_start) |
67 | #define logged_chars (*ext_logged_chars) | |
68 | ||
69 | /* Forced by code, eh! */ | |
70 | #define LOGBUFF_MAGIC 0xc0de4ced | |
71 | ||
228f29ac WD |
72 | /* The mapping used here has to be the same as in setup_ext_logbuff () |
73 | in linux/kernel/printk */ | |
74 | void logbuff_init_ptrs (void) | |
75 | { | |
76 | DECLARE_GLOBAL_DATA_PTR; | |
77 | unsigned long *ext_tag; | |
78 | char *s; | |
79 | ||
80 | log_buf = (unsigned char *)(gd->bd->bi_memsize-LOGBUFF_LEN); | |
81 | ext_tag = (unsigned long *)(log_buf)-4; | |
82 | ext_log_start = (unsigned long *)(log_buf)-3; | |
83 | ext_log_size = (unsigned long *)(log_buf)-2; | |
84 | ext_logged_chars = (unsigned long *)(log_buf)-1; | |
85 | if (*ext_tag!=LOGBUFF_MAGIC) { | |
86 | logged_chars = log_size = log_start = 0; | |
87 | *ext_tag = LOGBUFF_MAGIC; | |
88 | } | |
89 | /* Initialize default loglevel if present */ | |
90 | if ((s = getenv ("loglevel")) != NULL) | |
91 | console_loglevel = (int)simple_strtoul (s, NULL, 10); | |
92 | ||
93 | gd->post_log_word |= LOGBUFF_INITIALIZED; | |
94 | } | |
95 | ||
56f94be3 WD |
96 | int drv_logbuff_init (void) |
97 | { | |
98 | device_t logdev; | |
99 | int rc; | |
100 | ||
101 | /* Device initialization */ | |
102 | memset (&logdev, 0, sizeof (logdev)); | |
103 | ||
104 | strcpy (logdev.name, "logbuff"); | |
105 | logdev.ext = 0; /* No extensions */ | |
106 | logdev.flags = DEV_FLAGS_OUTPUT; /* Output only */ | |
107 | logdev.putc = logbuff_putc; /* 'putc' function */ | |
108 | logdev.puts = logbuff_puts; /* 'puts' function */ | |
109 | ||
110 | rc = device_register (&logdev); | |
111 | ||
112 | return (rc == 0) ? 1 : rc; | |
113 | } | |
114 | ||
115 | static void logbuff_putc (const char c) | |
116 | { | |
117 | char buf[2]; | |
228f29ac WD |
118 | buf[0] = c; |
119 | buf[1] = '\0'; | |
120 | logbuff_printk (buf); | |
56f94be3 WD |
121 | } |
122 | ||
123 | static void logbuff_puts (const char *s) | |
124 | { | |
228f29ac | 125 | logbuff_printk (s); |
56f94be3 WD |
126 | } |
127 | ||
128 | void logbuff_log(char *msg) | |
129 | { | |
130 | DECLARE_GLOBAL_DATA_PTR; | |
131 | ||
228f29ac WD |
132 | if ((gd->post_log_word & LOGBUFF_INITIALIZED)) { |
133 | logbuff_printk (msg); | |
56f94be3 | 134 | } else { |
228f29ac WD |
135 | /* Can happen only for pre-relocated errors as logging */ |
136 | /* at that stage should be disabled */ | |
137 | puts (msg); | |
56f94be3 WD |
138 | } |
139 | } | |
140 | ||
141 | /* | |
142 | * Subroutine: do_log | |
143 | * | |
144 | * Description: Handler for 'log' command.. | |
145 | * | |
146 | * Inputs: argv[1] contains the subcommand | |
147 | * | |
148 | * Return: None | |
149 | * | |
150 | */ | |
151 | int do_log (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
152 | { | |
153 | char *s; | |
154 | unsigned long i; | |
155 | ||
228f29ac WD |
156 | if (strcmp(argv[1],"append") == 0) { |
157 | /* Log concatenation of all arguments separated by spaces */ | |
158 | for (i=2; i<argc; i++) { | |
159 | if (i<argc-1) { | |
160 | logbuff_printk (argv[i]); | |
161 | logbuff_putc (' '); | |
162 | } else { | |
163 | logbuff_puts (argv[i]); | |
164 | } | |
165 | } | |
166 | return 0; | |
56f94be3 WD |
167 | } |
168 | ||
169 | switch (argc) { | |
170 | ||
171 | case 2: | |
172 | if (strcmp(argv[1],"show") == 0) { | |
228f29ac WD |
173 | for (i=0; i < (log_size&LOGBUFF_MASK); i++) { |
174 | s = log_buf+((log_start+i)&LOGBUFF_MASK); | |
175 | putc (*s); | |
56f94be3 WD |
176 | } |
177 | return 0; | |
178 | } else if (strcmp(argv[1],"reset") == 0) { | |
228f29ac WD |
179 | log_start = 0; |
180 | log_size = 0; | |
181 | logged_chars = 0; | |
56f94be3 | 182 | return 0; |
228f29ac WD |
183 | } else if (strcmp(argv[1],"info") == 0) { |
184 | printf ("Logbuffer at %08lx\n", (unsigned long)log_buf); | |
185 | printf ("log_start = %08lx\n", log_start); | |
186 | printf ("log_size = %08lx\n", log_size); | |
187 | printf ("logged_chars = %08lx\n", logged_chars); | |
56f94be3 | 188 | return 0; |
56f94be3 WD |
189 | } |
190 | printf ("Usage:\n%s\n", cmdtp->usage); | |
191 | return 1; | |
192 | ||
193 | default: | |
194 | printf ("Usage:\n%s\n", cmdtp->usage); | |
195 | return 1; | |
196 | } | |
197 | } | |
198 | ||
199 | static int logbuff_printk(const char *line) | |
200 | { | |
201 | int i; | |
202 | char *msg, *p, *buf_end; | |
203 | int line_feed; | |
204 | static signed char msg_level = -1; | |
205 | ||
228f29ac WD |
206 | strcpy (buf + 3, line); |
207 | i = strlen (line); | |
56f94be3 WD |
208 | buf_end = buf + 3 + i; |
209 | for (p = buf + 3; p < buf_end; p++) { | |
210 | msg = p; | |
211 | if (msg_level < 0) { | |
212 | if ( | |
213 | p[0] != '<' || | |
214 | p[1] < '0' || | |
215 | p[1] > '7' || | |
216 | p[2] != '>' | |
217 | ) { | |
218 | p -= 3; | |
219 | p[0] = '<'; | |
220 | p[1] = default_message_loglevel + '0'; | |
221 | p[2] = '>'; | |
222 | } else | |
223 | msg += 3; | |
224 | msg_level = p[1] - '0'; | |
225 | } | |
226 | line_feed = 0; | |
227 | for (; p < buf_end; p++) { | |
228f29ac WD |
228 | log_buf[(log_start+log_size) & LOGBUFF_MASK] = *p; |
229 | if (log_size < LOGBUFF_LEN) | |
56f94be3 WD |
230 | log_size++; |
231 | else | |
232 | log_start++; | |
233 | ||
234 | logged_chars++; | |
235 | if (*p == '\n') { | |
236 | line_feed = 1; | |
237 | break; | |
238 | } | |
239 | } | |
240 | if (msg_level < console_loglevel) { | |
241 | printf("%s", msg); | |
242 | } | |
243 | if (line_feed) | |
244 | msg_level = -1; | |
245 | } | |
246 | return i; | |
247 | } | |
248 | ||
249 | #endif /* (CONFIG_LOGBUFFER) */ |