162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- * 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 562306a36Sopenharmony_ci * Copyright 2007 rPath, Inc. - All Rights Reserved 662306a36Sopenharmony_ci * Copyright 2009 Intel Corporation; author H. Peter Anvin 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * ----------------------------------------------------------------------- */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * Very simple screen and serial I/O 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "boot.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciint early_serial_base; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define XMTRDY 0x20 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define TXR 0 /* Transmit register (WRITE) */ 2162306a36Sopenharmony_ci#define LSR 5 /* Line Status */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * These functions are in .inittext so they can be used to signal 2562306a36Sopenharmony_ci * error during initialization. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void __section(".inittext") serial_putchar(int ch) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci unsigned timeout = 0xffff; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) 3362306a36Sopenharmony_ci cpu_relax(); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci outb(ch, early_serial_base + TXR); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void __section(".inittext") bios_putchar(int ch) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct biosregs ireg; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci initregs(&ireg); 4362306a36Sopenharmony_ci ireg.bx = 0x0007; 4462306a36Sopenharmony_ci ireg.cx = 0x0001; 4562306a36Sopenharmony_ci ireg.ah = 0x0e; 4662306a36Sopenharmony_ci ireg.al = ch; 4762306a36Sopenharmony_ci intcall(0x10, &ireg, NULL); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_civoid __section(".inittext") putchar(int ch) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci if (ch == '\n') 5362306a36Sopenharmony_ci putchar('\r'); /* \n -> \r\n */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci bios_putchar(ch); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (early_serial_base != 0) 5862306a36Sopenharmony_ci serial_putchar(ch); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_civoid __section(".inittext") puts(const char *str) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci while (*str) 6462306a36Sopenharmony_ci putchar(*str++); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * Read the CMOS clock through the BIOS, and return the 6962306a36Sopenharmony_ci * seconds in BCD. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic u8 gettime(void) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct biosregs ireg, oreg; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci initregs(&ireg); 7762306a36Sopenharmony_ci ireg.ah = 0x02; 7862306a36Sopenharmony_ci intcall(0x1a, &ireg, &oreg); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return oreg.dh; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* 8462306a36Sopenharmony_ci * Read from the keyboard 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ciint getchar(void) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct biosregs ireg, oreg; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci initregs(&ireg); 9162306a36Sopenharmony_ci /* ireg.ah = 0x00; */ 9262306a36Sopenharmony_ci intcall(0x16, &ireg, &oreg); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return oreg.al; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int kbd_pending(void) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct biosregs ireg, oreg; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci initregs(&ireg); 10262306a36Sopenharmony_ci ireg.ah = 0x01; 10362306a36Sopenharmony_ci intcall(0x16, &ireg, &oreg); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return !(oreg.eflags & X86_EFLAGS_ZF); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_civoid kbd_flush(void) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci for (;;) { 11162306a36Sopenharmony_ci if (!kbd_pending()) 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci getchar(); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciint getchar_timeout(void) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci int cnt = 30; 12062306a36Sopenharmony_ci int t0, t1; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci t0 = gettime(); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci while (cnt) { 12562306a36Sopenharmony_ci if (kbd_pending()) 12662306a36Sopenharmony_ci return getchar(); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci t1 = gettime(); 12962306a36Sopenharmony_ci if (t0 != t1) { 13062306a36Sopenharmony_ci cnt--; 13162306a36Sopenharmony_ci t0 = t1; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return 0; /* Timeout! */ 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 138