diff options
Diffstat (limited to 'src/console')
-rw-r--r-- | src/console/console.c | 75 | ||||
-rw-r--r-- | src/console/logbuf_console.c | 19 | ||||
-rw-r--r-- | src/console/printk.c | 56 | ||||
-rw-r--r-- | src/console/uart8250_console.c | 49 | ||||
-rw-r--r-- | src/console/vga_console.c | 100 | ||||
-rw-r--r-- | src/console/vsprintf.c | 352 |
6 files changed, 651 insertions, 0 deletions
diff --git a/src/console/console.c b/src/console/console.c new file mode 100644 index 0000000000..458fbb8fff --- /dev/null +++ b/src/console/console.c @@ -0,0 +1,75 @@ +/* + * Bootstrap code for the INTEL + * $Id$ + * + */ + +#include <arch/io.h> +#include <console/console.h> +#include <string.h> +#include <pc80/mc146818rtc.h> + + +static int initialized; + +/* initialize the console */ +void console_init(void) +{ + struct console_driver *driver; + if(get_option(&console_loglevel, "debug_level")) + console_loglevel=DEFAULT_CONSOLE_LOGLEVEL; + + for(driver = console_drivers; driver < econsole_drivers; driver++) { + if (!driver->init) + continue; + driver->init(); + } + initialized = 1; +} + +static void __console_tx_byte(unsigned char byte) +{ + struct console_driver *driver; + for(driver = console_drivers; driver < econsole_drivers; driver++) { + driver->tx_byte(byte); + } +} + +void console_tx_flush(void) +{ + struct console_driver *driver; + for(driver = console_drivers; driver < econsole_drivers; driver++) { + if (!driver->tx_flush) + continue; + driver->tx_flush(); + } +} + +void console_tx_byte(unsigned char byte) +{ + if (!initialized) + return; + if (byte == '\n') + __console_tx_byte('\r'); + __console_tx_byte(byte); +} + +/* + * Write POST information + */ +void post_code(uint8_t value) +{ +#ifdef CONFIG_SERIAL_POST + printk_info("POST: 0x%02x\n", value); +#elsif !define(NO_POST) + outb(value, 0x80); +#endif +} + +/* Report a fatal error */ +void die(char *msg) +{ + printk_emerg("%s", msg); + post_code(0xff); + while (1); /* Halt */ +} diff --git a/src/console/logbuf_console.c b/src/console/logbuf_console.c new file mode 100644 index 0000000000..e605ae5c23 --- /dev/null +++ b/src/console/logbuf_console.c @@ -0,0 +1,19 @@ +#include <console/console.h> + +#define LOGBUF_SIZE 1024 + +// KEEP THIS GLOBAL. +// I need the address so I can watch it with the ARIUM hardware. RGM. +char logbuf[LOGBUF_SIZE]; +int logbuf_offset = 0; + +static void logbuf_tx_byte(unsigned char byte) +{ + logbuf[logbuf_offset] = byte; + logbuf_offset = (logbuf_offset +1) % LOGBUF_SIZE; +} + +static struct console_driver __console = { + .init = 0, + .tx_byte = logbuf_tx_byte, +};} diff --git a/src/console/printk.c b/src/console/printk.c new file mode 100644 index 0000000000..67b0d4e19b --- /dev/null +++ b/src/console/printk.c @@ -0,0 +1,56 @@ +/* + * blantantly copied from linux/kernel/printk.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +//typedef void * va_list; + +#include <stdarg.h> +#include <smp/spinlock.h> +#include <console/console.h> + +/* printk's without a loglevel use this.. */ +#define DEFAULT_MESSAGE_LOGLEVEL 4 /* BIOS_WARNING */ + +/* We show everything that is MORE important than this.. */ +#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ + +/* Keep together for sysctl support */ + +int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; +int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL; +int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL; +int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; + +void display(char*); +extern int vtxprintf(void (*)(unsigned char), const char *, va_list); + +spinlock_t console_lock = SPIN_LOCK_UNLOCKED; + +int do_printk(int msg_level, const char *fmt, ...) +{ + va_list args; + int i; + + if (msg_level >= console_loglevel) { + return 0; + } + + spin_lock(&console_lock); + + va_start(args, fmt); + i = vtxprintf(console_tx_byte, fmt, args); + va_end(args); + + console_tx_flush(); + + spin_unlock(&console_lock); + + return i; +} diff --git a/src/console/uart8250_console.c b/src/console/uart8250_console.c new file mode 100644 index 0000000000..6eeeb6aa55 --- /dev/null +++ b/src/console/uart8250_console.c @@ -0,0 +1,49 @@ +#include <console/console.h> +#include <uart8250.h> +#include <pc80/mc146818rtc.h> + +/* Base Address */ +#ifndef TTYS0_BASE +#define TTYS0_BASE 0x3f8 +#endif + +#ifndef TTYS0_BAUD +#define TTYS0_BAUD 115200 +#endif + +#if ((115200%TTYS0_BAUD) != 0) +#error Bad ttys0 baud rate +#endif + +#define TTYS0_DIV (115200/TTYS0_BAUD) + +/* Line Control Settings */ +#ifndef TTYS0_LCS +/* Set 8bit, 1 stop bit, no parity */ +#define TTYS0_LCS 0x3 +#endif + +#define UART_LCS TTYS0_LCS + +void ttyS0_init(void) +{ + static unsigned char div[8]={1,2,3,6,12,24,48,96}; + int b_index=0; + unsigned int divisor=TTYS0_DIV; + + if(get_option(&b_index,"baud_rate")==0) { + divisor=div[b_index]; + } + uart8250_init(TTYS0_BASE, divisor, TTYS0_LCS); +} + +void ttyS0_tx_byte(unsigned char data) +{ + uart8250_tx_byte(TTYS0_BASE, data); +} + +static struct console_driver uart8250_console __console = { + .init = ttyS0_init, + .tx_byte = ttyS0_tx_byte, +}; + diff --git a/src/console/vga_console.c b/src/console/vga_console.c new file mode 100644 index 0000000000..ffd6699529 --- /dev/null +++ b/src/console/vga_console.c @@ -0,0 +1,100 @@ +/* + * + * modified from original freebios code + * by Steve M. Gehlbach <steve@kesa.com> + * + */ + +#include <arch/io.h> +#include <string.h> +#include <pc80/vga.h> +#include <console/console.h> + +void beep(int ms); + +static char *vidmem; /* The video buffer, should be replaced by symbol in ldscript.ld */ +int vga_line, vga_col; + +#define VIDBUFFER 0xB8000; + +static void memsetw(void *s, int c, unsigned int n) +{ + int i; + u16 *ss = (u16 *) s; + + for (i = 0; i < n; i++) { + ss[i] = ( u16 ) c; + } +} + +static void vga_init(void) +{ + + // these are globals + vga_line = 0; + vga_col = 0; + vidmem = (unsigned char *) VIDBUFFER; + + // mainboard or chip specific init routines + // also loads font + vga_hardware_fixup(); + + // set attributes, char for entire screen + // font should be previously loaded in + // device specific code (vga_hardware_fixup) + memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); // +} + +static void vga_scroll(void) +{ + int i; + + memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2); + for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2) + vidmem[i] = ' '; +} + +static void vga_tx_byte(unsigned char byte) +{ + if (byte == '\n') { + vga_line++; + vga_col = 0; + + } else if (byte == '\r') { + vga_col = 0; + + } else if (byte == '\b') { + vga_col--; + + } else if (byte == '\t') { + vga_col += 4; + + } else if (byte == '\a') { + //beep + beep(500); + + } else { + vidmem[((vga_col + (vga_line *COLS)) * 2)] = byte; + vidmem[((vga_col + (vga_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT; + vga_col++; + } + if (vga_col < 0) { + vga_col = 0; + } + if (vga_col >= COLS) { + vga_line++; + vga_col = 0; + } + if (vga_line >= LINES) { + vga_scroll(); + vga_line--; + } + // move the cursor + write_crtc((vga_col + (vga_line *COLS)) >> 8, CRTC_CURSOR_HI); + write_crtc((vga_col + (vga_line *COLS)) & 0x0ff, CRTC_CURSOR_LO); +} + +struct console_driver { + .init = vga_init, + .tx_byte = vga_tx_byte, +}; diff --git a/src/console/vsprintf.c b/src/console/vsprintf.c new file mode 100644 index 0000000000..b1310c62d1 --- /dev/null +++ b/src/console/vsprintf.c @@ -0,0 +1,352 @@ +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#ifndef lint +static char rcsid[] = "$Id$"; +#endif + +#include <stdarg.h> +#include <string.h> + +/* haha, don't need ctype.c */ +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#define is_digit isdigit +#define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#define toupper(c) __toupper(c) + +static inline unsigned char __toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a'-'A'; + return c; +} + + +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ + unsigned long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper(*cp) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +long simple_strtol(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoul(cp+1,endp,base); + return simple_strtoul(cp,endp,base); +} + + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static int number(void (*tx_byte)(unsigned char byte), long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + int count = 0; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + tx_byte(' '), count++; + if (sign) + tx_byte(sign), count++; + if (type & SPECIAL) { + if (base==8) + tx_byte('0'), count++; + else if (base==16) { + tx_byte('0'), count++; + tx_byte(digits[33]), count++; + } + } + if (!(type & LEFT)) + while (size-- > 0) + tx_byte(c), count++; + while (i < precision--) + tx_byte('0'), count++; + while (i-- > 0) + tx_byte(tmp[i]), count++; + while (size-- > 0) + tx_byte(' '), count++; + return count; +} + + +int vtxprintf(void (*tx_byte)(unsigned char byte), const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + int count; + + for (count=0; *fmt ; ++fmt) { + if (*fmt != '%') { + tx_byte(*fmt), count++; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + tx_byte(' '), count++; + tx_byte((unsigned char) va_arg(args, int)), count++; + while (--field_width > 0) + tx_byte(' '), count++; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = "<NULL>"; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + tx_byte(' '), count++; + for (i = 0; i < len; ++i) + tx_byte(*s++), count++; + while (len < field_width--) + tx_byte(' '), count++; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + count += number(tx_byte, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = count; + } else { + int * ip = va_arg(args, int *); + *ip = count; + } + continue; + + case '%': + tx_byte('%'), count++; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + tx_byte('%'), count++; + if (*fmt) + tx_byte(*fmt), count++; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + count += number(tx_byte, num, base, field_width, precision, flags); + } + return count; +} + +/* FIXME this global makes vsprintf non-reentrant + */ +static char *str_buf; +static void str_tx_byte(unsigned char byte) +{ + *str_buf = byte; + str_buf++; +} + +int vsprintf(char * buf, const char *fmt, va_list args) +{ + int i; + str_buf = buf; + i = vtxprintf(str_tx_byte, fmt, args); + /* maeder/Ispiri -- The null termination was missing a deference */ + /* and was just zeroing out the pointer instead */ + *str_buf = '\0'; + return i; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} |