diff options
| -rw-r--r-- | kernel/printk.c | 146 |
1 files changed, 92 insertions, 54 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index b4d97b54c1ec..41fe60995530 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
| @@ -37,6 +37,12 @@ | |||
| 37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
| 38 | 38 | ||
| 39 | /* | 39 | /* |
| 40 | * for_each_console() allows you to iterate on each console | ||
| 41 | */ | ||
| 42 | #define for_each_console(con) \ | ||
| 43 | for (con = console_drivers; con != NULL; con = con->next) | ||
| 44 | |||
| 45 | /* | ||
| 40 | * Architectures can override it: | 46 | * Architectures can override it: |
| 41 | */ | 47 | */ |
| 42 | void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) | 48 | void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) |
| @@ -412,7 +418,7 @@ static void __call_console_drivers(unsigned start, unsigned end) | |||
| 412 | { | 418 | { |
| 413 | struct console *con; | 419 | struct console *con; |
| 414 | 420 | ||
| 415 | for (con = console_drivers; con; con = con->next) { | 421 | for_each_console(con) { |
| 416 | if ((con->flags & CON_ENABLED) && con->write && | 422 | if ((con->flags & CON_ENABLED) && con->write && |
| 417 | (cpu_online(smp_processor_id()) || | 423 | (cpu_online(smp_processor_id()) || |
| 418 | (con->flags & CON_ANYTIME))) | 424 | (con->flags & CON_ANYTIME))) |
| @@ -544,7 +550,7 @@ static int have_callable_console(void) | |||
| 544 | { | 550 | { |
| 545 | struct console *con; | 551 | struct console *con; |
| 546 | 552 | ||
| 547 | for (con = console_drivers; con; con = con->next) | 553 | for_each_console(con) |
| 548 | if (con->flags & CON_ANYTIME) | 554 | if (con->flags & CON_ANYTIME) |
| 549 | return 1; | 555 | return 1; |
| 550 | 556 | ||
| @@ -1082,7 +1088,7 @@ void console_unblank(void) | |||
| 1082 | 1088 | ||
| 1083 | console_locked = 1; | 1089 | console_locked = 1; |
| 1084 | console_may_schedule = 0; | 1090 | console_may_schedule = 0; |
| 1085 | for (c = console_drivers; c != NULL; c = c->next) | 1091 | for_each_console(c) |
| 1086 | if ((c->flags & CON_ENABLED) && c->unblank) | 1092 | if ((c->flags & CON_ENABLED) && c->unblank) |
| 1087 | c->unblank(); | 1093 | c->unblank(); |
| 1088 | release_console_sem(); | 1094 | release_console_sem(); |
| @@ -1097,7 +1103,7 @@ struct tty_driver *console_device(int *index) | |||
| 1097 | struct tty_driver *driver = NULL; | 1103 | struct tty_driver *driver = NULL; |
| 1098 | 1104 | ||
| 1099 | acquire_console_sem(); | 1105 | acquire_console_sem(); |
| 1100 | for (c = console_drivers; c != NULL; c = c->next) { | 1106 | for_each_console(c) { |
| 1101 | if (!c->device) | 1107 | if (!c->device) |
| 1102 | continue; | 1108 | continue; |
| 1103 | driver = c->device(c, index); | 1109 | driver = c->device(c, index); |
| @@ -1134,25 +1140,49 @@ EXPORT_SYMBOL(console_start); | |||
| 1134 | * to register the console printing procedure with printk() and to | 1140 | * to register the console printing procedure with printk() and to |
| 1135 | * print any messages that were printed by the kernel before the | 1141 | * print any messages that were printed by the kernel before the |
| 1136 | * console driver was initialized. | 1142 | * console driver was initialized. |
| 1143 | * | ||
| 1144 | * This can happen pretty early during the boot process (because of | ||
| 1145 | * early_printk) - sometimes before setup_arch() completes - be careful | ||
| 1146 | * of what kernel features are used - they may not be initialised yet. | ||
| 1147 | * | ||
| 1148 | * There are two types of consoles - bootconsoles (early_printk) and | ||
| 1149 | * "real" consoles (everything which is not a bootconsole) which are | ||
| 1150 | * handled differently. | ||
| 1151 | * - Any number of bootconsoles can be registered at any time. | ||
| 1152 | * - As soon as a "real" console is registered, all bootconsoles | ||
| 1153 | * will be unregistered automatically. | ||
| 1154 | * - Once a "real" console is registered, any attempt to register a | ||
| 1155 | * bootconsoles will be rejected | ||
| 1137 | */ | 1156 | */ |
| 1138 | void register_console(struct console *console) | 1157 | void register_console(struct console *newcon) |
| 1139 | { | 1158 | { |
| 1140 | int i; | 1159 | int i; |
| 1141 | unsigned long flags; | 1160 | unsigned long flags; |
| 1142 | struct console *bootconsole = NULL; | 1161 | struct console *bcon = NULL; |
| 1143 | 1162 | ||
| 1144 | if (console_drivers) { | 1163 | /* |
| 1145 | if (console->flags & CON_BOOT) | 1164 | * before we register a new CON_BOOT console, make sure we don't |
| 1146 | return; | 1165 | * already have a valid console |
| 1147 | if (console_drivers->flags & CON_BOOT) | 1166 | */ |
| 1148 | bootconsole = console_drivers; | 1167 | if (console_drivers && newcon->flags & CON_BOOT) { |
| 1168 | /* find the last or real console */ | ||
| 1169 | for_each_console(bcon) { | ||
| 1170 | if (!(bcon->flags & CON_BOOT)) { | ||
| 1171 | printk(KERN_INFO "Too late to register bootconsole %s%d\n", | ||
| 1172 | newcon->name, newcon->index); | ||
| 1173 | return; | ||
| 1174 | } | ||
| 1175 | } | ||
| 1149 | } | 1176 | } |
| 1150 | 1177 | ||
| 1151 | if (preferred_console < 0 || bootconsole || !console_drivers) | 1178 | if (console_drivers && console_drivers->flags & CON_BOOT) |
| 1179 | bcon = console_drivers; | ||
| 1180 | |||
| 1181 | if (preferred_console < 0 || bcon || !console_drivers) | ||
| 1152 | preferred_console = selected_console; | 1182 | preferred_console = selected_console; |
| 1153 | 1183 | ||
| 1154 | if (console->early_setup) | 1184 | if (newcon->early_setup) |
| 1155 | console->early_setup(); | 1185 | newcon->early_setup(); |
| 1156 | 1186 | ||
| 1157 | /* | 1187 | /* |
| 1158 | * See if we want to use this console driver. If we | 1188 | * See if we want to use this console driver. If we |
| @@ -1160,13 +1190,13 @@ void register_console(struct console *console) | |||
| 1160 | * that registers here. | 1190 | * that registers here. |
| 1161 | */ | 1191 | */ |
| 1162 | if (preferred_console < 0) { | 1192 | if (preferred_console < 0) { |
| 1163 | if (console->index < 0) | 1193 | if (newcon->index < 0) |
| 1164 | console->index = 0; | 1194 | newcon->index = 0; |
| 1165 | if (console->setup == NULL || | 1195 | if (newcon->setup == NULL || |
| 1166 | console->setup(console, NULL) == 0) { | 1196 | newcon->setup(newcon, NULL) == 0) { |
| 1167 | console->flags |= CON_ENABLED; | 1197 | newcon->flags |= CON_ENABLED; |
| 1168 | if (console->device) { | 1198 | if (newcon->device) { |
| 1169 | console->flags |= CON_CONSDEV; | 1199 | newcon->flags |= CON_CONSDEV; |
| 1170 | preferred_console = 0; | 1200 | preferred_console = 0; |
| 1171 | } | 1201 | } |
| 1172 | } | 1202 | } |
| @@ -1178,47 +1208,53 @@ void register_console(struct console *console) | |||
| 1178 | */ | 1208 | */ |
| 1179 | for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; | 1209 | for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; |
| 1180 | i++) { | 1210 | i++) { |
| 1181 | if (strcmp(console_cmdline[i].name, console->name) != 0) | 1211 | if (strcmp(console_cmdline[i].name, newcon->name) != 0) |
| 1182 | continue; | 1212 | continue; |
| 1183 | if (console->index >= 0 && | 1213 | if (newcon->index >= 0 && |
| 1184 | console->index != console_cmdline[i].index) | 1214 | newcon->index != console_cmdline[i].index) |
| 1185 | continue; | 1215 | continue; |
| 1186 | if (console->index < 0) | 1216 | if (newcon->index < 0) |
| 1187 | console->index = console_cmdline[i].index; | 1217 | newcon->index = console_cmdline[i].index; |
| 1188 | #ifdef CONFIG_A11Y_BRAILLE_CONSOLE | 1218 | #ifdef CONFIG_A11Y_BRAILLE_CONSOLE |
| 1189 | if (console_cmdline[i].brl_options) { | 1219 | if (console_cmdline[i].brl_options) { |
| 1190 | console->flags |= CON_BRL; | 1220 | newcon->flags |= CON_BRL; |
| 1191 | braille_register_console(console, | 1221 | braille_register_console(newcon, |
| 1192 | console_cmdline[i].index, | 1222 | console_cmdline[i].index, |
| 1193 | console_cmdline[i].options, | 1223 | console_cmdline[i].options, |
| 1194 | console_cmdline[i].brl_options); | 1224 | console_cmdline[i].brl_options); |
| 1195 | return; | 1225 | return; |
| 1196 | } | 1226 | } |
| 1197 | #endif | 1227 | #endif |
| 1198 | if (console->setup && | 1228 | if (newcon->setup && |
| 1199 | console->setup(console, console_cmdline[i].options) != 0) | 1229 | newcon->setup(newcon, console_cmdline[i].options) != 0) |
| 1200 | break; | 1230 | break; |
| 1201 | console->flags |= CON_ENABLED; | 1231 | newcon->flags |= CON_ENABLED; |
| 1202 | console->index = console_cmdline[i].index; | 1232 | newcon->index = console_cmdline[i].index; |
| 1203 | if (i == selected_console) { | 1233 | if (i == selected_console) { |
| 1204 | console->flags |= CON_CONSDEV; | 1234 | newcon->flags |= CON_CONSDEV; |
| 1205 | preferred_console = selected_console; | 1235 | preferred_console = selected_console; |
| 1206 | } | 1236 | } |
| 1207 | break; | 1237 | break; |
| 1208 | } | 1238 | } |
| 1209 | 1239 | ||
| 1210 | if (!(console->flags & CON_ENABLED)) | 1240 | if (!(newcon->flags & CON_ENABLED)) |
| 1211 | return; | 1241 | return; |
| 1212 | 1242 | ||
| 1213 | if (bootconsole && (console->flags & CON_CONSDEV)) { | 1243 | if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) { |
| 1214 | printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n", | 1244 | /* we need to iterate through twice, to make sure we print |
| 1215 | bootconsole->name, bootconsole->index, | 1245 | * everything out, before we unregister the console(s) |
| 1216 | console->name, console->index); | 1246 | */ |
| 1217 | unregister_console(bootconsole); | 1247 | printk(KERN_INFO "console handover:"); |
| 1218 | console->flags &= ~CON_PRINTBUFFER; | 1248 | for_each_console(bcon) |
| 1249 | printk("boot [%s%d] ", bcon->name, bcon->index); | ||
| 1250 | printk(" -> real [%s%d]\n", newcon->name, newcon->index); | ||
| 1251 | for_each_console(bcon) | ||
| 1252 | unregister_console(bcon); | ||
| 1253 | newcon->flags &= ~CON_PRINTBUFFER; | ||
| 1219 | } else { | 1254 | } else { |
| 1220 | printk(KERN_INFO "console [%s%d] enabled\n", | 1255 | printk(KERN_INFO "%sconsole [%s%d] enabled\n", |
| 1221 | console->name, console->index); | 1256 | (newcon->flags & CON_BOOT) ? "boot" : "" , |
| 1257 | newcon->name, newcon->index); | ||
| 1222 | } | 1258 | } |
| 1223 | 1259 | ||
| 1224 | /* | 1260 | /* |
| @@ -1226,16 +1262,16 @@ void register_console(struct console *console) | |||
| 1226 | * preferred driver at the head of the list. | 1262 | * preferred driver at the head of the list. |
| 1227 | */ | 1263 | */ |
| 1228 | acquire_console_sem(); | 1264 | acquire_console_sem(); |
| 1229 | if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { | 1265 | if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { |
| 1230 | console->next = console_drivers; | 1266 | newcon->next = console_drivers; |
| 1231 | console_drivers = console; | 1267 | console_drivers = newcon; |
| 1232 | if (console->next) | 1268 | if (newcon->next) |
| 1233 | console->next->flags &= ~CON_CONSDEV; | 1269 | newcon->next->flags &= ~CON_CONSDEV; |
| 1234 | } else { | 1270 | } else { |
| 1235 | console->next = console_drivers->next; | 1271 | newcon->next = console_drivers->next; |
| 1236 | console_drivers->next = console; | 1272 | console_drivers->next = newcon; |
| 1237 | } | 1273 | } |
| 1238 | if (console->flags & CON_PRINTBUFFER) { | 1274 | if (newcon->flags & CON_PRINTBUFFER) { |
| 1239 | /* | 1275 | /* |
| 1240 | * release_console_sem() will print out the buffered messages | 1276 | * release_console_sem() will print out the buffered messages |
| 1241 | * for us. | 1277 | * for us. |
| @@ -1287,11 +1323,13 @@ EXPORT_SYMBOL(unregister_console); | |||
| 1287 | 1323 | ||
| 1288 | static int __init disable_boot_consoles(void) | 1324 | static int __init disable_boot_consoles(void) |
| 1289 | { | 1325 | { |
| 1290 | if (console_drivers != NULL) { | 1326 | struct console *con; |
| 1291 | if (console_drivers->flags & CON_BOOT) { | 1327 | |
| 1328 | for_each_console(con) { | ||
| 1329 | if (con->flags & CON_BOOT) { | ||
| 1292 | printk(KERN_INFO "turn off boot console %s%d\n", | 1330 | printk(KERN_INFO "turn off boot console %s%d\n", |
| 1293 | console_drivers->name, console_drivers->index); | 1331 | con->name, con->index); |
| 1294 | return unregister_console(console_drivers); | 1332 | return unregister_console(con); |
| 1295 | } | 1333 | } |
| 1296 | } | 1334 | } |
| 1297 | return 0; | 1335 | return 0; |
