9fd7acf6be2d2d8b701ceca275e25aaeddc118cd
[coreboot.git] / payloads / libpayload / drivers / serial.c
1 /*
2  * This file is part of the libpayload project.
3  *
4  * Copyright (C) 2008 Advanced Micro Devices, Inc.
5  * Copyright (C) 2008 Ulf Jordan <jordan@chalmers.se>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <libpayload-config.h>
32 #include <libpayload.h>
33
34 #define IOBASE lib_sysinfo.ser_ioport
35 #define DIVISOR(x) (115200 / x)
36
37 void serial_hardware_init(int port, int speed, int word_bits, int parity, int stop_bits)
38 {
39         unsigned char reg;
40
41         /* We will assume 8n1 for now. Does anyone use anything else these days? */
42
43         /* Disable interrupts. */
44         outb(0, port + 0x01);
45
46         /* Assert RTS and DTR. */
47         outb(3, port + 0x04);
48
49         /* Set the divisor latch. */
50         reg = inb(port + 0x03);
51         outb(reg | 0x80, port + 0x03);
52
53         /* Write the divisor. */
54         outb(DIVISOR(speed) & 0xFF, port);
55         outb(DIVISOR(speed) >> 8 & 0xFF, port + 1);
56
57         /* Restore the previous value of the divisor. */
58         outb(reg & ~0x80, port + 0x03);
59 }
60
61 static struct console_input_driver consin = {
62         .havekey = serial_havechar,
63         .getchar = serial_getchar
64 };
65
66 static struct console_output_driver consout = {
67         .putchar = serial_putchar
68 };
69
70 void serial_init(void)
71 {
72 #ifdef CONFIG_SERIAL_SET_SPEED
73         serial_hardware_init(IOBASE, CONFIG_SERIAL_BAUD_RATE, 8, 0, 1);
74 #endif
75         console_add_input_driver(&consin);
76         console_add_output_driver(&consout);
77 }
78
79 void serial_putchar(unsigned int c)
80 {
81         c &= 0xff;
82         while ((inb(IOBASE + 0x05) & 0x20) == 0) ;
83         outb(c, IOBASE);
84 }
85
86 int serial_havechar(void)
87 {
88         return inb(IOBASE + 0x05) & 0x01;
89 }
90
91 int serial_getchar(void)
92 {
93         while (!serial_havechar()) ;
94         return (int)inb(IOBASE);
95 }
96
97 /*  These are thinly veiled vt100 functions used by curses */
98
99 #define VT100_CLEAR       "\e[H\e[J"
100 /* These defines will fail if you use bold and reverse at the same time.
101  * Switching off one of them will switch off both. tinycurses knows about
102  * this and does the right thing.
103  */
104 #define VT100_SBOLD       "\e[1m"
105 #define VT100_EBOLD       "\e[m"
106 #define VT100_SREVERSE    "\e[7m"
107 #define VT100_EREVERSE    "\e[m"
108 #define VT100_CURSOR_ADDR "\e[%d;%dH"
109 #define VT100_CURSOR_ON   "\e[?25l"
110 #define VT100_CURSOR_OFF  "\e[?25h"
111 /* The following smacs/rmacs are actually for xterm; a real vt100 has
112    enacs=\E(B\E)0, smacs=^N, rmacs=^O.  */
113 #define VT100_SMACS       "\e(0"
114 #define VT100_RMACS       "\e(B"
115 /* A vt100 doesn't do color, setaf/setab below are from xterm-color. */
116 #define VT100_SET_COLOR   "\e[3%d;4%dm"
117
118 static void serial_putcmd(char *str)
119 {
120         while(*str)
121                 serial_putchar(*(str++));
122 }
123
124 void serial_clear(void)
125 {
126         serial_putcmd(VT100_CLEAR);
127 }
128
129 void serial_start_bold(void)
130 {
131         serial_putcmd(VT100_SBOLD);
132 }
133
134 void serial_end_bold(void)
135 {
136         serial_putcmd(VT100_EBOLD);
137 }
138
139 void serial_start_reverse(void)
140 {
141         serial_putcmd(VT100_SREVERSE);
142 }
143
144 void serial_end_reverse(void)
145 {
146         serial_putcmd(VT100_EREVERSE);
147 }
148
149 void serial_start_altcharset(void)
150 {
151         serial_putcmd(VT100_SMACS);
152 }
153
154 void serial_end_altcharset(void)
155 {
156         serial_putcmd(VT100_RMACS);
157 }
158
159 /**
160  * Set the foreground and background colors on the serial console.
161  *
162  * @param fg Foreground color number.
163  * @param bg Background color number.
164  */
165 void serial_set_color(short fg, short bg)
166 {
167         char buffer[32];
168         snprintf(buffer, sizeof(buffer), VT100_SET_COLOR, fg, bg);
169         serial_putcmd(buffer);
170 }
171
172 void serial_set_cursor(int y, int x)
173 {
174         char buffer[32];
175         snprintf(buffer, sizeof(buffer), VT100_CURSOR_ADDR, y + 1, x + 1);
176         serial_putcmd(buffer);
177 }
178
179 void serial_cursor_enable(int state)
180 {
181         if (state)
182                 serial_putcmd(VT100_CURSOR_ON);
183         else
184                 serial_putcmd(VT100_CURSOR_OFF);
185 }