xref: /openbmc/linux/arch/x86/boot/tty.c (revision 96ae6ea0)
196ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
296ae6ea0SThomas Gleixner  *
396ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
496ae6ea0SThomas Gleixner  *   Copyright 2007 rPath, Inc. - All Rights Reserved
596ae6ea0SThomas Gleixner  *
696ae6ea0SThomas Gleixner  *   This file is part of the Linux kernel, and is made available under
796ae6ea0SThomas Gleixner  *   the terms of the GNU General Public License version 2.
896ae6ea0SThomas Gleixner  *
996ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
1096ae6ea0SThomas Gleixner 
1196ae6ea0SThomas Gleixner /*
1296ae6ea0SThomas Gleixner  * arch/i386/boot/tty.c
1396ae6ea0SThomas Gleixner  *
1496ae6ea0SThomas Gleixner  * Very simple screen I/O
1596ae6ea0SThomas Gleixner  * XXX: Probably should add very simple serial I/O?
1696ae6ea0SThomas Gleixner  */
1796ae6ea0SThomas Gleixner 
1896ae6ea0SThomas Gleixner #include "boot.h"
1996ae6ea0SThomas Gleixner 
2096ae6ea0SThomas Gleixner /*
2196ae6ea0SThomas Gleixner  * These functions are in .inittext so they can be used to signal
2296ae6ea0SThomas Gleixner  * error during initialization.
2396ae6ea0SThomas Gleixner  */
2496ae6ea0SThomas Gleixner 
2596ae6ea0SThomas Gleixner void __attribute__((section(".inittext"))) putchar(int ch)
2696ae6ea0SThomas Gleixner {
2796ae6ea0SThomas Gleixner 	unsigned char c = ch;
2896ae6ea0SThomas Gleixner 
2996ae6ea0SThomas Gleixner 	if (c == '\n')
3096ae6ea0SThomas Gleixner 		putchar('\r');	/* \n -> \r\n */
3196ae6ea0SThomas Gleixner 
3296ae6ea0SThomas Gleixner 	/* int $0x10 is known to have bugs involving touching registers
3396ae6ea0SThomas Gleixner 	   it shouldn't.  Be extra conservative... */
3496ae6ea0SThomas Gleixner 	asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
3596ae6ea0SThomas Gleixner 		     : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
3696ae6ea0SThomas Gleixner }
3796ae6ea0SThomas Gleixner 
3896ae6ea0SThomas Gleixner void __attribute__((section(".inittext"))) puts(const char *str)
3996ae6ea0SThomas Gleixner {
4096ae6ea0SThomas Gleixner 	int n = 0;
4196ae6ea0SThomas Gleixner 	while (*str) {
4296ae6ea0SThomas Gleixner 		putchar(*str++);
4396ae6ea0SThomas Gleixner 		n++;
4496ae6ea0SThomas Gleixner 	}
4596ae6ea0SThomas Gleixner }
4696ae6ea0SThomas Gleixner 
4796ae6ea0SThomas Gleixner /*
4896ae6ea0SThomas Gleixner  * Read the CMOS clock through the BIOS, and return the
4996ae6ea0SThomas Gleixner  * seconds in BCD.
5096ae6ea0SThomas Gleixner  */
5196ae6ea0SThomas Gleixner 
5296ae6ea0SThomas Gleixner static u8 gettime(void)
5396ae6ea0SThomas Gleixner {
5496ae6ea0SThomas Gleixner 	u16 ax = 0x0200;
5596ae6ea0SThomas Gleixner 	u16 cx, dx;
5696ae6ea0SThomas Gleixner 
5796ae6ea0SThomas Gleixner 	asm volatile("int $0x1a"
5896ae6ea0SThomas Gleixner 		     : "+a" (ax), "=c" (cx), "=d" (dx)
5996ae6ea0SThomas Gleixner 		     : : "ebx", "esi", "edi");
6096ae6ea0SThomas Gleixner 
6196ae6ea0SThomas Gleixner 	return dx >> 8;
6296ae6ea0SThomas Gleixner }
6396ae6ea0SThomas Gleixner 
6496ae6ea0SThomas Gleixner /*
6596ae6ea0SThomas Gleixner  * Read from the keyboard
6696ae6ea0SThomas Gleixner  */
6796ae6ea0SThomas Gleixner int getchar(void)
6896ae6ea0SThomas Gleixner {
6996ae6ea0SThomas Gleixner 	u16 ax = 0;
7096ae6ea0SThomas Gleixner 	asm volatile("int $0x16" : "+a" (ax));
7196ae6ea0SThomas Gleixner 
7296ae6ea0SThomas Gleixner 	return ax & 0xff;
7396ae6ea0SThomas Gleixner }
7496ae6ea0SThomas Gleixner 
7596ae6ea0SThomas Gleixner static int kbd_pending(void)
7696ae6ea0SThomas Gleixner {
7796ae6ea0SThomas Gleixner 	u8 pending;
7896ae6ea0SThomas Gleixner 	asm volatile("int $0x16; setnz %0"
7996ae6ea0SThomas Gleixner 		     : "=rm" (pending)
8096ae6ea0SThomas Gleixner 		     : "a" (0x0100));
8196ae6ea0SThomas Gleixner 	return pending;
8296ae6ea0SThomas Gleixner }
8396ae6ea0SThomas Gleixner 
8496ae6ea0SThomas Gleixner void kbd_flush(void)
8596ae6ea0SThomas Gleixner {
8696ae6ea0SThomas Gleixner 	for (;;) {
8796ae6ea0SThomas Gleixner 		if (!kbd_pending())
8896ae6ea0SThomas Gleixner 			break;
8996ae6ea0SThomas Gleixner 		getchar();
9096ae6ea0SThomas Gleixner 	}
9196ae6ea0SThomas Gleixner }
9296ae6ea0SThomas Gleixner 
9396ae6ea0SThomas Gleixner int getchar_timeout(void)
9496ae6ea0SThomas Gleixner {
9596ae6ea0SThomas Gleixner 	int cnt = 30;
9696ae6ea0SThomas Gleixner 	int t0, t1;
9796ae6ea0SThomas Gleixner 
9896ae6ea0SThomas Gleixner 	t0 = gettime();
9996ae6ea0SThomas Gleixner 
10096ae6ea0SThomas Gleixner 	while (cnt) {
10196ae6ea0SThomas Gleixner 		if (kbd_pending())
10296ae6ea0SThomas Gleixner 			return getchar();
10396ae6ea0SThomas Gleixner 
10496ae6ea0SThomas Gleixner 		t1 = gettime();
10596ae6ea0SThomas Gleixner 		if (t0 != t1) {
10696ae6ea0SThomas Gleixner 			cnt--;
10796ae6ea0SThomas Gleixner 			t0 = t1;
10896ae6ea0SThomas Gleixner 		}
10996ae6ea0SThomas Gleixner 	}
11096ae6ea0SThomas Gleixner 
11196ae6ea0SThomas Gleixner 	return 0;		/* Timeout! */
11296ae6ea0SThomas Gleixner }
113