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