| 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 | 
|  | 5 | * | 
|  | 6 | *   This file is part of the Linux kernel, and is made available under | 
|  | 7 | *   the terms of the GNU General Public License version 2. | 
|  | 8 | * | 
|  | 9 | * ----------------------------------------------------------------------- */ | 
|  | 10 |  | 
|  | 11 | /* | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 12 | * Very simple screen I/O | 
|  | 13 | * XXX: Probably should add very simple serial I/O? | 
|  | 14 | */ | 
|  | 15 |  | 
|  | 16 | #include "boot.h" | 
|  | 17 |  | 
|  | 18 | /* | 
|  | 19 | * These functions are in .inittext so they can be used to signal | 
|  | 20 | * error during initialization. | 
|  | 21 | */ | 
|  | 22 |  | 
|  | 23 | void __attribute__((section(".inittext"))) putchar(int ch) | 
|  | 24 | { | 
|  | 25 | unsigned char c = ch; | 
|  | 26 |  | 
|  | 27 | if (c == '\n') | 
|  | 28 | putchar('\r');	/* \n -> \r\n */ | 
|  | 29 |  | 
|  | 30 | /* int $0x10 is known to have bugs involving touching registers | 
|  | 31 | it shouldn't.  Be extra conservative... */ | 
| H. Peter Anvin | 8c027ae | 2007-07-16 11:58:24 -0700 | [diff] [blame] | 32 | asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal" | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 33 | : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch)); | 
|  | 34 | } | 
|  | 35 |  | 
|  | 36 | void __attribute__((section(".inittext"))) puts(const char *str) | 
|  | 37 | { | 
|  | 38 | int n = 0; | 
|  | 39 | while (*str) { | 
|  | 40 | putchar(*str++); | 
|  | 41 | n++; | 
|  | 42 | } | 
|  | 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 | { | 
|  | 52 | u16 ax = 0x0200; | 
|  | 53 | u16 cx, dx; | 
|  | 54 |  | 
| H. Peter Anvin | b015124 | 2007-08-22 16:28:01 -0700 | [diff] [blame] | 55 | asm volatile("int $0x1a" | 
|  | 56 | : "+a" (ax), "=c" (cx), "=d" (dx) | 
|  | 57 | : : "ebx", "esi", "edi"); | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 58 |  | 
|  | 59 | return dx >> 8; | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | /* | 
|  | 63 | * Read from the keyboard | 
|  | 64 | */ | 
|  | 65 | int getchar(void) | 
|  | 66 | { | 
|  | 67 | u16 ax = 0; | 
| H. Peter Anvin | b015124 | 2007-08-22 16:28:01 -0700 | [diff] [blame] | 68 | asm volatile("int $0x16" : "+a" (ax)); | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 69 |  | 
|  | 70 | return ax & 0xff; | 
|  | 71 | } | 
|  | 72 |  | 
|  | 73 | static int kbd_pending(void) | 
|  | 74 | { | 
|  | 75 | u8 pending; | 
| H. Peter Anvin | b015124 | 2007-08-22 16:28:01 -0700 | [diff] [blame] | 76 | asm volatile("int $0x16; setnz %0" | 
|  | 77 | : "=rm" (pending) | 
|  | 78 | : "a" (0x0100)); | 
| H. Peter Anvin | 1543610 | 2007-07-11 12:18:45 -0700 | [diff] [blame] | 79 | return pending; | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | void kbd_flush(void) | 
|  | 83 | { | 
|  | 84 | for (;;) { | 
|  | 85 | if (!kbd_pending()) | 
|  | 86 | break; | 
|  | 87 | getchar(); | 
|  | 88 | } | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | int getchar_timeout(void) | 
|  | 92 | { | 
|  | 93 | int cnt = 30; | 
|  | 94 | int t0, t1; | 
|  | 95 |  | 
|  | 96 | t0 = gettime(); | 
|  | 97 |  | 
|  | 98 | while (cnt) { | 
|  | 99 | if (kbd_pending()) | 
|  | 100 | return getchar(); | 
|  | 101 |  | 
|  | 102 | t1 = gettime(); | 
|  | 103 | if (t0 != t1) { | 
|  | 104 | cnt--; | 
|  | 105 | t0 = t1; | 
|  | 106 | } | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | return 0;		/* Timeout! */ | 
|  | 110 | } |