| /* |
| * Copyright (C) 2003, 2004 Stefan Reinauer |
| * |
| * See the file "COPYING" for further information about |
| * the copyright and warranty status of this work. |
| */ |
| |
| #include "config.h" |
| #include "kernel/kernel.h" |
| #include "openbios.h" |
| |
| #ifdef CONFIG_DEBUG_CONSOLE |
| |
| /* ****************************************************************** |
| * serial console functions |
| * ****************************************************************** */ |
| |
| #ifdef CONFIG_DEBUG_CONSOLE_SERIAL |
| |
| #define RBR(x) x==2?0x2f8:0x3f8 |
| #define THR(x) x==2?0x2f8:0x3f8 |
| #define IER(x) x==2?0x2f9:0x3f9 |
| #define IIR(x) x==2?0x2fa:0x3fa |
| #define LCR(x) x==2?0x2fb:0x3fb |
| #define MCR(x) x==2?0x2fc:0x3fc |
| #define LSR(x) x==2?0x2fd:0x3fd |
| #define MSR(x) x==2?0x2fe:0x3fe |
| #define SCR(x) x==2?0x2ff:0x3ff |
| #define DLL(x) x==2?0x2f8:0x3f8 |
| #define DLM(x) x==2?0x2f9:0x3f9 |
| |
| static int uart_charav(int port) |
| { |
| if (!port) |
| return -1; |
| return ((inb(LSR(port)) & 1) != 0); |
| } |
| |
| static char uart_getchar(int port) |
| { |
| if (!port) |
| return -1; |
| while (!uart_charav(port)); |
| return ((char) inb(RBR(port)) & 0177); |
| } |
| |
| static void uart_putchar(int port, unsigned char c) |
| { |
| if (!port) |
| return; |
| if (c == '\n') |
| uart_putchar(port, '\r'); |
| while (!(inb(LSR(port)) & 0x20)); |
| outb(c, THR(port)); |
| } |
| |
| static void uart_init_line(int port, unsigned long baud) |
| { |
| int i, baudconst; |
| |
| if (!port) |
| return; |
| |
| switch (baud) { |
| case 115200: |
| baudconst = 1; |
| break; |
| case 57600: |
| baudconst = 2; |
| break; |
| case 38400: |
| baudconst = 3; |
| break; |
| case 19200: |
| baudconst = 6; |
| break; |
| case 9600: |
| default: |
| baudconst = 12; |
| break; |
| } |
| |
| outb(0x87, LCR(port)); |
| outb(0x00, DLM(port)); |
| outb(baudconst, DLL(port)); |
| outb(0x07, LCR(port)); |
| outb(0x0f, MCR(port)); |
| |
| for (i = 10; i > 0; i--) { |
| if (inb(LSR(port)) == (unsigned int) 0) |
| break; |
| inb(RBR(port)); |
| } |
| } |
| |
| int uart_init(int port, unsigned long speed) |
| { |
| if (port) |
| uart_init_line(port, speed); |
| return -1; |
| } |
| |
| static void serial_putchar(int c) |
| { |
| uart_putchar(CONFIG_SERIAL_PORT, (unsigned char) (c & 0xff)); |
| } |
| |
| static void serial_cls(void) |
| { |
| serial_putchar(27); |
| serial_putchar('['); |
| serial_putchar('H'); |
| serial_putchar(27); |
| serial_putchar('['); |
| serial_putchar('J'); |
| } |
| |
| #endif |
| |
| /* ****************************************************************** |
| * simple polling video/keyboard console functions |
| * ****************************************************************** */ |
| |
| #ifdef CONFIG_DEBUG_CONSOLE_VGA |
| |
| /* raw vga text mode */ |
| #define COLUMNS 80 /* The number of columns. */ |
| #define LINES 25 /* The number of lines. */ |
| #define ATTRIBUTE 7 /* The attribute of an character. */ |
| |
| #define VGA_BASE 0xB8000 /* The video memory address. */ |
| |
| /* VGA Index and Data Registers */ |
| #define VGA_REG_INDEX 0x03D4 /* VGA index register */ |
| #define VGA_REG_DATA 0x03D5 /* VGA data register */ |
| |
| #define VGA_IDX_CURMSL 0x09 /* cursor maximum scan line */ |
| #define VGA_IDX_CURSTART 0x0A /* cursor start */ |
| #define VGA_IDX_CUREND 0x0B /* cursor end */ |
| #define VGA_IDX_CURLO 0x0F /* cursor position (low 8 bits) */ |
| #define VGA_IDX_CURHI 0x0E /* cursor position (high 8 bits) */ |
| |
| /* Save the X and Y position. */ |
| static int xpos, ypos; |
| /* Point to the video memory. */ |
| static volatile unsigned char *video = (unsigned char *) VGA_BASE; |
| |
| static void video_initcursor(void) |
| { |
| u8 val; |
| outb(VGA_IDX_CURMSL, VGA_REG_INDEX); |
| val = inb(VGA_REG_DATA) & 0x1f; /* maximum scan line -1 */ |
| |
| outb(VGA_IDX_CURSTART, VGA_REG_INDEX); |
| outb(0, VGA_REG_DATA); |
| |
| outb(VGA_IDX_CUREND, VGA_REG_INDEX); |
| outb(val, VGA_REG_DATA); |
| } |
| |
| |
| |
| static void video_poscursor(unsigned int x, unsigned int y) |
| { |
| unsigned short pos; |
| |
| /* Calculate new cursor position as a function of x and y */ |
| pos = (y * COLUMNS) + x; |
| |
| /* Output the new position to VGA card */ |
| outb(VGA_IDX_CURLO, VGA_REG_INDEX); /* output low 8 bits */ |
| outb((u8) (pos), VGA_REG_DATA); |
| outb(VGA_IDX_CURHI, VGA_REG_INDEX); /* output high 8 bits */ |
| outb((u8) (pos >> 8), VGA_REG_DATA); |
| |
| }; |
| |
| |
| static void video_newline(void) |
| { |
| xpos = 0; |
| |
| if (ypos < LINES - 1) { |
| ypos++; |
| } else { |
| int i; |
| memmove((void *) video, (void *) (video + 2 * COLUMNS), |
| (LINES - 1) * COLUMNS * 2); |
| |
| for (i = ((LINES - 1) * 2 * COLUMNS); |
| i < 2 * COLUMNS * LINES;) { |
| video[i++] = 0; |
| video[i++] = ATTRIBUTE; |
| } |
| } |
| |
| } |
| |
| /* Put the character C on the screen. */ |
| static void video_putchar(int c) |
| { |
| int p=1; |
| |
| if (c == '\n' || c == '\r') { |
| video_newline(); |
| return; |
| } |
| |
| if (c == '\b') { |
| if (xpos) xpos--; |
| c=' '; |
| p=0; |
| } |
| |
| |
| if (xpos >= COLUMNS) |
| video_newline(); |
| |
| *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF; |
| *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE; |
| |
| if (p) |
| xpos++; |
| |
| video_poscursor(xpos, ypos); |
| } |
| |
| static void video_cls(void) |
| { |
| int i; |
| |
| for (i = 0; i < 2 * COLUMNS * LINES;) { |
| video[i++] = 0; |
| video[i++] = ATTRIBUTE; |
| } |
| |
| |
| xpos = 0; |
| ypos = 0; |
| |
| video_initcursor(); |
| video_poscursor(xpos, ypos); |
| } |
| |
| void video_init(void) |
| { |
| video=phys_to_virt((unsigned char*)VGA_BASE); |
| } |
| |
| /* |
| * keyboard driver |
| */ |
| |
| static char normal[] = { |
| 0x0, 0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', |
| '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', |
| 'p', '[', ']', 0xa, 0x0, 'a', 's', 'd', 'f', 'g', 'h', 'j', |
| 'k', 'l', ';', 0x27, 0x60, 0x0, 0x5c, 'z', 'x', 'c', 'v', 'b', |
| 'n', 'm', ',', '.', '/', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0, |
| 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
| 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '0', 0x7f |
| }; |
| |
| static char shifted[] = { |
| 0x0, 0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', |
| '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', |
| 'P', '{', '}', 0xa, 0x0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', |
| 'K', 'L', ':', 0x22, '~', 0x0, '|', 'Z', 'X', 'C', 'V', 'B', |
| 'N', 'M', '<', '>', '?', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0, |
| 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '7', '8', |
| '9', 0x0, '4', '5', '6', 0x0, '1', '2', '3', '0', 0x7f |
| }; |
| |
| static int key_ext; |
| static int key_lshift = 0, key_rshift = 0, key_caps = 0; |
| |
| static char last_key; |
| |
| static void keyboard_cmd(unsigned char cmd, unsigned char val) |
| { |
| outb(cmd, 0x60); |
| /* wait until keyboard controller accepts cmds: */ |
| while (inb(0x64) & 2); |
| outb(val, 0x60); |
| while (inb(0x64) & 2); |
| } |
| |
| static char keyboard_poll(void) |
| { |
| unsigned int c; |
| if (inb(0x64) & 1) { |
| c = inb(0x60); |
| switch (c) { |
| case 0xe0: |
| key_ext = 1; |
| return 0; |
| case 0x2a: |
| key_lshift = 1; |
| return 0; |
| case 0x36: |
| key_rshift = 1; |
| return 0; |
| case 0xaa: |
| key_lshift = 0; |
| return 0; |
| case 0xb6: |
| key_rshift = 0; |
| return 0; |
| case 0x3a: |
| if (key_caps) { |
| key_caps = 0; |
| keyboard_cmd(0xed, 0); |
| } else { |
| key_caps = 1; |
| keyboard_cmd(0xed, 4); /* set caps led */ |
| } |
| return 0; |
| } |
| |
| if (key_ext) { |
| // void printk(const char *format, ...); |
| printk("extended keycode: %x\n", c); |
| |
| key_ext = 0; |
| return 0; |
| } |
| |
| if (c & 0x80) /* unhandled key release */ |
| return 0; |
| |
| if (key_lshift || key_rshift) |
| return key_caps ? normal[c] : shifted[c]; |
| else |
| return key_caps ? shifted[c] : normal[c]; |
| } |
| return 0; |
| } |
| |
| static int keyboard_dataready(void) |
| { |
| if (last_key) |
| return 1; |
| |
| last_key = keyboard_poll(); |
| |
| return (last_key != 0); |
| } |
| |
| static unsigned char keyboard_readdata(void) |
| { |
| char tmp; |
| while (!keyboard_dataready()); |
| tmp = last_key; |
| last_key = 0; |
| return tmp; |
| } |
| #endif |
| |
| |
| /* ****************************************************************** |
| * common functions, implementing simple concurrent console |
| * ****************************************************************** */ |
| |
| int arch_putchar(int c) |
| { |
| #ifdef CONFIG_DEBUG_CONSOLE_SERIAL |
| serial_putchar(c); |
| #endif |
| #ifdef CONFIG_DEBUG_CONSOLE_VGA |
| video_putchar(c); |
| #endif |
| return c; |
| } |
| |
| int arch_availchar(void) |
| { |
| #ifdef CONFIG_DEBUG_CONSOLE_SERIAL |
| if (uart_charav(CONFIG_SERIAL_PORT)) |
| return 1; |
| #endif |
| #ifdef CONFIG_DEBUG_CONSOLE_VGA |
| if (keyboard_dataready()) |
| return 1; |
| #endif |
| return 0; |
| } |
| |
| int arch_getchar(void) |
| { |
| #ifdef CONFIG_DEBUG_CONSOLE_SERIAL |
| if (uart_charav(CONFIG_SERIAL_PORT)) |
| return (uart_getchar(CONFIG_SERIAL_PORT)); |
| #endif |
| #ifdef CONFIG_DEBUG_CONSOLE_VGA |
| if (keyboard_dataready()) |
| return (keyboard_readdata()); |
| #endif |
| return 0; |
| } |
| |
| void cls(void) |
| { |
| #ifdef CONFIG_DEBUG_CONSOLE_SERIAL |
| serial_cls(); |
| #endif |
| #ifdef CONFIG_DEBUG_CONSOLE_VGA |
| video_cls(); |
| #endif |
| } |
| |
| struct _console_ops arch_console_ops = { |
| .putchar = arch_putchar, |
| .availchar = arch_availchar, |
| .getchar = arch_getchar |
| }; |
| |
| #endif // CONFIG_DEBUG_CONSOLE |