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