Reduce warnings/errors in libpayload when using picky compiler options
[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 MEMBASE (phys_to_virt(lib_sysinfo.ser_base))
36 #define DIVISOR(x) (115200 / x)
37
38 #ifdef CONFIG_SERIAL_SET_SPEED
39 static void serial_io_hardware_init(int port, int speed, int word_bits, int parity, int stop_bits)
40 {
41         unsigned char reg;
42
43         /* We will assume 8n1 for now. Does anyone use anything else these days? */
44
45         /* Disable interrupts. */
46         outb(0, port + 0x01);
47
48         /* Assert RTS and DTR. */
49         outb(3, port + 0x04);
50
51         /* Set the divisor latch. */
52         reg = inb(port + 0x03);
53         outb(reg | 0x80, port + 0x03);
54
55         /* Write the divisor. */
56         outb(DIVISOR(speed) & 0xFF, port);
57         outb(DIVISOR(speed) >> 8 & 0xFF, port + 1);
58
59         /* Restore the previous value of the divisor. */
60         outb(reg & ~0x80, port + 0x03);
61 }
62
63 static void serial_mem_hardware_init(int port, int speed, int word_bits, int parity, int stop_bits)
64 {
65         unsigned char reg;
66
67         /* We will assume 8n1 for now. Does anyone use anything else these days? */
68
69         /* Disable interrupts. */
70         writeb(0, MEMBASE + 0x01);
71
72         /* Assert RTS and DTR. */
73         writeb(3, MEMBASE + 0x04);
74
75         /* Set the divisor latch. */
76         reg = readb(MEMBASE + 0x03);
77         writeb(reg | 0x80, MEMBASE + 0x03);
78
79         /* Write the divisor. */
80         writeb(DIVISOR(speed) & 0xFF, MEMBASE);
81         writeb(DIVISOR(speed) >> 8 & 0xFF, MEMBASE + 1);
82
83         /* Restore the previous value of the divisor. */
84         writeb(reg & ~0x80, MEMBASE + 0x03);
85 }
86 #endif
87
88 static struct console_input_driver consin = {
89         .havekey = serial_havechar,
90         .getchar = serial_getchar
91 };
92
93 static struct console_output_driver consout = {
94         .putchar = serial_putchar
95 };
96
97 void serial_init(void)
98 {
99         pcidev_t oxpcie_dev;
100         if (pci_find_device(0x1415, 0xc158, &oxpcie_dev)) {
101                 lib_sysinfo.ser_base = pci_read_resource(oxpcie_dev, 0) + 0x1000;
102         } else {
103                 lib_sysinfo.ser_base = 0;
104         }
105
106 #ifdef CONFIG_SERIAL_SET_SPEED
107         if (lib_sysinfo.ser_base)
108                 serial_mem_hardware_init(IOBASE, CONFIG_SERIAL_BAUD_RATE, 8, 0, 1);
109         else
110                 serial_io_hardware_init(IOBASE, CONFIG_SERIAL_BAUD_RATE, 8, 0, 1);
111 #endif
112         console_add_input_driver(&consin);
113         console_add_output_driver(&consout);
114 }
115
116 static void serial_io_putchar(unsigned int c)
117 {
118         c &= 0xff;
119         while ((inb(IOBASE + 0x05) & 0x20) == 0) ;
120         outb(c, IOBASE);
121 }
122
123 static int serial_io_havechar(void)
124 {
125         return inb(IOBASE + 0x05) & 0x01;
126 }
127
128 static int serial_io_getchar(void)
129 {
130         while (!serial_io_havechar()) ;
131         return (int)inb(IOBASE);
132 }
133
134 static void serial_mem_putchar(unsigned int c)
135 {
136         c &= 0xff;
137         while ((readb(MEMBASE + 0x05) & 0x20) == 0) ;
138         writeb(c, MEMBASE);
139 }
140
141 static int serial_mem_havechar(void)
142 {
143         return readb(MEMBASE + 0x05) & 0x01;
144 }
145
146 static int serial_mem_getchar(void)
147 {
148         while (!serial_mem_havechar()) ;
149         return (int)readb(MEMBASE);
150 }
151
152
153 void serial_putchar(unsigned int c)
154 {
155         if (lib_sysinfo.ser_base)
156                 serial_mem_putchar(c);
157         else
158                 serial_io_putchar(c);
159 }
160
161 int serial_havechar(void)
162 {
163         if (lib_sysinfo.ser_base)
164                 return serial_mem_havechar();
165         else
166                 return serial_io_havechar();
167 }
168
169 int serial_getchar(void)
170 {
171         if (lib_sysinfo.ser_base)
172                 return serial_mem_getchar();
173         else
174                 return serial_io_getchar();
175 }
176
177 /*  These are thinly veiled vt100 functions used by curses */
178
179 #define VT100_CLEAR       "\e[H\e[J"
180 /* These defines will fail if you use bold and reverse at the same time.
181  * Switching off one of them will switch off both. tinycurses knows about
182  * this and does the right thing.
183  */
184 #define VT100_SBOLD       "\e[1m"
185 #define VT100_EBOLD       "\e[m"
186 #define VT100_SREVERSE    "\e[7m"
187 #define VT100_EREVERSE    "\e[m"
188 #define VT100_CURSOR_ADDR "\e[%d;%dH"
189 #define VT100_CURSOR_ON   "\e[?25l"
190 #define VT100_CURSOR_OFF  "\e[?25h"
191 /* The following smacs/rmacs are actually for xterm; a real vt100 has
192    enacs=\E(B\E)0, smacs=^N, rmacs=^O.  */
193 #define VT100_SMACS       "\e(0"
194 #define VT100_RMACS       "\e(B"
195 /* A vt100 doesn't do color, setaf/setab below are from xterm-color. */
196 #define VT100_SET_COLOR   "\e[3%d;4%dm"
197
198 static void serial_putcmd(const char *str)
199 {
200         while(*str)
201                 serial_putchar(*(str++));
202 }
203
204 void serial_clear(void)
205 {
206         serial_putcmd(VT100_CLEAR);
207 }
208
209 void serial_start_bold(void)
210 {
211         serial_putcmd(VT100_SBOLD);
212 }
213
214 void serial_end_bold(void)
215 {
216         serial_putcmd(VT100_EBOLD);
217 }
218
219 void serial_start_reverse(void)
220 {
221         serial_putcmd(VT100_SREVERSE);
222 }
223
224 void serial_end_reverse(void)
225 {
226         serial_putcmd(VT100_EREVERSE);
227 }
228
229 void serial_start_altcharset(void)
230 {
231         serial_putcmd(VT100_SMACS);
232 }
233
234 void serial_end_altcharset(void)
235 {
236         serial_putcmd(VT100_RMACS);
237 }
238
239 /**
240  * Set the foreground and background colors on the serial console.
241  *
242  * @param fg Foreground color number.
243  * @param bg Background color number.
244  */
245 void serial_set_color(short fg, short bg)
246 {
247         char buffer[32];
248         snprintf(buffer, sizeof(buffer), VT100_SET_COLOR, fg, bg);
249         serial_putcmd(buffer);
250 }
251
252 void serial_set_cursor(int y, int x)
253 {
254         char buffer[32];
255         snprintf(buffer, sizeof(buffer), VT100_CURSOR_ADDR, y + 1, x + 1);
256         serial_putcmd(buffer);
257 }
258
259 void serial_cursor_enable(int state)
260 {
261         if (state)
262                 serial_putcmd(VT100_CURSOR_ON);
263         else
264                 serial_putcmd(VT100_CURSOR_OFF);
265 }