| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | /* -*- linux-c -*- ------------------------------------------------------- *
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   Copyright (C) 1991, 1992 Linus Torvalds | 
					
						
							|  |  |  |  *   Copyright 2007 rPath, Inc. - All Rights Reserved | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  |  *   Copyright 2009 Intel Corporation; author H. Peter Anvin | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  *   This file is part of the Linux kernel, and is made available under | 
					
						
							|  |  |  |  *   the terms of the GNU General Public License version 2. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ----------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2010-07-11 11:06:57 +03:00
										 |  |  |  * Very simple screen and serial I/O | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "boot.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-02 02:17:31 -07:00
										 |  |  | int early_serial_base; | 
					
						
							| 
									
										
										
										
											2010-07-11 11:06:57 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define XMTRDY          0x20
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define TXR             0       /*  Transmit register (WRITE) */
 | 
					
						
							|  |  |  | #define LSR             5       /*  Line Status               */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * These functions are in .inittext so they can be used to signal | 
					
						
							|  |  |  |  * error during initialization. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-11 11:06:57 +03:00
										 |  |  | static void __attribute__((section(".inittext"))) serial_putchar(int ch) | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-11 11:06:57 +03:00
										 |  |  | 	unsigned timeout = 0xffff; | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-11 11:06:57 +03:00
										 |  |  | 	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) | 
					
						
							|  |  |  | 		cpu_relax(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	outb(ch, early_serial_base + TXR); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __attribute__((section(".inittext"))) bios_putchar(int ch) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct biosregs ireg; | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	initregs(&ireg); | 
					
						
							|  |  |  | 	ireg.bx = 0x0007; | 
					
						
							|  |  |  | 	ireg.cx = 0x0001; | 
					
						
							|  |  |  | 	ireg.ah = 0x0e; | 
					
						
							|  |  |  | 	ireg.al = ch; | 
					
						
							|  |  |  | 	intcall(0x10, &ireg, NULL); | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-11 11:06:57 +03:00
										 |  |  | void __attribute__((section(".inittext"))) putchar(int ch) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (ch == '\n') | 
					
						
							|  |  |  | 		putchar('\r');	/* \n -> \r\n */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bios_putchar(ch); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (early_serial_base != 0) | 
					
						
							|  |  |  | 		serial_putchar(ch); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | void __attribute__((section(".inittext"))) puts(const char *str) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	while (*str) | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | 		putchar(*str++); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Read the CMOS clock through the BIOS, and return the | 
					
						
							|  |  |  |  * seconds in BCD. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u8 gettime(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	struct biosregs ireg, oreg; | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	initregs(&ireg); | 
					
						
							|  |  |  | 	ireg.ah = 0x02; | 
					
						
							|  |  |  | 	intcall(0x1a, &ireg, &oreg); | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	return oreg.dh; | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Read from the keyboard | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int getchar(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	struct biosregs ireg, oreg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	initregs(&ireg); | 
					
						
							|  |  |  | 	/* ireg.ah = 0x00; */ | 
					
						
							|  |  |  | 	intcall(0x16, &ireg, &oreg); | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	return oreg.al; | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int kbd_pending(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-01 18:13:46 -07:00
										 |  |  | 	struct biosregs ireg, oreg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	initregs(&ireg); | 
					
						
							|  |  |  | 	ireg.ah = 0x01; | 
					
						
							|  |  |  | 	intcall(0x16, &ireg, &oreg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return !(oreg.eflags & X86_EFLAGS_ZF); | 
					
						
							| 
									
										
										
										
											2007-07-11 12:18:45 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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! */ | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-11 11:06:57 +03:00
										 |  |  | 
 |