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 * -----------------------------------------------------------------------
18 * Console I/O code, except:
19 * writechr, writestr_early - module-dependent
20 * writestr, crlf - writestr.inc
21 * writehex* - writehex.inc
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
)
67 f
= fopen(filename
, "r");
71 fread(KbdMap
, 1, sizeof(KbdMap
), f
);
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
)
89 f
= fopen(filename
, "r");
93 TextAttribute
= 0x7; /* Default grey on white */
94 DisplayMask
= 0x7; /* Display text in all modes */
98 * Read the text file a byte at a time and interpret that
101 while ((ch
= getc(f
)) != EOF
) {
108 * 02h = graphics mode
113 NextCharJump(ch
); /* Do what shall be done */
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
133 void write_serial(char data
)
141 ch
= inb(SerialPort
+ 5); /* LSR */
143 /* Wait for space in transmit register */
147 /* Wait for input flow control */
148 ch
= inb(SerialPort
+ 6);
156 outb(data
, SerialPort
); /* Send data */
160 void pm_write_serial(com32sys_t
*regs
)
162 write_serial(regs
->eax
.b
[0]);
165 void pm_serialcfg(com32sys_t
*regs
)
169 regs
->eax
.w
[0] = SerialPort
;
170 regs
->ecx
.w
[0] = BaudDivisor
;
182 regs
->ebx
.w
[0] = al
| (ah
<< 8);
185 static void write_serial_displaymask(char data
)
187 if (DisplayMask
& 0x4)
192 * write_serial_str: write_serial for strings
194 void write_serial_str(char *data
)
198 while ((ch
= *data
++))
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.
218 com32sys_t ireg
, oreg
;
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
))
232 /* Already-queued input? */
233 if (SerialTail
== SerialHead
) {
235 data
= inb(SerialPort
+ 5) & 1;
238 data
= inb(SerialPort
+ 6);
240 /* Required status bits */
243 if (data
!= FlowIgnore
)
256 void pm_pollchar(com32sys_t
*regs
)
259 regs
->eflags
.l
&= ~EFLAGS_ZF
;
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
;
274 memset(&ireg
, 0, sizeof(ireg
));
275 memset(&oreg
, 0, sizeof(oreg
));
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
) {
287 if (SerialTail
!= SerialHead
) {
289 sti(); /* We already know we'll consume data */
290 data
= *SerialTail
++;
292 SerialTail
= (char *)((unsigned long)SerialTail
& (serial_buf_size
- 1));
295 data
= inb(SerialPort
+ 5) & 1;
300 data
= inb(SerialPort
+ 6);
302 if (data
!= FlowIgnore
) {
307 data
= inb(SerialPort
);
312 /* Keyboard input? */
313 ireg
.eax
.b
[1] = 0x10; /* Get keyboard input */
314 __intcall(0x16, &ireg
, &oreg
);
316 data
= oreg
.eax
.b
[0];
323 /* Convert character sets */
331 reset_idle(); /* Character received */
335 void pm_getchar(com32sys_t
*regs
)
337 regs
->eax
.b
[0] = getchar((char *)®s
->eax
.b
[1]);
340 static void msg_setbg(char data
)
342 if (unhexchar(&data
) == 0) {
344 if (DisplayMask
& UsingVGA
)
345 TextAttribute
= data
;
347 NextCharJump
= msg_setfg
;
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
;
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
))
396 if ((CursorRow
+ 1) <= VidRows
)
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
);
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
);
436 static void msg_novga(void)
438 syslinux_force_text_mode();
442 static void msg_viewimage(void)
446 *VGAFilePtr
= '\0'; /* Zero-terminate filename */
448 mangle_name(VGAFileMBuf
, VGAFileBuf
);
449 f
= fopen(VGAFileMBuf
, "r");
452 NextCharJump
= msg_putchar
;
462 * Getting VGA filename
464 static void msg_filename(char data
)
466 /* <LF> = end of filename */
472 /* Ignore space/control char */
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
))
491 if ((CursorRow
+ 1) <= VidRows
)
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
);
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))
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
) {
540 msg_line_wrap(); /* Screen wraparound */
543 static void msg_modectl(char 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) {
559 case 0x0F: /* ^O = color code follows */
562 case 0x0D: /* Ignore <CR> */
564 case 0x0A: /* <LF> = newline */
567 case 0x0C: /* <FF> = clear screen */
570 case 0x07: /* <BEL> = beep */
573 case 0x19: /* <EM> = return to text mode */
576 case 0x18: /* <CAN> = VGA filename follows */
586 * Subroutine to initialize variables, also needed after loading
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
;