blob: 1fedabdb95ad3dfc8a17ebc4a2b097ac6d0c65c9 [file] [log] [blame]
Thomas Gleixner97873a32019-06-04 10:11:30 +02001// SPDX-License-Identifier: GPL-2.0-only
H. Peter Anvin15436102007-07-11 12:18:45 -07002/* -*- linux-c -*- ------------------------------------------------------- *
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright 2007 rPath, Inc. - All Rights Reserved
H. Peter Anvindf7699c52009-04-01 18:13:46 -07006 * Copyright 2009 Intel Corporation; author H. Peter Anvin
H. Peter Anvin15436102007-07-11 12:18:45 -07007 *
H. Peter Anvin15436102007-07-11 12:18:45 -07008 * ----------------------------------------------------------------------- */
9
10/*
Pekka Enbergfa97bdf2010-07-11 11:06:57 +030011 * Very simple screen and serial I/O
H. Peter Anvin15436102007-07-11 12:18:45 -070012 */
13
14#include "boot.h"
15
Yinghai Luf4ed2872010-08-02 02:17:31 -070016int early_serial_base;
Pekka Enbergfa97bdf2010-07-11 11:06:57 +030017
18#define XMTRDY 0x20
19
Pekka Enbergfa97bdf2010-07-11 11:06:57 +030020#define TXR 0 /* Transmit register (WRITE) */
Pekka Enbergfa97bdf2010-07-11 11:06:57 +030021#define LSR 5 /* Line Status */
Pekka Enbergfa97bdf2010-07-11 11:06:57 +030022
H. Peter Anvin15436102007-07-11 12:18:45 -070023/*
24 * These functions are in .inittext so they can be used to signal
25 * error during initialization.
26 */
27
Pekka Enbergfa97bdf2010-07-11 11:06:57 +030028static void __attribute__((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 __attribute__((section(".inittext"))) bios_putchar(int ch)
H. Peter Anvin15436102007-07-11 12:18:45 -070039{
H. Peter Anvindf7699c52009-04-01 18:13:46 -070040 struct biosregs ireg;
H. Peter Anvin15436102007-07-11 12:18:45 -070041
H. Peter Anvindf7699c52009-04-01 18:13:46 -070042 initregs(&ireg);
43 ireg.bx = 0x0007;
44 ireg.cx = 0x0001;
45 ireg.ah = 0x0e;
46 ireg.al = ch;
47 intcall(0x10, &ireg, NULL);
H. Peter Anvin15436102007-07-11 12:18:45 -070048}
49
Pekka Enbergfa97bdf2010-07-11 11:06:57 +030050void __attribute__((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
H. Peter Anvin15436102007-07-11 12:18:45 -070061void __attribute__((section(".inittext"))) puts(const char *str)
62{
H. Peter Anvindf7699c52009-04-01 18:13:46 -070063 while (*str)
H. Peter Anvin15436102007-07-11 12:18:45 -070064 putchar(*str++);
H. Peter Anvin15436102007-07-11 12:18:45 -070065}
66
67/*
68 * Read the CMOS clock through the BIOS, and return the
69 * seconds in BCD.
70 */
71
72static u8 gettime(void)
73{
H. Peter Anvindf7699c52009-04-01 18:13:46 -070074 struct biosregs ireg, oreg;
H. Peter Anvin15436102007-07-11 12:18:45 -070075
H. Peter Anvindf7699c52009-04-01 18:13:46 -070076 initregs(&ireg);
77 ireg.ah = 0x02;
78 intcall(0x1a, &ireg, &oreg);
H. Peter Anvin15436102007-07-11 12:18:45 -070079
H. Peter Anvindf7699c52009-04-01 18:13:46 -070080 return oreg.dh;
H. Peter Anvin15436102007-07-11 12:18:45 -070081}
82
83/*
84 * Read from the keyboard
85 */
86int getchar(void)
87{
H. Peter Anvindf7699c52009-04-01 18:13:46 -070088 struct biosregs ireg, oreg;
H. Peter Anvin15436102007-07-11 12:18:45 -070089
H. Peter Anvindf7699c52009-04-01 18:13:46 -070090 initregs(&ireg);
91 /* ireg.ah = 0x00; */
92 intcall(0x16, &ireg, &oreg);
93
94 return oreg.al;
H. Peter Anvin15436102007-07-11 12:18:45 -070095}
96
97static int kbd_pending(void)
98{
H. Peter Anvindf7699c52009-04-01 18:13:46 -070099 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);
H. Peter Anvin15436102007-07-11 12:18:45 -0700106}
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}
Pekka Enbergfa97bdf2010-07-11 11:06:57 +0300137