blob: 427228ea045c78cd0e5f8677f274d0fcee476cc1 [file] [log] [blame]
Greg Hartman76d05dc2016-11-23 15:51:27 -08001/*
2 * -----------------------------------------------------------------------
3 *
4 * Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
5 * Copyright 2009-2014 Intel Corporation; author: H. Peter Anvin
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
10 * Boston MA 02111-1307, USA; either version 2 of the License, or
11 * (at your option) any later version; incorporated herein by reference.
12 *
13 * -----------------------------------------------------------------------
14 *
15 *
16 * conio.c
17 *
18 * Console I/O code, except:
19 * writechr, writestr_early - module-dependent
20 * writestr, crlf - writestr.inc
21 * writehex* - writehex.inc
22 */
23#include <sys/io.h>
24#include <stddef.h>
25#include <stdio.h>
26#include <string.h>
27#include <fs.h>
28#include <com32.h>
29#include <sys/cpu.h>
30#include <syslinux/firmware.h>
31
32#include "bios.h"
33#include "graphics.h"
34
35union screen _cursor;
36union screen _screensize;
37
38/*
39 * Serial console stuff.
40 */
41__export uint16_t SerialPort = 0; /* Serial port base (or 0 for no serial port) */
42__export uint8_t FlowInput = 0; /* Input bits for serial flow */
43__export uint16_t BaudDivisor = 115200/9600; /* Baud rate divisor */
44__export uint8_t FlowIgnore = 0; /* Ignore input unless these bits set */
45__export uint16_t DisplayCon = 0x01; /* Display console enabled */
46__export uint8_t FlowOutput = 0; /* Output to assert for serial flow */
47
48__export uint8_t DisplayMask = 0x07; /* Display modes mask */
49
50uint8_t ScrollAttribute = 0x07; /* Grey on white (normal text color) */
51
52/*
53 * loadkeys: Load a LILO-style keymap
54 *
55 * Returns 0 on success, or -1 on error.
56 */
57__export int loadkeys(const char *filename)
58{
59 FILE *f;
60
61 f = fopen(filename, "r");
62 if (!f)
63 return -1;
64
65 fread(KbdMap, 1, sizeof(KbdMap), f);
66
67 fclose(f);
68 return 0;
69}
70
71/*
72 * write_serial: If serial output is enabled, write character on
73 * serial port.
74 */
75__export void write_serial(char data)
76{
77 if (!SerialPort)
78 return;
79
80 if (!(DisplayMask & 0x04))
81 return;
82
83 while (1) {
84 char ch;
85
86 ch = inb(SerialPort + 5); /* LSR */
87
88 /* Wait for space in transmit register */
89 if (!(ch & 0x20))
90 continue;
91
92 /* Wait for input flow control */
93 ch = inb(SerialPort + 6);
94 ch &= FlowInput;
95 if (ch != FlowInput)
96 continue;
97
98 break;
99 }
100
101 outb(data, SerialPort); /* Send data */
102 io_delay();
103}
104
105void pm_write_serial(com32sys_t *regs)
106{
107 write_serial(regs->eax.b[0]);
108}
109
110void serialcfg(uint16_t *iobase, uint16_t *divisor, uint16_t *flowctl)
111{
112 uint8_t al, ah;
113
114 *iobase = SerialPort;
115 *divisor = BaudDivisor;
116
117 al = FlowOutput;
118 ah = FlowInput;
119
120 al |= ah;
121 ah = FlowIgnore;
122 ah >>= 4;
123
124 if (!DisplayCon)
125 ah |= 0x80;
126
127 *flowctl = al | (ah << 8);
128}
129
130void pm_serialcfg(com32sys_t *regs)
131{
132 serialcfg(&regs->eax.w[0], &regs->ecx.w[0], &regs->ebx.w[0]);
133}
134
135/*
136 * write_serial_str: write_serial for strings
137 */
138__export void write_serial_str(char *data)
139{
140 char ch;
141
142 while ((ch = *data++))
143 write_serial(ch);
144}
145
146/*
147 * pollchar: check if we have an input character pending
148 *
149 * Returns 1 if character pending.
150 */
151int bios_pollchar(void)
152{
153 com32sys_t ireg, oreg;
154 uint8_t data = 0;
155
156 memset(&ireg, 0, sizeof(ireg));
157
158 ireg.eax.b[1] = 0x11; /* Poll keyboard */
159 __intcall(0x16, &ireg, &oreg);
160
161 if (!(oreg.eflags.l & EFLAGS_ZF))
162 return 1;
163
164 if (SerialPort) {
165 cli();
166
167 /* Already-queued input? */
168 if (SerialTail == SerialHead) {
169 /* LSR */
170 data = inb(SerialPort + 5) & 1;
171 if (data) {
172 /* MSR */
173 data = inb(SerialPort + 6);
174
175 /* Required status bits */
176 data &= FlowIgnore;
177
178 if (data == FlowIgnore)
179 data = 1;
180 else
181 data = 0;
182 }
183 } else
184 data = 1;
185 sti();
186 }
187
188 return data;
189}
190
191__export int pollchar(void)
192{
193 return firmware->i_ops->pollchar();
194}
195
196void pm_pollchar(com32sys_t *regs)
197{
198 if (pollchar())
199 regs->eflags.l &= ~EFLAGS_ZF;
200 else
201 regs->eflags.l |= EFLAGS_ZF;
202}
203
204char bios_getchar(char *hi)
205{
206 com32sys_t ireg, oreg;
207 unsigned char data;
208
209 memset(&ireg, 0, sizeof(ireg));
210 memset(&oreg, 0, sizeof(oreg));
211 while (1) {
212 __idle();
213
214 ireg.eax.b[1] = 0x11; /* Poll keyboard */
215 __intcall(0x16, &ireg, &oreg);
216
217 if (oreg.eflags.l & EFLAGS_ZF) {
218 if (!SerialPort)
219 continue;
220
221 cli();
222 if (SerialTail != SerialHead) {
223 /* serial queued */
224 sti(); /* We already know we'll consume data */
225 data = *SerialTail++;
226
227 if (SerialTail > SerialHead + serial_buf_size)
228 SerialTail = SerialHead;
229 } else {
230 /* LSR */
231 data = inb(SerialPort + 5) & 1;
232 if (!data) {
233 sti();
234 continue;
235 }
236 data = inb(SerialPort + 6);
237 data &= FlowIgnore;
238 if (data != FlowIgnore) {
239 sti();
240 continue;
241 }
242
243 data = inb(SerialPort);
244 sti();
245 break;
246 }
247 } else {
248 /* Keyboard input? */
249 ireg.eax.b[1] = 0x10; /* Get keyboard input */
250 __intcall(0x16, &ireg, &oreg);
251
252 data = oreg.eax.b[0];
253 *hi = oreg.eax.b[1];
254
255 if (data == 0xE0)
256 data = 0;
257
258 if (data) {
259 /* Convert character sets */
260 data = KbdMap[data];
261 }
262 }
263
264 break;
265 }
266
267 reset_idle(); /* Character received */
268 return data;
269}
270
271uint8_t bios_shiftflags(void)
272{
273 com32sys_t reg;
274 uint8_t ah, al;
275
276 memset(&reg, 0, sizeof reg);
277 reg.eax.b[1] = 0x12;
278 __intcall(0x16, &reg, &reg);
279 ah = reg.eax.b[1];
280 al = reg.eax.b[0];
281
282 /*
283 * According to the Interrupt List, "many machines" don't correctly
284 * fold the Alt state, presumably because it might be AltGr.
285 * Explicitly fold the Alt and Ctrl states; it fits our needs
286 * better.
287 */
288
289 if (ah & 0x0a)
290 al |= 0x08;
291 if (ah & 0x05)
292 al |= 0x04;
293
294 return al;
295}
296
297__export uint8_t kbd_shiftflags(void)
298{
299 if (firmware->i_ops->shiftflags)
300 return firmware->i_ops->shiftflags();
301 else
302 return 0; /* Unavailable on this firmware */
303}
304
305/*
306 * getchar: Read a character from keyboard or serial port
307 */
308__export char getchar(char *hi)
309{
310 return firmware->i_ops->getchar(hi);
311}
312
313void pm_getchar(com32sys_t *regs)
314{
315 regs->eax.b[0] = getchar((char *)&regs->eax.b[1]);
316}