Merge commit 'd76af0754db7ddd4c06215d922d213c93178c0af' into elflink
[syslinux/sherbszt.git] / core / conio.c
blob421dabfd1864d33f4743e6cca563e86801190808
1 /*
2 * -----------------------------------------------------------------------
4 * Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
5 * Copyright 2009 Intel Corporation; author: H. Peter Anvin
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.
13 * -----------------------------------------------------------------------
16 * conio.c
18 * Console I/O code, except:
19 * writechr, writestr_early - module-dependent
20 * writestr, crlf - writestr.inc
21 * writehex* - writehex.inc
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>
31 #include "bios.h"
32 #include "graphics.h"
34 union screen _cursor;
35 union screen _screensize;
38 * Serial console stuff.
40 uint16_t SerialPort = 0; /* Serial port base (or 0 for no serial port) */
41 uint16_t BaudDivisor = 115200/9600; /* Baud rate divisor */
42 uint8_t FlowOutput = 0; /* Output to assert for serial flow */
43 uint8_t FlowInput = 0; /* Input bits for serial flow */
44 uint8_t FlowIgnore = 0; /* Ignore input unless these bits set */
46 uint8_t ScrollAttribute = 0x07; /* Grey on white (normal text color) */
47 uint16_t DisplayCon = 0x01; /* Display console enabled */
48 static uint8_t TextAttribute; /* Text attribute for message file */
49 static uint8_t DisplayMask; /* Display modes mask */
51 /* Routine to interpret next print char */
52 static void (*NextCharJump)(char);
54 void msg_initvars(void);
55 static void msg_setfg(char data);
56 static void msg_putchar(char ch);
59 * loadkeys: Load a LILO-style keymap
61 * Returns 0 on success, or -1 on error.
63 int loadkeys(char *filename)
65 FILE *f;
67 f = fopen(filename, "r");
68 if (!f)
69 return -1;
71 fread(KbdMap, 1, sizeof(KbdMap), f);
73 fclose(f);
74 return 0;
79 * get_msg_file: Load a text file and write its contents to the screen,
80 * interpreting color codes.
82 * Returns 0 on success, -1 on failure.
84 int get_msg_file(char *filename)
86 FILE *f;
87 char ch;
89 f = fopen(filename, "r");
90 if (!f)
91 return -1;
93 TextAttribute = 0x7; /* Default grey on white */
94 DisplayMask = 0x7; /* Display text in all modes */
95 msg_initvars();
98 * Read the text file a byte at a time and interpret that
99 * byte.
101 while ((ch = getc(f)) != EOF) {
102 /* DOS EOF? */
103 if (ch == 0x1A)
104 break;
107 * 01h = text mode
108 * 02h = graphics mode
110 UsingVGA &= 0x1;
111 UsingVGA += 1;
113 NextCharJump(ch); /* Do what shall be done */
116 fclose(f);
117 return 0;
120 static inline void msg_beep(void)
122 com32sys_t ireg, oreg;
124 ireg.eax.w[0] = 0x0E07; /* Beep */
125 ireg.ebx.w[0] = 0x0000;
126 __intcall(0x10, &ireg, &oreg);
130 * write_serial: If serial output is enabled, write character on
131 * serial port.
133 void write_serial(char data)
135 if (!SerialPort)
136 return;
138 while (1) {
139 char ch;
141 ch = inb(SerialPort + 5); /* LSR */
143 /* Wait for space in transmit register */
144 if (!(ch & 0x20))
145 continue;
147 /* Wait for input flow control */
148 ch = inb(SerialPort + 6);
149 ch &= FlowInput;
150 if (ch != FlowInput)
151 continue;
153 break;
156 outb(data, SerialPort); /* Send data */
157 io_delay();
160 void pm_write_serial(com32sys_t *regs)
162 write_serial(regs->eax.b[0]);
165 void pm_serialcfg(com32sys_t *regs)
167 uint8_t al, ah;
169 regs->eax.w[0] = SerialPort;
170 regs->ecx.w[0] = BaudDivisor;
172 al = FlowOutput;
173 ah = FlowInput;
175 al |= ah;
176 ah = FlowIgnore;
177 ah >>= 4;
179 if (!DisplayCon)
180 ah |= 0x80;
182 regs->ebx.w[0] = al | (ah << 8);
185 static void write_serial_displaymask(char data)
187 if (DisplayMask & 0x4)
188 write_serial(data);
192 * write_serial_str: write_serial for strings
194 void write_serial_str(char *data)
196 char ch;
198 while ((ch = *data++))
199 write_serial(ch);
203 * write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0
205 static void write_serial_str_displaymask(char *data)
207 if (DisplayMask & 0x4)
208 write_serial_str(data);
212 * pollchar: check if we have an input character pending
214 * Returns 1 if character pending.
216 int pollchar(void)
218 com32sys_t ireg, oreg;
219 uint8_t data = 0;
221 memset(&ireg, 0, sizeof(ireg));
223 ireg.eax.b[1] = 0x11; /* Poll keyboard */
224 __intcall(0x16, &ireg, &oreg);
226 if (!(oreg.eflags.l & EFLAGS_ZF))
227 return 1;
229 if (SerialPort) {
230 cli();
232 /* Already-queued input? */
233 if (SerialTail == SerialHead) {
234 /* LSR */
235 data = inb(SerialPort + 5) & 1;
236 if (data) {
237 /* MSR */
238 data = inb(SerialPort + 6);
240 /* Required status bits */
241 if (data) {
242 data &= FlowIgnore;
243 if (data != FlowIgnore)
244 data = 0;
245 else
246 data = 1;
250 sti();
253 return data;
256 void pm_pollchar(com32sys_t *regs)
258 if (pollchar())
259 regs->eflags.l &= ~EFLAGS_ZF;
260 else
261 regs->eflags.l |= EFLAGS_ZF;
264 extern void do_idle(void);
267 * getchar: Read a character from keyboard or serial port
269 char getchar(char *hi)
271 com32sys_t ireg, oreg;
272 unsigned char data;
274 memset(&ireg, 0, sizeof(ireg));
275 memset(&oreg, 0, sizeof(oreg));
276 while (1) {
277 call16(do_idle, &zero_regs, NULL);
279 ireg.eax.b[1] = 0x11; /* Poll keyboard */
280 __intcall(0x16, &ireg, &oreg);
282 if (oreg.eflags.l & EFLAGS_ZF) {
283 if (!SerialPort)
284 continue;
286 cli();
287 if (SerialTail != SerialHead) {
288 /* serial queued */
289 sti(); /* We already know we'll consume data */
290 data = *SerialTail++;
292 SerialTail = (char *)((unsigned long)SerialTail & (serial_buf_size - 1));
293 } else {
294 /* LSR */
295 data = inb(SerialPort + 5) & 1;
296 if (!data) {
297 sti();
298 continue;
300 data = inb(SerialPort + 6);
301 data &= FlowIgnore;
302 if (data != FlowIgnore) {
303 sti();
304 continue;
307 data = inb(SerialPort);
308 sti();
309 break;
311 } else {
312 /* Keyboard input? */
313 ireg.eax.b[1] = 0x10; /* Get keyboard input */
314 __intcall(0x16, &ireg, &oreg);
316 data = oreg.eax.b[0];
317 *hi = oreg.eax.b[1];
319 if (data == 0xE0)
320 data = 0;
322 if (data) {
323 /* Convert character sets */
324 data = KbdMap[data];
328 break;
331 reset_idle(); /* Character received */
332 return data;
335 void pm_getchar(com32sys_t *regs)
337 regs->eax.b[0] = getchar((char *)&regs->eax.b[1]);
340 static void msg_setbg(char data)
342 if (unhexchar(&data) == 0) {
343 data <<= 4;
344 if (DisplayMask & UsingVGA)
345 TextAttribute = data;
347 NextCharJump = msg_setfg;
348 } else {
349 TextAttribute = 0x7; /* Default attribute */
350 NextCharJump = msg_putchar;
354 static void msg_setfg(char data)
356 if (unhexchar(&data) == 0) {
357 if (DisplayMask & UsingVGA) {
358 /* setbg set foreground to 0 */
359 TextAttribute |= data;
361 } else
362 TextAttribute = 0x7; /* Default attribute */
364 NextCharJump = msg_putchar;
367 static inline void msg_ctrl_o(void)
369 NextCharJump = msg_setbg;
372 static void msg_gotoxy(void)
374 com32sys_t ireg, oreg;
376 memset(&ireg, 0, sizeof(ireg));
378 ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
379 ireg.edx.w[0] = CursorDX;
380 ireg.eax.b[1] = 0x02; /* Set cursor position */
382 __intcall(0x10, &ireg, &oreg);
385 static void msg_newline(void)
387 com32sys_t ireg, oreg;
388 char crlf_msg[] = { '\r', '\n', '\0' };
390 write_serial_str_displaymask(crlf_msg);
392 if (!(DisplayMask & UsingVGA))
393 return;
395 CursorCol = 0;
396 if ((CursorRow + 1) <= VidRows)
397 CursorRow++;
398 else {
399 ireg.ecx.w[0] = 0x0; /* Upper left hand corner */
400 ireg.edx.w[0] = ScreenSize;
402 CursorRow = ireg.edx.b[1]; /* New cursor at the bottom */
404 ireg.ebx.b[1] = ScrollAttribute;
405 ireg.eax.w[0] = 0x0601; /* Scroll up one line */
407 __intcall(0x10, &ireg, &oreg);
410 msg_gotoxy();
413 static void msg_formfeed(void)
415 char crff_msg[] = { '\r', '\f', '\0' };
417 write_serial_str_displaymask(crff_msg);
419 if (DisplayMask & UsingVGA) {
420 com32sys_t ireg, oreg;
422 memset(&ireg, 0, sizeof(ireg));
424 CursorDX = 0x0; /* Upper left hand corner */
426 ireg.edx.w[0] = ScreenSize;
427 ireg.ebx.b[1] = TextAttribute;
429 ireg.eax.w[0] = 0x0600; /* Clear screen region */
430 __intcall(0x10, &ireg, &oreg);
432 msg_gotoxy();
436 static void msg_novga(void)
438 syslinux_force_text_mode();
439 msg_initvars();
442 static void msg_viewimage(void)
444 FILE *f;
446 *VGAFilePtr = '\0'; /* Zero-terminate filename */
448 mangle_name(VGAFileMBuf, VGAFileBuf);
449 f = fopen(VGAFileMBuf, "r");
450 if (!f) {
451 /* Not there */
452 NextCharJump = msg_putchar;
453 return;
456 vgadisplayfile(f);
457 fclose(f);
458 msg_initvars();
462 * Getting VGA filename
464 static void msg_filename(char data)
466 /* <LF> = end of filename */
467 if (data == 0x0A) {
468 msg_viewimage();
469 return;
472 /* Ignore space/control char */
473 if (data > ' ') {
474 if ((char *)VGAFilePtr < (VGAFileBuf + sizeof(VGAFileBuf)))
475 *VGAFilePtr++ = data;
479 static void msg_vga(void)
481 NextCharJump = msg_filename;
482 VGAFilePtr = (uint16_t *)VGAFileBuf;
485 static void msg_line_wrap(void)
487 if (!(DisplayMask & UsingVGA))
488 return;
490 CursorCol = 0;
491 if ((CursorRow + 1) <= VidRows)
492 CursorRow++;
493 else {
494 com32sys_t ireg, oreg;
496 memset(&ireg, 0, sizeof(ireg));
498 ireg.ecx.w[0] = 0x0; /* Upper left hand corner */
499 ireg.edx.w[0] = ScreenSize;
501 CursorRow = ireg.edx.b[1]; /* New cursor at the bottom */
503 ireg.ebx.b[1] = ScrollAttribute;
504 ireg.eax.w[0] = 0x0601; /* Scroll up one line */
506 __intcall(0x10, &ireg, &oreg);
509 msg_gotoxy();
512 static void msg_normal(char data)
514 com32sys_t ireg, oreg;
516 /* Write to serial port */
517 write_serial_displaymask(data);
519 if (!(DisplayMask & UsingVGA))
520 return; /* Not screen */
522 if (!(DisplayCon & 0x01))
523 return;
525 memset(&ireg, 0, sizeof(ireg));
527 ireg.ebx.b[0] = TextAttribute;
528 ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
529 ireg.eax.b[0] = data;
530 ireg.eax.b[1] = 0x09; /* Write character/attribute */
531 ireg.ecx.w[0] = 1; /* One character only */
533 /* Write to screen */
534 __intcall(0x10, &ireg, &oreg);
536 if ((CursorCol + 1) <= VidCols) {
537 CursorCol++;
538 msg_gotoxy();
539 } else
540 msg_line_wrap(); /* Screen wraparound */
543 static void msg_modectl(char data)
545 data &= 0x07;
546 DisplayMask = data;
547 NextCharJump = msg_putchar;
550 static void msg_putchar(char ch)
552 /* 10h to 17h are mode controls */
553 if (ch >= 0x10 && ch < 0x18) {
554 msg_modectl(ch);
555 return;
558 switch (ch) {
559 case 0x0F: /* ^O = color code follows */
560 msg_ctrl_o();
561 break;
562 case 0x0D: /* Ignore <CR> */
563 break;
564 case 0x0A: /* <LF> = newline */
565 msg_newline();
566 break;
567 case 0x0C: /* <FF> = clear screen */
568 msg_formfeed();
569 break;
570 case 0x07: /* <BEL> = beep */
571 msg_beep();
572 break;
573 case 0x19: /* <EM> = return to text mode */
574 msg_novga();
575 break;
576 case 0x18: /* <CAN> = VGA filename follows */
577 msg_vga();
578 break;
579 default:
580 msg_normal(ch);
581 break;
586 * Subroutine to initialize variables, also needed after loading
587 * graphics file.
589 void msg_initvars(void)
591 com32sys_t ireg, oreg;
593 ireg.eax.b[1] = 0x3; /* Read cursor position */
594 ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
595 __intcall(0x10, &ireg, &oreg);
597 CursorDX = oreg.edx.w[0];
599 /* Initialize state machine */
600 NextCharJump = msg_putchar;