xref: /openbmc/linux/arch/x86/boot/tty.c (revision f4ed2877)
196ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
296ae6ea0SThomas Gleixner  *
396ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
496ae6ea0SThomas Gleixner  *   Copyright 2007 rPath, Inc. - All Rights Reserved
5df7699c5SH. Peter Anvin  *   Copyright 2009 Intel Corporation; author H. Peter Anvin
696ae6ea0SThomas Gleixner  *
796ae6ea0SThomas Gleixner  *   This file is part of the Linux kernel, and is made available under
896ae6ea0SThomas Gleixner  *   the terms of the GNU General Public License version 2.
996ae6ea0SThomas Gleixner  *
1096ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
1196ae6ea0SThomas Gleixner 
1296ae6ea0SThomas Gleixner /*
13fa97bdf9SPekka Enberg  * Very simple screen and serial I/O
1496ae6ea0SThomas Gleixner  */
1596ae6ea0SThomas Gleixner 
1696ae6ea0SThomas Gleixner #include "boot.h"
1796ae6ea0SThomas Gleixner 
18f4ed2877SYinghai Lu int early_serial_base;
19fa97bdf9SPekka Enberg 
20fa97bdf9SPekka Enberg #define XMTRDY          0x20
21fa97bdf9SPekka Enberg 
22fa97bdf9SPekka Enberg #define TXR             0       /*  Transmit register (WRITE) */
23fa97bdf9SPekka Enberg #define LSR             5       /*  Line Status               */
24fa97bdf9SPekka Enberg 
2596ae6ea0SThomas Gleixner /*
2696ae6ea0SThomas Gleixner  * These functions are in .inittext so they can be used to signal
2796ae6ea0SThomas Gleixner  * error during initialization.
2896ae6ea0SThomas Gleixner  */
2996ae6ea0SThomas Gleixner 
30fa97bdf9SPekka Enberg static void __attribute__((section(".inittext"))) serial_putchar(int ch)
31fa97bdf9SPekka Enberg {
32fa97bdf9SPekka Enberg 	unsigned timeout = 0xffff;
33fa97bdf9SPekka Enberg 
34fa97bdf9SPekka Enberg 	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
35fa97bdf9SPekka Enberg 		cpu_relax();
36fa97bdf9SPekka Enberg 
37fa97bdf9SPekka Enberg 	outb(ch, early_serial_base + TXR);
38fa97bdf9SPekka Enberg }
39fa97bdf9SPekka Enberg 
40fa97bdf9SPekka Enberg static void __attribute__((section(".inittext"))) bios_putchar(int ch)
4196ae6ea0SThomas Gleixner {
42df7699c5SH. Peter Anvin 	struct biosregs ireg;
4396ae6ea0SThomas Gleixner 
44df7699c5SH. Peter Anvin 	initregs(&ireg);
45df7699c5SH. Peter Anvin 	ireg.bx = 0x0007;
46df7699c5SH. Peter Anvin 	ireg.cx = 0x0001;
47df7699c5SH. Peter Anvin 	ireg.ah = 0x0e;
48df7699c5SH. Peter Anvin 	ireg.al = ch;
49df7699c5SH. Peter Anvin 	intcall(0x10, &ireg, NULL);
5096ae6ea0SThomas Gleixner }
5196ae6ea0SThomas Gleixner 
52fa97bdf9SPekka Enberg void __attribute__((section(".inittext"))) putchar(int ch)
53fa97bdf9SPekka Enberg {
54fa97bdf9SPekka Enberg 	if (ch == '\n')
55fa97bdf9SPekka Enberg 		putchar('\r');	/* \n -> \r\n */
56fa97bdf9SPekka Enberg 
57fa97bdf9SPekka Enberg 	bios_putchar(ch);
58fa97bdf9SPekka Enberg 
59fa97bdf9SPekka Enberg 	if (early_serial_base != 0)
60fa97bdf9SPekka Enberg 		serial_putchar(ch);
61fa97bdf9SPekka Enberg }
62fa97bdf9SPekka Enberg 
6396ae6ea0SThomas Gleixner void __attribute__((section(".inittext"))) puts(const char *str)
6496ae6ea0SThomas Gleixner {
65df7699c5SH. Peter Anvin 	while (*str)
6696ae6ea0SThomas Gleixner 		putchar(*str++);
6796ae6ea0SThomas Gleixner }
6896ae6ea0SThomas Gleixner 
6996ae6ea0SThomas Gleixner /*
7096ae6ea0SThomas Gleixner  * Read the CMOS clock through the BIOS, and return the
7196ae6ea0SThomas Gleixner  * seconds in BCD.
7296ae6ea0SThomas Gleixner  */
7396ae6ea0SThomas Gleixner 
7496ae6ea0SThomas Gleixner static u8 gettime(void)
7596ae6ea0SThomas Gleixner {
76df7699c5SH. Peter Anvin 	struct biosregs ireg, oreg;
7796ae6ea0SThomas Gleixner 
78df7699c5SH. Peter Anvin 	initregs(&ireg);
79df7699c5SH. Peter Anvin 	ireg.ah = 0x02;
80df7699c5SH. Peter Anvin 	intcall(0x1a, &ireg, &oreg);
8196ae6ea0SThomas Gleixner 
82df7699c5SH. Peter Anvin 	return oreg.dh;
8396ae6ea0SThomas Gleixner }
8496ae6ea0SThomas Gleixner 
8596ae6ea0SThomas Gleixner /*
8696ae6ea0SThomas Gleixner  * Read from the keyboard
8796ae6ea0SThomas Gleixner  */
8896ae6ea0SThomas Gleixner int getchar(void)
8996ae6ea0SThomas Gleixner {
90df7699c5SH. Peter Anvin 	struct biosregs ireg, oreg;
9196ae6ea0SThomas Gleixner 
92df7699c5SH. Peter Anvin 	initregs(&ireg);
93df7699c5SH. Peter Anvin 	/* ireg.ah = 0x00; */
94df7699c5SH. Peter Anvin 	intcall(0x16, &ireg, &oreg);
95df7699c5SH. Peter Anvin 
96df7699c5SH. Peter Anvin 	return oreg.al;
9796ae6ea0SThomas Gleixner }
9896ae6ea0SThomas Gleixner 
9996ae6ea0SThomas Gleixner static int kbd_pending(void)
10096ae6ea0SThomas Gleixner {
101df7699c5SH. Peter Anvin 	struct biosregs ireg, oreg;
102df7699c5SH. Peter Anvin 
103df7699c5SH. Peter Anvin 	initregs(&ireg);
104df7699c5SH. Peter Anvin 	ireg.ah = 0x01;
105df7699c5SH. Peter Anvin 	intcall(0x16, &ireg, &oreg);
106df7699c5SH. Peter Anvin 
107df7699c5SH. Peter Anvin 	return !(oreg.eflags & X86_EFLAGS_ZF);
10896ae6ea0SThomas Gleixner }
10996ae6ea0SThomas Gleixner 
11096ae6ea0SThomas Gleixner void kbd_flush(void)
11196ae6ea0SThomas Gleixner {
11296ae6ea0SThomas Gleixner 	for (;;) {
11396ae6ea0SThomas Gleixner 		if (!kbd_pending())
11496ae6ea0SThomas Gleixner 			break;
11596ae6ea0SThomas Gleixner 		getchar();
11696ae6ea0SThomas Gleixner 	}
11796ae6ea0SThomas Gleixner }
11896ae6ea0SThomas Gleixner 
11996ae6ea0SThomas Gleixner int getchar_timeout(void)
12096ae6ea0SThomas Gleixner {
12196ae6ea0SThomas Gleixner 	int cnt = 30;
12296ae6ea0SThomas Gleixner 	int t0, t1;
12396ae6ea0SThomas Gleixner 
12496ae6ea0SThomas Gleixner 	t0 = gettime();
12596ae6ea0SThomas Gleixner 
12696ae6ea0SThomas Gleixner 	while (cnt) {
12796ae6ea0SThomas Gleixner 		if (kbd_pending())
12896ae6ea0SThomas Gleixner 			return getchar();
12996ae6ea0SThomas Gleixner 
13096ae6ea0SThomas Gleixner 		t1 = gettime();
13196ae6ea0SThomas Gleixner 		if (t0 != t1) {
13296ae6ea0SThomas Gleixner 			cnt--;
13396ae6ea0SThomas Gleixner 			t0 = t1;
13496ae6ea0SThomas Gleixner 		}
13596ae6ea0SThomas Gleixner 	}
13696ae6ea0SThomas Gleixner 
13796ae6ea0SThomas Gleixner 	return 0;		/* Timeout! */
13896ae6ea0SThomas Gleixner }
139fa97bdf9SPekka Enberg 
140