Rename ram_pages to init_ram_pages.
[pintos-anon] / src / devices / vga.c
1 #include "devices/vga.h"
2 #include <round.h>
3 #include <stdint.h>
4 #include <stddef.h>
5 #include <string.h>
6 #include "threads/io.h"
7 #include "threads/interrupt.h"
8 #include "threads/vaddr.h"
9
10 /* VGA text screen support.  See [FREEVGA] for more information. */
11
12 /* Number of columns and rows on the text display. */
13 #define COL_CNT 80
14 #define ROW_CNT 25
15
16 /* Current cursor position.  (0,0) is in the upper left corner of
17    the display. */
18 static size_t cx, cy;
19
20 /* Attribute value for gray text on a black background. */
21 #define GRAY_ON_BLACK 0x07
22
23 /* Framebuffer.  See [FREEVGA] under "VGA Text Mode Operation".
24    The character at (x,y) is fb[y][x][0].
25    The attribute at (x,y) is fb[y][x][1]. */
26 static uint8_t (*fb)[COL_CNT][2];
27
28 static void clear_row (size_t y);
29 static void cls (void);
30 static void newline (void);
31 static void move_cursor (void);
32 static void find_cursor (size_t *x, size_t *y);
33
34 /* Initializes the VGA text display. */
35 static void
36 init (void)
37 {
38   /* Already initialized? */
39   static bool inited;
40   if (!inited)
41     {
42       fb = ptov (0xb8000);
43       find_cursor (&cx, &cy);
44       inited = true; 
45     }
46 }
47
48 /* Writes C to the VGA text display, interpreting control
49    characters in the conventional ways.  */
50 void
51 vga_putc (int c)
52 {
53   /* Disable interrupts to lock out interrupt handlers
54      that might write to the console. */
55   enum intr_level old_level = intr_disable ();
56
57   init ();
58   
59   switch (c) 
60     {
61     case '\n':
62       newline ();
63       break;
64
65     case '\f':
66       cls ();
67       break;
68
69     case '\b':
70       if (cx > 0)
71         cx--;
72       break;
73       
74     case '\r':
75       cx = 0;
76       break;
77
78     case '\t':
79       cx = ROUND_UP (cx + 1, 8);
80       if (cx >= COL_CNT)
81         newline ();
82       break;
83       
84     default:
85       fb[cy][cx][0] = c;
86       fb[cy][cx][1] = GRAY_ON_BLACK;
87       if (++cx >= COL_CNT)
88         newline ();
89       break;
90     }
91
92   /* Update cursor position. */
93   move_cursor ();
94
95   intr_set_level (old_level);
96 }
97 \f
98 /* Clears the screen and moves the cursor to the upper left. */
99 static void
100 cls (void)
101 {
102   size_t y;
103
104   for (y = 0; y < ROW_CNT; y++)
105     clear_row (y);
106
107   cx = cy = 0;
108   move_cursor ();
109 }
110
111 /* Clears row Y to spaces. */
112 static void
113 clear_row (size_t y) 
114 {
115   size_t x;
116
117   for (x = 0; x < COL_CNT; x++)
118     {
119       fb[y][x][0] = ' ';
120       fb[y][x][1] = GRAY_ON_BLACK;
121     }
122 }
123
124 /* Advances the cursor to the first column in the next line on
125    the screen.  If the cursor is already on the last line on the
126    screen, scrolls the screen upward one line. */
127 static void
128 newline (void)
129 {
130   cx = 0;
131   cy++;
132   if (cy >= ROW_CNT)
133     {
134       cy = ROW_CNT - 1;
135       memmove (&fb[0], &fb[1], sizeof fb[0] * (ROW_CNT - 1));
136       clear_row (ROW_CNT - 1);
137     }
138 }
139
140 /* Moves the hardware cursor to (cx,cy). */
141 static void
142 move_cursor (void) 
143 {
144   /* See [FREEVGA] under "Manipulating the Text-mode Cursor". */
145   uint16_t cp = cx + COL_CNT * cy;
146   outw (0x3d4, 0x0e | (cp & 0xff00));
147   outw (0x3d4, 0x0f | (cp << 8));
148 }
149
150 /* Reads the current hardware cursor position into (*X,*Y). */
151 static void
152 find_cursor (size_t *x, size_t *y) 
153 {
154   /* See [FREEVGA] under "Manipulating the Text-mode Cursor". */
155   uint16_t cp;
156
157   outb (0x3d4, 0x0e);
158   cp = inb (0x3d5) << 8;
159
160   outb (0x3d4, 0x0f);
161   cp |= inb (0x3d5);
162
163   *x = cp % COL_CNT;
164   *y = cp / COL_CNT;
165 }