1 // SPDX-License-Identifier: GPL-2.0-only 2 /* -*- linux-c -*- ------------------------------------------------------- * 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 * Copyright 2007 rPath, Inc. - All Rights Reserved 6 * Copyright 2009 Intel Corporation; author H. Peter Anvin 7 * 8 * ----------------------------------------------------------------------- */ 9 10 /* 11 * Very simple screen and serial I/O 12 */ 13 14 #include "boot.h" 15 16 int early_serial_base; 17 18 #define XMTRDY 0x20 19 20 #define TXR 0 /* Transmit register (WRITE) */ 21 #define LSR 5 /* Line Status */ 22 23 /* 24 * These functions are in .inittext so they can be used to signal 25 * error during initialization. 26 */ 27 28 static void __section(".inittext") serial_putchar(int ch) 29 { 30 unsigned timeout = 0xffff; 31 32 while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) 33 cpu_relax(); 34 35 outb(ch, early_serial_base + TXR); 36 } 37 38 static void __section(".inittext") bios_putchar(int ch) 39 { 40 struct biosregs ireg; 41 42 initregs(&ireg); 43 ireg.bx = 0x0007; 44 ireg.cx = 0x0001; 45 ireg.ah = 0x0e; 46 ireg.al = ch; 47 intcall(0x10, &ireg, NULL); 48 } 49 50 void __section(".inittext") putchar(int ch) 51 { 52 if (ch == '\n') 53 putchar('\r'); /* \n -> \r\n */ 54 55 bios_putchar(ch); 56 57 if (early_serial_base != 0) 58 serial_putchar(ch); 59 } 60 61 void __section(".inittext") puts(const char *str) 62 { 63 while (*str) 64 putchar(*str++); 65 } 66 67 /* 68 * Read the CMOS clock through the BIOS, and return the 69 * seconds in BCD. 70 */ 71 72 static u8 gettime(void) 73 { 74 struct biosregs ireg, oreg; 75 76 initregs(&ireg); 77 ireg.ah = 0x02; 78 intcall(0x1a, &ireg, &oreg); 79 80 return oreg.dh; 81 } 82 83 /* 84 * Read from the keyboard 85 */ 86 int getchar(void) 87 { 88 struct biosregs ireg, oreg; 89 90 initregs(&ireg); 91 /* ireg.ah = 0x00; */ 92 intcall(0x16, &ireg, &oreg); 93 94 return oreg.al; 95 } 96 97 static int kbd_pending(void) 98 { 99 struct biosregs ireg, oreg; 100 101 initregs(&ireg); 102 ireg.ah = 0x01; 103 intcall(0x16, &ireg, &oreg); 104 105 return !(oreg.eflags & X86_EFLAGS_ZF); 106 } 107 108 void kbd_flush(void) 109 { 110 for (;;) { 111 if (!kbd_pending()) 112 break; 113 getchar(); 114 } 115 } 116 117 int getchar_timeout(void) 118 { 119 int cnt = 30; 120 int t0, t1; 121 122 t0 = gettime(); 123 124 while (cnt) { 125 if (kbd_pending()) 126 return getchar(); 127 128 t1 = gettime(); 129 if (t0 != t1) { 130 cnt--; 131 t0 = t1; 132 } 133 } 134 135 return 0; /* Timeout! */ 136 } 137 138