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