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