| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 1 | /* -*- linux-c -*- ------------------------------------------------------- * | 
|  | 2 | * | 
|  | 3 | *   Copyright (C) 1991, 1992 Linus Torvalds | 
|  | 4 | *   Copyright 2007 rPath, Inc. - All Rights Reserved | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 5 | *   Copyright 2009 Intel Corporation; author H. Peter Anvin | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 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 | /* | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 13 | * Very simple screen I/O | 
|  | 14 | * XXX: Probably should add very simple serial I/O? | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | #include "boot.h" | 
|  | 18 |  | 
|  | 19 | /* | 
|  | 20 | * These functions are in .inittext so they can be used to signal | 
|  | 21 | * error during initialization. | 
|  | 22 | */ | 
|  | 23 |  | 
|  | 24 | void __attribute__((section(".inittext"))) putchar(int ch) | 
|  | 25 | { | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 26 | struct biosregs ireg; | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 27 |  | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 28 | if (ch == '\n') | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 29 | putchar('\r');	/* \n -> \r\n */ | 
|  | 30 |  | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 31 | initregs(&ireg); | 
|  | 32 | ireg.bx = 0x0007; | 
|  | 33 | ireg.cx = 0x0001; | 
|  | 34 | ireg.ah = 0x0e; | 
|  | 35 | ireg.al = ch; | 
|  | 36 | intcall(0x10, &ireg, NULL); | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 37 | } | 
|  | 38 |  | 
|  | 39 | void __attribute__((section(".inittext"))) puts(const char *str) | 
|  | 40 | { | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 41 | while (*str) | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 42 | putchar(*str++); | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 43 | } | 
|  | 44 |  | 
|  | 45 | /* | 
|  | 46 | * Read the CMOS clock through the BIOS, and return the | 
|  | 47 | * seconds in BCD. | 
|  | 48 | */ | 
|  | 49 |  | 
|  | 50 | static u8 gettime(void) | 
|  | 51 | { | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 52 | struct biosregs ireg, oreg; | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 53 |  | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 54 | initregs(&ireg); | 
|  | 55 | ireg.ah = 0x02; | 
|  | 56 | intcall(0x1a, &ireg, &oreg); | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 57 |  | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 58 | return oreg.dh; | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 59 | } | 
|  | 60 |  | 
|  | 61 | /* | 
|  | 62 | * Read from the keyboard | 
|  | 63 | */ | 
|  | 64 | int getchar(void) | 
|  | 65 | { | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 66 | struct biosregs ireg, oreg; | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 67 |  | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 68 | initregs(&ireg); | 
|  | 69 | /* ireg.ah = 0x00; */ | 
|  | 70 | intcall(0x16, &ireg, &oreg); | 
|  | 71 |  | 
|  | 72 | return oreg.al; | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 73 | } | 
|  | 74 |  | 
|  | 75 | static int kbd_pending(void) | 
|  | 76 | { | 
| H. Peter Anvin | df7699c | 2009-04-01 18:13:46 -0700 | [diff] [blame] | 77 | struct biosregs ireg, oreg; | 
|  | 78 |  | 
|  | 79 | initregs(&ireg); | 
|  | 80 | ireg.ah = 0x01; | 
|  | 81 | intcall(0x16, &ireg, &oreg); | 
|  | 82 |  | 
|  | 83 | return !(oreg.eflags & X86_EFLAGS_ZF); | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 84 | } | 
|  | 85 |  | 
|  | 86 | void kbd_flush(void) | 
|  | 87 | { | 
|  | 88 | for (;;) { | 
|  | 89 | if (!kbd_pending()) | 
|  | 90 | break; | 
|  | 91 | getchar(); | 
|  | 92 | } | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | int getchar_timeout(void) | 
|  | 96 | { | 
|  | 97 | int cnt = 30; | 
|  | 98 | int t0, t1; | 
|  | 99 |  | 
|  | 100 | t0 = gettime(); | 
|  | 101 |  | 
|  | 102 | while (cnt) { | 
|  | 103 | if (kbd_pending()) | 
|  | 104 | return getchar(); | 
|  | 105 |  | 
|  | 106 | t1 = gettime(); | 
|  | 107 | if (t0 != t1) { | 
|  | 108 | cnt--; | 
|  | 109 | t0 = t1; | 
|  | 110 | } | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | return 0;		/* Timeout! */ | 
|  | 114 | } |