| /* |
| * Copyright (c) 2009 Corey Tabaka |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files |
| * (the "Software"), to deal in the Software without restriction, |
| * including without limitation the rights to use, copy, modify, merge, |
| * publish, distribute, sublicense, and/or sell copies of the Software, |
| * and to permit persons to whom the Software is furnished to do so, |
| * subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| #include <arch/x86.h> |
| #include <platform/pc.h> |
| #include <platform/console.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <stdarg.h> |
| |
| /* CGA values */ |
| #define CURSOR_START 0x0A |
| #define CURSOR_END 0x0B |
| #define VIDEO_ADDRESS_MSB 0x0C |
| #define VIDEO_ADDRESS_LSB 0x0D |
| #define CURSOR_POS_MSB 0x0E |
| #define CURSOR_POS_LSB 0x0F |
| |
| /* curr settings */ |
| static unsigned char curr_x; |
| static unsigned char curr_y; |
| static unsigned char curr_start; |
| static unsigned char curr_end; |
| static unsigned char curr_attr; |
| |
| /* video page buffer */ |
| #define VPAGE_SIZE 2048 |
| #define PAGE_MAX 8 |
| |
| static int active_page = 0; |
| static int visual_page = 0; |
| |
| static int curs_x[PAGE_MAX]; |
| static int curs_y[PAGE_MAX]; |
| |
| static struct { |
| int x1, y1, x2, y2; |
| } view_window = { |
| 0, 0, 79, 24 |
| }; |
| |
| void platform_init_console(void) |
| { |
| curr_save(); |
| window(0, 0, 79, 24); |
| clear(); |
| place(0, 0); |
| } |
| |
| void set_visual_page(int page) |
| { |
| unsigned short page_offset = page*VPAGE_SIZE; |
| visual_page = page; |
| |
| outp(CGA_INDEX_REG, VIDEO_ADDRESS_LSB); |
| outp(CGA_DATA_REG, page_offset & 0xFF); |
| outp(CGA_INDEX_REG, VIDEO_ADDRESS_MSB); |
| outp(CGA_DATA_REG, (page_offset >> 8) & 0xFF); |
| } |
| |
| void set_active_page(int page) |
| { |
| curs_x[active_page] = curr_x; |
| curs_y[active_page] = curr_y; |
| curr_x = curs_x[page]; |
| curr_y = curs_y[page]; |
| active_page = page; |
| } |
| |
| int get_visual_page(void) |
| { |
| return visual_page; |
| } |
| |
| int get_active_page(void) |
| { |
| return active_page; |
| } |
| |
| void place(int x,int y) |
| { |
| unsigned short cursor_word = x + y*80 + active_page*VPAGE_SIZE; |
| |
| /* |
| * program CGA using index reg, then data reg |
| */ |
| outp(CGA_INDEX_REG, CURSOR_POS_LSB); |
| outp(CGA_DATA_REG, cursor_word & 0xFF); |
| outp(CGA_INDEX_REG, CURSOR_POS_MSB); |
| outp(CGA_DATA_REG, (cursor_word >> 8) & 0xFF); |
| |
| curr_x = x; |
| curr_y = y; |
| } |
| |
| void cursor(int start,int end) |
| { |
| outp(CGA_INDEX_REG, CURSOR_START); |
| outp(CGA_DATA_REG, start); |
| outp(CGA_INDEX_REG, CURSOR_END); |
| outp(CGA_DATA_REG, end); |
| } |
| |
| void curr_save(void) |
| { |
| /* grab some info from the bios data area (these should be defined in memmap.h */ |
| curr_attr = *((unsigned char *)0xB8000 + 159); |
| curr_x = *((unsigned char *)0x00450); |
| curr_y = *((unsigned char *)0x00451); |
| curr_end = *((unsigned char *)0x00460); |
| curr_start = *((unsigned char *)0x00461); |
| active_page = visual_page = 0; |
| } |
| |
| void curr_restore(void) |
| { |
| *((unsigned char *)0x00450) = curr_x; |
| *((unsigned char *)0x00451) = curr_y; |
| |
| place(curr_x, curr_y); |
| cursor(curr_start, curr_end); |
| } |
| |
| void window(int x1, int y1, int x2, int y2) { |
| view_window.x1 = x1; |
| view_window.y1 = y1; |
| view_window.x2 = x2; |
| view_window.y2 = y2; |
| |
| //place(x1, y1); |
| } |
| |
| void _clear(char c,char attr,int x1,int y1,int x2,int y2) |
| { |
| register int i,j; |
| unsigned short w = attr; |
| |
| w <<= 8; w |= c; |
| for (i = x1; i <= x2; i++) { |
| for (j = y1; j <= y2; j++) { |
| *((unsigned short *)(0xB8000 + 2*i+160*j + 2*active_page*VPAGE_SIZE)) = w; |
| } |
| } |
| |
| place(x1,y1); |
| curr_y = y1; |
| curr_x = x1; |
| } |
| |
| void clear() |
| { |
| _clear(' ', curr_attr, view_window.x1, view_window.y1, view_window.x2, |
| view_window.y2); |
| } |
| |
| void _scroll(char attr, int x1, int y1, int x2, int y2) |
| { |
| register int x,y; |
| unsigned short xattr = attr << 8,w; |
| unsigned char *v = (unsigned char *)(0xB8000 + active_page*(2*VPAGE_SIZE)); |
| |
| for (y = y1+1; y <= y2; y++) { |
| for (x = x1; x <= x2; x++) { |
| w = *((unsigned short *) (v + 2*(y*80+x))); |
| *((unsigned short *)(v + 2*((y-1)*80+x))) = w; |
| } |
| } |
| |
| for (x = x1; x <= x2; x++) { |
| *((unsigned short *)(v + 2*((y-1)*80+x))) = xattr; |
| } |
| } |
| |
| void scroll(void) |
| { |
| _scroll(curr_attr, view_window.x1, view_window.y1, view_window.x2, |
| view_window.y2); |
| } |
| |
| void cputc(char c) |
| { |
| static unsigned short scan_x, x, y; |
| unsigned char *v = (unsigned char *)(0xB8000 + active_page*(2*VPAGE_SIZE)); |
| x = curr_x; |
| y = curr_y; |
| |
| switch (c) { |
| case '\t': |
| x += 8; |
| if (x >= view_window.x2+1) { |
| x = view_window.x1; |
| if (y == view_window.y2) { |
| scroll(); |
| } else { |
| y++; |
| } |
| } else { |
| scan_x = 0; |
| |
| while ((scan_x+8) < x) { |
| scan_x += 8; |
| } |
| |
| x = scan_x; |
| } |
| break; |
| |
| case '\n': |
| x = view_window.x1; |
| if (y == view_window.y2) { |
| scroll(); |
| } else { |
| y++; |
| } |
| break; |
| |
| case '\b': |
| x--; |
| *(v + 2*(x + y*80)) = ' '; |
| break; |
| |
| default: |
| *(v + 2*(x + y*80)) = c; |
| x++; |
| |
| if (x >= view_window.x2+1) { |
| x = view_window.x1; |
| if (y == view_window.y2) { |
| scroll(); |
| } else { |
| y++; |
| } |
| } |
| } |
| |
| place(x, y); |
| } |
| |
| void cputs(char *s) |
| { |
| char c; |
| while (*s != '\0') { |
| c = *s++; |
| cputc(c); |
| } |
| } |
| |
| void puts_xy(int x,int y,char attr,char *s) |
| { |
| unsigned char *v = (unsigned char *)(0xB8000 + (80*y+x)*2 + active_page*(2*VPAGE_SIZE)); |
| while (*s != 0) { |
| *v = *s; s++; v++; |
| *v = attr; v++; |
| } |
| } |
| |
| void putc_xy(int x, int y, char attr, char c) |
| { |
| unsigned char *v = (unsigned char *)(0xB8000 + (80*y+x)*2 + active_page*(2*VPAGE_SIZE)); |
| *v = c; v++; |
| *v = attr; |
| } |
| |
| int printf_xy(int x, int y, char attr, char *fmt, ...) |
| { |
| char cbuf[200]; |
| va_list parms; |
| int result; |
| |
| va_start(parms, fmt); |
| result = vsprintf(cbuf, fmt, parms); |
| va_end(parms); |
| |
| puts_xy(x, y, attr, cbuf); |
| |
| return result; |
| } |