xref: /plan9/sys/src/9/pc/vgavesa.c (revision e06f534bbaa4097bc6f4764ef1dd2dc3338fbd40)
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 #include "ureg.h"
9 
10 #define	Image	IMAGE
11 #include <draw.h>
12 #include <memdraw.h>
13 #include <cursor.h>
14 #include "screen.h"
15 
16 #define WORD(p) ((p)[0] | ((p)[1]<<8))
17 #define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
18 #define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8
19 #define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24
20 
21 extern void realmode(Ureg*);
22 
23 static uchar*
24 vbesetup(Ureg *u, int ax)
25 {
26 	ulong pa;
27 
28 	pa = PADDR(RMBUF);
29 	memset(u, 0, sizeof *u);
30 	u->ax = ax;
31 	u->es = (pa>>4)&0xF000;
32 	u->di = pa&0xFFFF;
33 	return (void*)RMBUF;
34 }
35 
36 static void
37 vbecall(Ureg *u)
38 {
39 	u->trap = 0x10;
40 	realmode(u);
41 	if((u->ax&0xFFFF) != 0x004F)
42 		error("vesa bios error");
43 }
44 
45 static void
46 vbecheck(void)
47 {
48 	Ureg u;
49 	uchar *p;
50 
51 	p = vbesetup(&u, 0x4F00);
52 	strcpy((char*)p, "VBE2");
53 	vbecall(&u);
54 	if(memcmp((char*)p, "VESA", 4) != 0)
55 		error("bad vesa signature");
56 	if(p[5] < 2)
57 		error("bad vesa version");
58 }
59 
60 static int
61 vbegetmode(void)
62 {
63 	Ureg u;
64 
65 	vbesetup(&u, 0x4F03);
66 	vbecall(&u);
67 	return u.bx;
68 }
69 
70 static uchar*
71 vbemodeinfo(int mode)
72 {
73 	uchar *p;
74 	Ureg u;
75 
76 	p = vbesetup(&u, 0x4F01);
77 	u.cx = mode;
78 	vbecall(&u);
79 	return p;
80 }
81 
82 static void
83 vesalinear(VGAscr* scr, int, int)
84 {
85 	int i, mode, size;
86 	uchar *p;
87 	ulong paddr;
88 	Pcidev *pci;
89 
90 	vbecheck();
91 	mode = vbegetmode();
92 	/* bochs loses the top bits - cannot use this
93 	if((mode&(1<<14)) == 0)
94 		error("not in linear graphics mode");
95 	*/
96 	mode &= 0x3FFF;
97 	p = vbemodeinfo(mode);
98 	if(!(WORD(p+0) & (1<<4)))
99 		error("not in VESA graphics mode");
100 	if(!(WORD(p+0) & (1<<7)))
101 		error("not in linear graphics mode");
102 
103 	paddr = LONG(p+40);
104 	size = WORD(p+20)*WORD(p+16);
105 	size = PGROUND(size);
106 
107 	/*
108 	 * figure out max size of memory so that we have
109 	 * enough if the screen is resized.
110 	 */
111 	pci = nil;
112 	while((pci = pcimatch(pci, 0, 0)) != nil){
113 		if(pci->ccrb != 3)
114 			continue;
115 		for(i=0; i<nelem(pci->mem); i++)
116 			if(paddr == (pci->mem[i].bar&~0x0F)){
117 				if(pci->mem[i].size > size)
118 					size = pci->mem[i].size;
119 				goto havesize;
120 			}
121 	}
122 
123 	/* no pci - heuristic guess */
124 	if(size < 4*1024*1024)
125 		size = 4*1024*1024;
126 	else
127 		size = ROUND(size, 1024*1024);
128 
129 havesize:
130 	vgalinearaddr(scr, paddr, size);
131 }
132 
133 VGAdev vgavesadev = {
134 	"vesa",
135 	0,
136 	0,
137 	0,
138 	vesalinear,
139 	0,
140 	0,
141 	0,
142 	0,
143 	0,
144 };
145 
146