xref: /openbmc/linux/arch/x86/boot/tty.c (revision df7699c5)
196ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
296ae6ea0SThomas Gleixner  *
396ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
496ae6ea0SThomas Gleixner  *   Copyright 2007 rPath, Inc. - All Rights Reserved
5df7699c5SH. Peter Anvin  *   Copyright 2009 Intel Corporation; author H. Peter Anvin
696ae6ea0SThomas Gleixner  *
796ae6ea0SThomas Gleixner  *   This file is part of the Linux kernel, and is made available under
896ae6ea0SThomas Gleixner  *   the terms of the GNU General Public License version 2.
996ae6ea0SThomas Gleixner  *
1096ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
1196ae6ea0SThomas Gleixner 
1296ae6ea0SThomas Gleixner /*
1396ae6ea0SThomas Gleixner  * Very simple screen I/O
1496ae6ea0SThomas Gleixner  * XXX: Probably should add very simple serial I/O?
1596ae6ea0SThomas Gleixner  */
1696ae6ea0SThomas Gleixner 
1796ae6ea0SThomas Gleixner #include "boot.h"
1896ae6ea0SThomas Gleixner 
1996ae6ea0SThomas Gleixner /*
2096ae6ea0SThomas Gleixner  * These functions are in .inittext so they can be used to signal
2196ae6ea0SThomas Gleixner  * error during initialization.
2296ae6ea0SThomas Gleixner  */
2396ae6ea0SThomas Gleixner 
2496ae6ea0SThomas Gleixner void __attribute__((section(".inittext"))) putchar(int ch)
2596ae6ea0SThomas Gleixner {
26df7699c5SH. Peter Anvin 	struct biosregs ireg;
2796ae6ea0SThomas Gleixner 
28df7699c5SH. Peter Anvin 	if (ch == '\n')
2996ae6ea0SThomas Gleixner 		putchar('\r');	/* \n -> \r\n */
3096ae6ea0SThomas Gleixner 
31df7699c5SH. Peter Anvin 	initregs(&ireg);
32df7699c5SH. Peter Anvin 	ireg.bx = 0x0007;
33df7699c5SH. Peter Anvin 	ireg.cx = 0x0001;
34df7699c5SH. Peter Anvin 	ireg.ah = 0x0e;
35df7699c5SH. Peter Anvin 	ireg.al = ch;
36df7699c5SH. Peter Anvin 	intcall(0x10, &ireg, NULL);
3796ae6ea0SThomas Gleixner }
3896ae6ea0SThomas Gleixner 
3996ae6ea0SThomas Gleixner void __attribute__((section(".inittext"))) puts(const char *str)
4096ae6ea0SThomas Gleixner {
41df7699c5SH. Peter Anvin 	while (*str)
4296ae6ea0SThomas Gleixner 		putchar(*str++);
4396ae6ea0SThomas Gleixner }
4496ae6ea0SThomas Gleixner 
4596ae6ea0SThomas Gleixner /*
4696ae6ea0SThomas Gleixner  * Read the CMOS clock through the BIOS, and return the
4796ae6ea0SThomas Gleixner  * seconds in BCD.
4896ae6ea0SThomas Gleixner  */
4996ae6ea0SThomas Gleixner 
5096ae6ea0SThomas Gleixner static u8 gettime(void)
5196ae6ea0SThomas Gleixner {
52df7699c5SH. Peter Anvin 	struct biosregs ireg, oreg;
5396ae6ea0SThomas Gleixner 
54df7699c5SH. Peter Anvin 	initregs(&ireg);
55df7699c5SH. Peter Anvin 	ireg.ah = 0x02;
56df7699c5SH. Peter Anvin 	intcall(0x1a, &ireg, &oreg);
5796ae6ea0SThomas Gleixner 
58df7699c5SH. Peter Anvin 	return oreg.dh;
5996ae6ea0SThomas Gleixner }
6096ae6ea0SThomas Gleixner 
6196ae6ea0SThomas Gleixner /*
6296ae6ea0SThomas Gleixner  * Read from the keyboard
6396ae6ea0SThomas Gleixner  */
6496ae6ea0SThomas Gleixner int getchar(void)
6596ae6ea0SThomas Gleixner {
66df7699c5SH. Peter Anvin 	struct biosregs ireg, oreg;
6796ae6ea0SThomas Gleixner 
68df7699c5SH. Peter Anvin 	initregs(&ireg);
69df7699c5SH. Peter Anvin 	/* ireg.ah = 0x00; */
70df7699c5SH. Peter Anvin 	intcall(0x16, &ireg, &oreg);
71df7699c5SH. Peter Anvin 
72df7699c5SH. Peter Anvin 	return oreg.al;
7396ae6ea0SThomas Gleixner }
7496ae6ea0SThomas Gleixner 
7596ae6ea0SThomas Gleixner static int kbd_pending(void)
7696ae6ea0SThomas Gleixner {
77df7699c5SH. Peter Anvin 	struct biosregs ireg, oreg;
78df7699c5SH. Peter Anvin 
79df7699c5SH. Peter Anvin 	initregs(&ireg);
80df7699c5SH. Peter Anvin 	ireg.ah = 0x01;
81df7699c5SH. Peter Anvin 	intcall(0x16, &ireg, &oreg);
82df7699c5SH. Peter Anvin 
83df7699c5SH. Peter Anvin 	return !(oreg.eflags & X86_EFLAGS_ZF);
8496ae6ea0SThomas Gleixner }
8596ae6ea0SThomas Gleixner 
8696ae6ea0SThomas Gleixner void kbd_flush(void)
8796ae6ea0SThomas Gleixner {
8896ae6ea0SThomas Gleixner 	for (;;) {
8996ae6ea0SThomas Gleixner 		if (!kbd_pending())
9096ae6ea0SThomas Gleixner 			break;
9196ae6ea0SThomas Gleixner 		getchar();
9296ae6ea0SThomas Gleixner 	}
9396ae6ea0SThomas Gleixner }
9496ae6ea0SThomas Gleixner 
9596ae6ea0SThomas Gleixner int getchar_timeout(void)
9696ae6ea0SThomas Gleixner {
9796ae6ea0SThomas Gleixner 	int cnt = 30;
9896ae6ea0SThomas Gleixner 	int t0, t1;
9996ae6ea0SThomas Gleixner 
10096ae6ea0SThomas Gleixner 	t0 = gettime();
10196ae6ea0SThomas Gleixner 
10296ae6ea0SThomas Gleixner 	while (cnt) {
10396ae6ea0SThomas Gleixner 		if (kbd_pending())
10496ae6ea0SThomas Gleixner 			return getchar();
10596ae6ea0SThomas Gleixner 
10696ae6ea0SThomas Gleixner 		t1 = gettime();
10796ae6ea0SThomas Gleixner 		if (t0 != t1) {
10896ae6ea0SThomas Gleixner 			cnt--;
10996ae6ea0SThomas Gleixner 			t0 = t1;
11096ae6ea0SThomas Gleixner 		}
11196ae6ea0SThomas Gleixner 	}
11296ae6ea0SThomas Gleixner 
11396ae6ea0SThomas Gleixner 	return 0;		/* Timeout! */
11496ae6ea0SThomas Gleixner }
115