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
16int 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
28static 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
38static 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
50void __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
61void __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
72static 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 */
86int 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
97static 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
108void kbd_flush(void)
109{
110	for (;;) {
111		if (!kbd_pending())
112			break;
113		getchar();
114	}
115}
116
117int 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