xref: /inferno-os/os/pc/vga.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 
8 #define	Image	IMAGE
9 #include <draw.h>
10 #include <memdraw.h>
11 #include <cursor.h>
12 #include "screen.h"
13 
14 static Memimage* back;
15 static Memimage *conscol;
16 
17 static Point curpos;
18 static Rectangle window;
19 static int *xp;
20 static int xbuf[256];
21 static Lock vgascreenlock;
22 int drawdebug;
23 
24 void
vgaimageinit(ulong chan)25 vgaimageinit(ulong chan)
26 {
27 	if(back == nil){
28 		back = allocmemimage(Rect(0,0,1,1), chan);	/* RSC BUG */
29 		if(back == nil)
30 			panic("back alloc");		/* RSC BUG */
31 		back->flags |= Frepl;
32 		back->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
33 		memfillcolor(back, DBlack);
34 	}
35 
36 	if(conscol == nil){
37 		conscol = allocmemimage(Rect(0,0,1,1), chan);	/* RSC BUG */
38 		if(conscol == nil)
39 			panic("conscol alloc");	/* RSC BUG */
40 		conscol->flags |= Frepl;
41 		conscol->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
42 		memfillcolor(conscol, DWhite);
43 	}
44 }
45 
46 static void
vgascroll(VGAscr * scr)47 vgascroll(VGAscr* scr)
48 {
49 	int h, o;
50 	Point p;
51 	Rectangle r;
52 
53 	h = scr->memdefont->height;
54 	o = 8*h;
55 	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
56 	p = Pt(window.min.x, window.min.y+o);
57 	memimagedraw(scr->gscreen, r, scr->gscreen, p, nil, p, S);
58 	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
59 	memimagedraw(scr->gscreen, r, back, ZP, nil, ZP, S);
60 
61 	curpos.y -= o;
62 }
63 
64 static void
vgascreenputc(VGAscr * scr,char * buf,Rectangle * flushr)65 vgascreenputc(VGAscr* scr, char* buf, Rectangle *flushr)
66 {
67 	Point p;
68 	int h, w, pos;
69 	Rectangle r;
70 
71 //	drawdebug = 1;
72 	if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
73 		xp = xbuf;
74 
75 	h = scr->memdefont->height;
76 	switch(buf[0]){
77 
78 	case '\n':
79 		if(curpos.y+h >= window.max.y){
80 			vgascroll(scr);
81 			*flushr = window;
82 		}
83 		curpos.y += h;
84 		vgascreenputc(scr, "\r", flushr);
85 		break;
86 
87 	case '\r':
88 		xp = xbuf;
89 		curpos.x = window.min.x;
90 		break;
91 
92 	case '\t':
93 		p = memsubfontwidth(scr->memdefont, " ");
94 		w = p.x;
95 		if(curpos.x >= window.max.x-4*w)
96 			vgascreenputc(scr, "\n", flushr);
97 
98 		pos = (curpos.x-window.min.x)/w;
99 		pos = 4-(pos%4);
100 		*xp++ = curpos.x;
101 		r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
102 		memimagedraw(scr->gscreen, r, back, back->r.min, nil, back->r.min, S);
103 		curpos.x += pos*w;
104 		break;
105 
106 	case '\b':
107 		if(xp <= xbuf)
108 			break;
109 		xp--;
110 		r = Rect(*xp, curpos.y, curpos.x, curpos.y+h);
111 		memimagedraw(scr->gscreen, r, back, back->r.min, nil, ZP, S);
112 		combinerect(flushr, r);
113 		curpos.x = *xp;
114 		break;
115 
116 	case '\0':
117 		break;
118 
119 	default:
120 		p = memsubfontwidth(scr->memdefont, buf);
121 		w = p.x;
122 
123 		if(curpos.x >= window.max.x-w)
124 			vgascreenputc(scr, "\n", flushr);
125 
126 		*xp++ = curpos.x;
127 		r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h);
128 		memimagedraw(scr->gscreen, r, back, back->r.min, nil, back->r.min, S);
129 		memimagestring(scr->gscreen, curpos, conscol, ZP, scr->memdefont, buf);
130 		combinerect(flushr, r);
131 		curpos.x += w;
132 	}
133 //	drawdebug = 0;
134 }
135 
136 static void
vgascreenputs(char * s,int n)137 vgascreenputs(char* s, int n)
138 {
139 	int i;
140 	Rune r;
141 	char buf[4];
142 	VGAscr *scr;
143 	Rectangle flushr;
144 
145 	scr = &vgascreen[0];
146 
147 	if(!islo()){
148 		/*
149 		 * Don't deadlock trying to
150 		 * print in an interrupt.
151 		 */
152 		if(!canlock(&vgascreenlock))
153 			return;
154 	}
155 	else
156 		lock(&vgascreenlock);
157 
158 	flushr = Rect(10000, 10000, -10000, -10000);
159 
160 	while(n > 0){
161 		i = chartorune(&r, s);
162 		if(i == 0){
163 			s++;
164 			--n;
165 			continue;
166 		}
167 		memmove(buf, s, i);
168 		buf[i] = 0;
169 		n -= i;
170 		s += i;
171 		vgascreenputc(scr, buf, &flushr);
172 	}
173 	flushmemscreen(flushr);
174 
175 	unlock(&vgascreenlock);
176 }
177 
178 void
vgascreenwin(VGAscr * scr)179 vgascreenwin(VGAscr* scr)
180 {
181 	int h, w;
182 
183 	h = scr->memdefont->height;
184 	w = scr->memdefont->info[' '].width;
185 
186 	window = insetrect(scr->gscreen->r, 48);
187 	window.max.x = window.min.x+((window.max.x-window.min.x)/w)*w;
188 	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
189 	curpos = window.min;
190 
191 	screenputs = vgascreenputs;
192 }
193 
194 /*
195  * Supposedly this is the way to turn DPMS
196  * monitors off using just the VGA registers.
197  * Unfortunately, it seems to mess up the video mode
198  * on the cards I've tried.
199  */
200 void
vgablank(VGAscr *,int blank)201 vgablank(VGAscr*, int blank)
202 {
203 	uchar seq1, crtc17;
204 
205 	if(blank) {
206 		seq1 = 0x00;
207 		crtc17 = 0x80;
208 	} else {
209 		seq1 = 0x20;
210 		crtc17 = 0x00;
211 	}
212 
213 	outs(Seqx, 0x0100);			/* synchronous reset */
214 	seq1 |= vgaxi(Seqx, 1) & ~0x20;
215 	vgaxo(Seqx, 1, seq1);
216 	crtc17 |= vgaxi(Crtx, 0x17) & ~0x80;
217 	delay(10);
218 	vgaxo(Crtx, 0x17, crtc17);
219 	outs(Crtx, 0x0300);				/* end synchronous reset */
220 }
221 
222 void
cornerstring(char * s)223 cornerstring(char *s)
224 {
225 	int h, w;
226 	VGAscr *scr;
227 	Rectangle r;
228 	Point p;
229 
230 	scr = &vgascreen[0];
231 	if(scr->aperture == 0 || screenputs != vgascreenputs)
232 		return;
233 	p = memsubfontwidth(scr->memdefont, s);
234 	w = p.x;
235 	h = scr->memdefont->height;
236 
237 	r = Rect(0, 0, w, h);
238 	memimagedraw(scr->gscreen, r, back, back->r.min, nil, back->r.min, S);
239 	memimagestring(scr->gscreen, r.min, conscol, ZP, scr->memdefont, s);
240 //	flushmemscreen(r);
241 }
242