0001
0002
0003
0004
0005
0006 #include "boot.h"
0007
0008 #define DEFAULT_SERIAL_PORT 0x3f8
0009
0010 #define DLAB 0x80
0011
0012 #define TXR 0
0013 #define RXR 0
0014 #define IER 1
0015 #define IIR 2
0016 #define FCR 2
0017 #define LCR 3
0018 #define MCR 4
0019 #define LSR 5
0020 #define MSR 6
0021 #define DLL 0
0022 #define DLH 1
0023
0024 #define DEFAULT_BAUD 9600
0025
0026 static void early_serial_init(int port, int baud)
0027 {
0028 unsigned char c;
0029 unsigned divisor;
0030
0031 outb(0x3, port + LCR);
0032 outb(0, port + IER);
0033 outb(0, port + FCR);
0034 outb(0x3, port + MCR);
0035
0036 divisor = 115200 / baud;
0037 c = inb(port + LCR);
0038 outb(c | DLAB, port + LCR);
0039 outb(divisor & 0xff, port + DLL);
0040 outb((divisor >> 8) & 0xff, port + DLH);
0041 outb(c & ~DLAB, port + LCR);
0042
0043 early_serial_base = port;
0044 }
0045
0046 static void parse_earlyprintk(void)
0047 {
0048 int baud = DEFAULT_BAUD;
0049 char arg[32];
0050 int pos = 0;
0051 int port = 0;
0052
0053 if (cmdline_find_option("earlyprintk", arg, sizeof(arg)) > 0) {
0054 char *e;
0055
0056 if (!strncmp(arg, "serial", 6)) {
0057 port = DEFAULT_SERIAL_PORT;
0058 pos += 6;
0059 }
0060
0061 if (arg[pos] == ',')
0062 pos++;
0063
0064
0065
0066
0067
0068
0069
0070 if (pos == 7 && !strncmp(arg + pos, "0x", 2)) {
0071 port = simple_strtoull(arg + pos, &e, 16);
0072 if (port == 0 || arg + pos == e)
0073 port = DEFAULT_SERIAL_PORT;
0074 else
0075 pos = e - arg;
0076 } else if (!strncmp(arg + pos, "ttyS", 4)) {
0077 static const int bases[] = { 0x3f8, 0x2f8 };
0078 int idx = 0;
0079
0080
0081 pos += 4;
0082
0083 if (arg[pos++] == '1')
0084 idx = 1;
0085
0086 port = bases[idx];
0087 }
0088
0089 if (arg[pos] == ',')
0090 pos++;
0091
0092 baud = simple_strtoull(arg + pos, &e, 0);
0093 if (baud == 0 || arg + pos == e)
0094 baud = DEFAULT_BAUD;
0095 }
0096
0097 if (port)
0098 early_serial_init(port, baud);
0099 }
0100
0101 #define BASE_BAUD (1843200/16)
0102 static unsigned int probe_baud(int port)
0103 {
0104 unsigned char lcr, dll, dlh;
0105 unsigned int quot;
0106
0107 lcr = inb(port + LCR);
0108 outb(lcr | DLAB, port + LCR);
0109 dll = inb(port + DLL);
0110 dlh = inb(port + DLH);
0111 outb(lcr, port + LCR);
0112 quot = (dlh << 8) | dll;
0113
0114 return BASE_BAUD / quot;
0115 }
0116
0117 static void parse_console_uart8250(void)
0118 {
0119 char optstr[64], *options;
0120 int baud = DEFAULT_BAUD;
0121 int port = 0;
0122
0123
0124
0125
0126
0127 if (cmdline_find_option("console", optstr, sizeof(optstr)) <= 0)
0128 return;
0129
0130 options = optstr;
0131
0132 if (!strncmp(options, "uart8250,io,", 12))
0133 port = simple_strtoull(options + 12, &options, 0);
0134 else if (!strncmp(options, "uart,io,", 8))
0135 port = simple_strtoull(options + 8, &options, 0);
0136 else
0137 return;
0138
0139 if (options && (options[0] == ','))
0140 baud = simple_strtoull(options + 1, &options, 0);
0141 else
0142 baud = probe_baud(port);
0143
0144 if (port)
0145 early_serial_init(port, baud);
0146 }
0147
0148 void console_init(void)
0149 {
0150 parse_earlyprintk();
0151
0152 if (!early_serial_base)
0153 parse_console_uart8250();
0154 }