• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
35 union screen _cursor;
36 union 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 
50 uint8_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  */
loadkeys(const char * filename)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  */
write_serial(char data)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 
pm_write_serial(com32sys_t * regs)105 void pm_write_serial(com32sys_t *regs)
106 {
107 	write_serial(regs->eax.b[0]);
108 }
109 
serialcfg(uint16_t * iobase,uint16_t * divisor,uint16_t * flowctl)110 void 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 
pm_serialcfg(com32sys_t * regs)130 void 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  */
write_serial_str(char * data)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  */
bios_pollchar(void)151 int 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 
pollchar(void)191 __export int pollchar(void)
192 {
193 	return firmware->i_ops->pollchar();
194 }
195 
pm_pollchar(com32sys_t * regs)196 void 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 
bios_getchar(char * hi)204 char 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 
bios_shiftflags(void)271 uint8_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 
kbd_shiftflags(void)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  */
getchar(char * hi)308 __export char getchar(char *hi)
309 {
310 	return firmware->i_ops->getchar(hi);
311 }
312 
pm_getchar(com32sys_t * regs)313 void pm_getchar(com32sys_t *regs)
314 {
315 	regs->eax.b[0] = getchar((char *)&regs->eax.b[1]);
316 }
317