00001 #include "devices/vga.h"
00002
00003 #include <round.h>
00004 #include <stdint.h>
00005 #include <stddef.h>
00006 #include <string.h>
00007 #include "devices/speaker.h"
00008 #include "threads/io.h"
00009 #include "threads/interrupt.h"
00010 #include "threads/vaddr.h"
00011
00012
00013
00014
00015 #define COL_CNT 80
00016 #define ROW_CNT 25
00017
00018
00019
00020 static size_t cx, cy;
00021
00022
00023 #define GRAY_ON_BLACK 0x07
00024
00025
00026
00027
00028 static uint8_t (*fb)[COL_CNT][2];
00029
00030 static void clear_row (size_t y);
00031 static void cls (void);
00032 static void newline (void);
00033 static void move_cursor (void);
00034 static void find_cursor (size_t *x, size_t *y);
00035
00036
00037 static void
00038 init (void)
00039 {
00040
00041 static bool inited;
00042 if (!inited)
00043 {
00044 fb = ptov (0xb8000);
00045 find_cursor (&cx, &cy);
00046 inited = true;
00047 }
00048 }
00049
00050
00051
00052 void
00053 vga_putc (int c)
00054 {
00055
00056
00057 enum intr_level old_level = intr_disable ();
00058
00059 init ();
00060
00061 switch (c)
00062 {
00063 case '\n':
00064 newline ();
00065 break;
00066
00067 case '\f':
00068 cls ();
00069 break;
00070
00071 case '\b':
00072 if (cx > 0)
00073 cx--;
00074 break;
00075
00076 case '\r':
00077 cx = 0;
00078 break;
00079
00080 case '\t':
00081 cx = ROUND_UP (cx + 1, 8);
00082 if (cx >= COL_CNT)
00083 newline ();
00084 break;
00085
00086 case '\a':
00087 intr_set_level (old_level);
00088 speaker_beep ();
00089 intr_disable ();
00090 break;
00091
00092 default:
00093 fb[cy][cx][0] = c;
00094 fb[cy][cx][1] = GRAY_ON_BLACK;
00095 if (++cx >= COL_CNT)
00096 newline ();
00097 break;
00098 }
00099
00100
00101 move_cursor ();
00102
00103 intr_set_level (old_level);
00104 }
00105
00106
00107 static void
00108 cls (void)
00109 {
00110 size_t y;
00111
00112 for (y = 0; y < ROW_CNT; y++)
00113 clear_row (y);
00114
00115 cx = cy = 0;
00116 move_cursor ();
00117 }
00118
00119
00120 static void
00121 clear_row (size_t y)
00122 {
00123 size_t x;
00124
00125 for (x = 0; x < COL_CNT; x++)
00126 {
00127 fb[y][x][0] = ' ';
00128 fb[y][x][1] = GRAY_ON_BLACK;
00129 }
00130 }
00131
00132
00133
00134
00135 static void
00136 newline (void)
00137 {
00138 cx = 0;
00139 cy++;
00140 if (cy >= ROW_CNT)
00141 {
00142 cy = ROW_CNT - 1;
00143 memmove (&fb[0], &fb[1], sizeof fb[0] * (ROW_CNT - 1));
00144 clear_row (ROW_CNT - 1);
00145 }
00146 }
00147
00148
00149 static void
00150 move_cursor (void)
00151 {
00152
00153 uint16_t cp = cx + COL_CNT * cy;
00154 outw (0x3d4, 0x0e | (cp & 0xff00));
00155 outw (0x3d4, 0x0f | (cp << 8));
00156 }
00157
00158
00159 static void
00160 find_cursor (size_t *x, size_t *y)
00161 {
00162
00163 uint16_t cp;
00164
00165 outb (0x3d4, 0x0e);
00166 cp = inb (0x3d5) << 8;
00167
00168 outb (0x3d4, 0x0f);
00169 cp |= inb (0x3d5);
00170
00171 *x = cp % COL_CNT;
00172 *y = cp / COL_CNT;
00173 }