![H. Peter Anvin](/assets/img/avatar_default.png)
There exists at least one card, Trident TVGA8900CL (BIOS dated 1992/9/8) which clobbers DS when "scrolling in an SVGA text mode of more than 800x600 pixels." Although we are extremely unlikely to run into that situation, it is cheap insurance to save and restore DS, and it only adds a grand total of 50 bytes to the total output. Pointed out by Etienne Lorrain. Cc: Etienne Lorrain <etienne_lorrain@yahoo.fr> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
113 lines
1.9 KiB
C
113 lines
1.9 KiB
C
/* -*- linux-c -*- ------------------------------------------------------- *
|
|
*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
|
*
|
|
* This file is part of the Linux kernel, and is made available under
|
|
* the terms of the GNU General Public License version 2.
|
|
*
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* arch/i386/boot/tty.c
|
|
*
|
|
* Very simple screen I/O
|
|
* XXX: Probably should add very simple serial I/O?
|
|
*/
|
|
|
|
#include "boot.h"
|
|
|
|
/*
|
|
* These functions are in .inittext so they can be used to signal
|
|
* error during initialization.
|
|
*/
|
|
|
|
void __attribute__((section(".inittext"))) putchar(int ch)
|
|
{
|
|
unsigned char c = ch;
|
|
|
|
if (c == '\n')
|
|
putchar('\r'); /* \n -> \r\n */
|
|
|
|
/* int $0x10 is known to have bugs involving touching registers
|
|
it shouldn't. Be extra conservative... */
|
|
asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
|
|
: : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
|
|
}
|
|
|
|
void __attribute__((section(".inittext"))) puts(const char *str)
|
|
{
|
|
int n = 0;
|
|
while (*str) {
|
|
putchar(*str++);
|
|
n++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Read the CMOS clock through the BIOS, and return the
|
|
* seconds in BCD.
|
|
*/
|
|
|
|
static u8 gettime(void)
|
|
{
|
|
u16 ax = 0x0200;
|
|
u16 cx, dx;
|
|
|
|
asm("int $0x1a"
|
|
: "+a" (ax), "=c" (cx), "=d" (dx)
|
|
: : "ebx", "esi", "edi");
|
|
|
|
return dx >> 8;
|
|
}
|
|
|
|
/*
|
|
* Read from the keyboard
|
|
*/
|
|
int getchar(void)
|
|
{
|
|
u16 ax = 0;
|
|
asm("int $0x16" : "+a" (ax));
|
|
|
|
return ax & 0xff;
|
|
}
|
|
|
|
static int kbd_pending(void)
|
|
{
|
|
u8 pending;
|
|
asm("int $0x16; setnz %0"
|
|
: "=rm" (pending)
|
|
: "a" (0x0100));
|
|
return pending;
|
|
}
|
|
|
|
void kbd_flush(void)
|
|
{
|
|
for (;;) {
|
|
if (!kbd_pending())
|
|
break;
|
|
getchar();
|
|
}
|
|
}
|
|
|
|
int getchar_timeout(void)
|
|
{
|
|
int cnt = 30;
|
|
int t0, t1;
|
|
|
|
t0 = gettime();
|
|
|
|
while (cnt) {
|
|
if (kbd_pending())
|
|
return getchar();
|
|
|
|
t1 = gettime();
|
|
if (t0 != t1) {
|
|
cnt--;
|
|
t0 = t1;
|
|
}
|
|
}
|
|
|
|
return 0; /* Timeout! */
|
|
}
|