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