xref: /openbmc/linux/arch/x86/boot/tty.c (revision 97873a3d)
197873a3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
296ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
396ae6ea0SThomas Gleixner  *
496ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
596ae6ea0SThomas Gleixner  *   Copyright 2007 rPath, Inc. - All Rights Reserved
6df7699c5SH. Peter Anvin  *   Copyright 2009 Intel Corporation; author H. Peter Anvin
796ae6ea0SThomas Gleixner  *
896ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
996ae6ea0SThomas Gleixner 
1096ae6ea0SThomas Gleixner /*
11fa97bdf9SPekka Enberg  * Very simple screen and serial I/O
1296ae6ea0SThomas Gleixner  */
1396ae6ea0SThomas Gleixner 
1496ae6ea0SThomas Gleixner #include "boot.h"
1596ae6ea0SThomas Gleixner 
16f4ed2877SYinghai Lu int early_serial_base;
17fa97bdf9SPekka Enberg 
18fa97bdf9SPekka Enberg #define XMTRDY          0x20
19fa97bdf9SPekka Enberg 
20fa97bdf9SPekka Enberg #define TXR             0       /*  Transmit register (WRITE) */
21fa97bdf9SPekka Enberg #define LSR             5       /*  Line Status               */
22fa97bdf9SPekka Enberg 
2396ae6ea0SThomas Gleixner /*
2496ae6ea0SThomas Gleixner  * These functions are in .inittext so they can be used to signal
2596ae6ea0SThomas Gleixner  * error during initialization.
2696ae6ea0SThomas Gleixner  */
2796ae6ea0SThomas Gleixner 
28fa97bdf9SPekka Enberg static void __attribute__((section(".inittext"))) serial_putchar(int ch)
29fa97bdf9SPekka Enberg {
30fa97bdf9SPekka Enberg 	unsigned timeout = 0xffff;
31fa97bdf9SPekka Enberg 
32fa97bdf9SPekka Enberg 	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
33fa97bdf9SPekka Enberg 		cpu_relax();
34fa97bdf9SPekka Enberg 
35fa97bdf9SPekka Enberg 	outb(ch, early_serial_base + TXR);
36fa97bdf9SPekka Enberg }
37fa97bdf9SPekka Enberg 
38fa97bdf9SPekka Enberg static void __attribute__((section(".inittext"))) bios_putchar(int ch)
3996ae6ea0SThomas Gleixner {
40df7699c5SH. Peter Anvin 	struct biosregs ireg;
4196ae6ea0SThomas Gleixner 
42df7699c5SH. Peter Anvin 	initregs(&ireg);
43df7699c5SH. Peter Anvin 	ireg.bx = 0x0007;
44df7699c5SH. Peter Anvin 	ireg.cx = 0x0001;
45df7699c5SH. Peter Anvin 	ireg.ah = 0x0e;
46df7699c5SH. Peter Anvin 	ireg.al = ch;
47df7699c5SH. Peter Anvin 	intcall(0x10, &ireg, NULL);
4896ae6ea0SThomas Gleixner }
4996ae6ea0SThomas Gleixner 
50fa97bdf9SPekka Enberg void __attribute__((section(".inittext"))) putchar(int ch)
51fa97bdf9SPekka Enberg {
52fa97bdf9SPekka Enberg 	if (ch == '\n')
53fa97bdf9SPekka Enberg 		putchar('\r');	/* \n -> \r\n */
54fa97bdf9SPekka Enberg 
55fa97bdf9SPekka Enberg 	bios_putchar(ch);
56fa97bdf9SPekka Enberg 
57fa97bdf9SPekka Enberg 	if (early_serial_base != 0)
58fa97bdf9SPekka Enberg 		serial_putchar(ch);
59fa97bdf9SPekka Enberg }
60fa97bdf9SPekka Enberg 
6196ae6ea0SThomas Gleixner void __attribute__((section(".inittext"))) puts(const char *str)
6296ae6ea0SThomas Gleixner {
63df7699c5SH. Peter Anvin 	while (*str)
6496ae6ea0SThomas Gleixner 		putchar(*str++);
6596ae6ea0SThomas Gleixner }
6696ae6ea0SThomas Gleixner 
6796ae6ea0SThomas Gleixner /*
6896ae6ea0SThomas Gleixner  * Read the CMOS clock through the BIOS, and return the
6996ae6ea0SThomas Gleixner  * seconds in BCD.
7096ae6ea0SThomas Gleixner  */
7196ae6ea0SThomas Gleixner 
7296ae6ea0SThomas Gleixner static u8 gettime(void)
7396ae6ea0SThomas Gleixner {
74df7699c5SH. Peter Anvin 	struct biosregs ireg, oreg;
7596ae6ea0SThomas Gleixner 
76df7699c5SH. Peter Anvin 	initregs(&ireg);
77df7699c5SH. Peter Anvin 	ireg.ah = 0x02;
78df7699c5SH. Peter Anvin 	intcall(0x1a, &ireg, &oreg);
7996ae6ea0SThomas Gleixner 
80df7699c5SH. Peter Anvin 	return oreg.dh;
8196ae6ea0SThomas Gleixner }
8296ae6ea0SThomas Gleixner 
8396ae6ea0SThomas Gleixner /*
8496ae6ea0SThomas Gleixner  * Read from the keyboard
8596ae6ea0SThomas Gleixner  */
8696ae6ea0SThomas Gleixner int getchar(void)
8796ae6ea0SThomas Gleixner {
88df7699c5SH. Peter Anvin 	struct biosregs ireg, oreg;
8996ae6ea0SThomas Gleixner 
90df7699c5SH. Peter Anvin 	initregs(&ireg);
91df7699c5SH. Peter Anvin 	/* ireg.ah = 0x00; */
92df7699c5SH. Peter Anvin 	intcall(0x16, &ireg, &oreg);
93df7699c5SH. Peter Anvin 
94df7699c5SH. Peter Anvin 	return oreg.al;
9596ae6ea0SThomas Gleixner }
9696ae6ea0SThomas Gleixner 
9796ae6ea0SThomas Gleixner static int kbd_pending(void)
9896ae6ea0SThomas Gleixner {
99df7699c5SH. Peter Anvin 	struct biosregs ireg, oreg;
100df7699c5SH. Peter Anvin 
101df7699c5SH. Peter Anvin 	initregs(&ireg);
102df7699c5SH. Peter Anvin 	ireg.ah = 0x01;
103df7699c5SH. Peter Anvin 	intcall(0x16, &ireg, &oreg);
104df7699c5SH. Peter Anvin 
105df7699c5SH. Peter Anvin 	return !(oreg.eflags & X86_EFLAGS_ZF);
10696ae6ea0SThomas Gleixner }
10796ae6ea0SThomas Gleixner 
10896ae6ea0SThomas Gleixner void kbd_flush(void)
10996ae6ea0SThomas Gleixner {
11096ae6ea0SThomas Gleixner 	for (;;) {
11196ae6ea0SThomas Gleixner 		if (!kbd_pending())
11296ae6ea0SThomas Gleixner 			break;
11396ae6ea0SThomas Gleixner 		getchar();
11496ae6ea0SThomas Gleixner 	}
11596ae6ea0SThomas Gleixner }
11696ae6ea0SThomas Gleixner 
11796ae6ea0SThomas Gleixner int getchar_timeout(void)
11896ae6ea0SThomas Gleixner {
11996ae6ea0SThomas Gleixner 	int cnt = 30;
12096ae6ea0SThomas Gleixner 	int t0, t1;
12196ae6ea0SThomas Gleixner 
12296ae6ea0SThomas Gleixner 	t0 = gettime();
12396ae6ea0SThomas Gleixner 
12496ae6ea0SThomas Gleixner 	while (cnt) {
12596ae6ea0SThomas Gleixner 		if (kbd_pending())
12696ae6ea0SThomas Gleixner 			return getchar();
12796ae6ea0SThomas Gleixner 
12896ae6ea0SThomas Gleixner 		t1 = gettime();
12996ae6ea0SThomas Gleixner 		if (t0 != t1) {
13096ae6ea0SThomas Gleixner 			cnt--;
13196ae6ea0SThomas Gleixner 			t0 = t1;
13296ae6ea0SThomas Gleixner 		}
13396ae6ea0SThomas Gleixner 	}
13496ae6ea0SThomas Gleixner 
13596ae6ea0SThomas Gleixner 	return 0;		/* Timeout! */
13696ae6ea0SThomas Gleixner }
137fa97bdf9SPekka Enberg 
138