xref: /openbmc/linux/arch/x86/boot/tty.c (revision f7af616c)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* -*- linux-c -*- ------------------------------------------------------- *
3  *
4  *   Copyright (C) 1991, 1992 Linus Torvalds
5  *   Copyright 2007 rPath, Inc. - All Rights Reserved
6  *   Copyright 2009 Intel Corporation; author H. Peter Anvin
7  *
8  * ----------------------------------------------------------------------- */
9 
10 /*
11  * Very simple screen and serial I/O
12  */
13 
14 #include "boot.h"
15 
16 int early_serial_base;
17 
18 #define XMTRDY          0x20
19 
20 #define TXR             0       /*  Transmit register (WRITE) */
21 #define LSR             5       /*  Line Status               */
22 
23 /*
24  * These functions are in .inittext so they can be used to signal
25  * error during initialization.
26  */
27 
28 static void __section(".inittext") serial_putchar(int ch)
29 {
30 	unsigned timeout = 0xffff;
31 
32 	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
33 		cpu_relax();
34 
35 	outb(ch, early_serial_base + TXR);
36 }
37 
38 static void __section(".inittext") bios_putchar(int ch)
39 {
40 	struct biosregs ireg;
41 
42 	initregs(&ireg);
43 	ireg.bx = 0x0007;
44 	ireg.cx = 0x0001;
45 	ireg.ah = 0x0e;
46 	ireg.al = ch;
47 	intcall(0x10, &ireg, NULL);
48 }
49 
50 void __section(".inittext") putchar(int ch)
51 {
52 	if (ch == '\n')
53 		putchar('\r');	/* \n -> \r\n */
54 
55 	bios_putchar(ch);
56 
57 	if (early_serial_base != 0)
58 		serial_putchar(ch);
59 }
60 
61 void __section(".inittext") puts(const char *str)
62 {
63 	while (*str)
64 		putchar(*str++);
65 }
66 
67 /*
68  * Read the CMOS clock through the BIOS, and return the
69  * seconds in BCD.
70  */
71 
72 static u8 gettime(void)
73 {
74 	struct biosregs ireg, oreg;
75 
76 	initregs(&ireg);
77 	ireg.ah = 0x02;
78 	intcall(0x1a, &ireg, &oreg);
79 
80 	return oreg.dh;
81 }
82 
83 /*
84  * Read from the keyboard
85  */
86 int getchar(void)
87 {
88 	struct biosregs ireg, oreg;
89 
90 	initregs(&ireg);
91 	/* ireg.ah = 0x00; */
92 	intcall(0x16, &ireg, &oreg);
93 
94 	return oreg.al;
95 }
96 
97 static int kbd_pending(void)
98 {
99 	struct biosregs ireg, oreg;
100 
101 	initregs(&ireg);
102 	ireg.ah = 0x01;
103 	intcall(0x16, &ireg, &oreg);
104 
105 	return !(oreg.eflags & X86_EFLAGS_ZF);
106 }
107 
108 void kbd_flush(void)
109 {
110 	for (;;) {
111 		if (!kbd_pending())
112 			break;
113 		getchar();
114 	}
115 }
116 
117 int getchar_timeout(void)
118 {
119 	int cnt = 30;
120 	int t0, t1;
121 
122 	t0 = gettime();
123 
124 	while (cnt) {
125 		if (kbd_pending())
126 			return getchar();
127 
128 		t1 = gettime();
129 		if (t0 != t1) {
130 			cnt--;
131 			t0 = t1;
132 		}
133 	}
134 
135 	return 0;		/* Timeout! */
136 }
137 
138