]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vgavesa.c
perms
[plan9front.git] / sys / src / 9 / pc / vgavesa.c
1 /*
2  * vga driver using just vesa bios to set up.
3  *
4  * note that setting hwaccel to zero will cause cursor ghosts to be
5  * left behind.  hwaccel set non-zero repairs this.
6  */
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "mem.h"
10 #include "dat.h"
11 #include "fns.h"
12 #include "io.h"
13 #include "../port/error.h"
14 #include "ureg.h"
15
16 #define Image   IMAGE
17 #include <draw.h>
18 #include <memdraw.h>
19 #include <cursor.h>
20 #include "screen.h"
21
22 enum {
23         Usesoftscreen = 1,
24 };
25
26 static void *hardscreen;
27 static uchar modebuf[0x1000];
28
29 #define WORD(p) ((p)[0] | ((p)[1]<<8))
30 #define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
31 #define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8
32 #define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24
33
34 static uchar*
35 vbesetup(Ureg *u, int ax)
36 {
37         ulong pa;
38
39         pa = PADDR(RMBUF);
40         memset(modebuf, 0, sizeof modebuf);
41         memset(u, 0, sizeof *u);
42         u->ax = ax;
43         u->es = (pa>>4)&0xF000;
44         u->di = pa&0xFFFF;
45         return modebuf;
46 }
47
48 static void
49 vbecall(Ureg *u)
50 {
51         Chan *creg, *cmem;
52         ulong pa;
53
54         cmem = namec("/dev/realmodemem", Aopen, ORDWR, 0);
55         if(waserror()){
56                 cclose(cmem);
57                 nexterror();
58         }
59         creg = namec("/dev/realmode", Aopen, ORDWR, 0);
60         if(waserror()){
61                 cclose(creg);
62                 nexterror();
63         }
64         pa = PADDR(RMBUF);
65         /* TODO: check read and write return values */
66         devtab[cmem->type]->write(cmem, modebuf, sizeof modebuf, pa);
67         u->trap = 0x10;
68         devtab[creg->type]->write(creg, u, sizeof *u, 0);
69
70         devtab[creg->type]->read(creg, u, sizeof *u, 0);
71         if((u->ax&0xFFFF) != 0x004F)
72                 error("vesa bios error");
73         devtab[cmem->type]->read(cmem, modebuf, sizeof modebuf, pa);
74
75         poperror();
76         cclose(creg);
77         poperror();
78         cclose(cmem);
79 }
80
81 static void
82 vbecheck(void)
83 {
84         Ureg u;
85         uchar *p;
86
87         p = vbesetup(&u, 0x4F00);
88         strcpy((char*)p, "VBE2");
89         vbecall(&u);
90         if(memcmp((char*)p, "VESA", 4) != 0)
91                 error("bad vesa signature");
92         if(p[5] < 2)
93                 error("bad vesa version");
94 }
95
96 static int
97 vbegetmode(void)
98 {
99         Ureg u;
100
101         vbesetup(&u, 0x4F03);
102         vbecall(&u);
103         return u.bx;
104 }
105
106 static uchar*
107 vbemodeinfo(int mode)
108 {
109         uchar *p;
110         Ureg u;
111
112         p = vbesetup(&u, 0x4F01);
113         u.cx = mode;
114         vbecall(&u);
115         return p;
116 }
117
118 static void
119 vesalinear(VGAscr *scr, int, int)
120 {
121         int i, mode, size, havesize;
122         uchar *p;
123         ulong paddr;
124         Pcidev *pci;
125
126         if(hardscreen) {
127                 scr->vaddr = 0;
128                 scr->paddr = scr->apsize = 0;
129                 return;
130         }
131
132         vbecheck();
133         mode = vbegetmode();
134         /*
135          * bochs loses the top bits - cannot use this
136         if((mode&(1<<14)) == 0)
137                 error("not in linear graphics mode");
138          */
139         mode &= 0x3FFF;
140         p = vbemodeinfo(mode);
141         if(!(WORD(p+0) & (1<<4)))
142                 error("not in VESA graphics mode");
143         if(!(WORD(p+0) & (1<<7)))
144                 error("not in linear graphics mode");
145
146         paddr = LONG(p+40);
147         size = WORD(p+20)*WORD(p+16);
148         size = PGROUND(size);
149
150         /*
151          * figure out max size of memory so that we have
152          * enough if the screen is resized.
153          */
154         pci = nil;
155         havesize = 0;
156         while(!havesize && (pci = pcimatch(pci, 0, 0)) != nil){
157                 if(pci->ccrb != Pcibcdisp)
158                         continue;
159                 for(i=0; i<nelem(pci->mem); i++)
160                         if(paddr == (pci->mem[i].bar&~0x0F)){
161                                 if(pci->mem[i].size > size)
162                                         size = pci->mem[i].size;
163                                 havesize = 1;
164                                 break;
165                         }
166         }
167
168         /* no pci - heuristic guess */
169         if (!havesize)
170                 if(size < 4*1024*1024)
171                         size = 4*1024*1024;
172                 else
173                         size = ROUND(size, 1024*1024);
174         if(size > 16*1024*1024)         /* arbitrary */
175                 size = 16*1024*1024;
176
177         vgalinearaddr(scr, paddr, size);
178         if(scr->apsize)
179                 addvgaseg("vesascreen", scr->paddr, scr->apsize);
180
181         if(Usesoftscreen){
182                 hardscreen = scr->vaddr;
183                 scr->vaddr = 0;
184                 scr->paddr = scr->apsize = 0;
185         }
186 }
187
188 static void
189 vesaflush(VGAscr *scr, Rectangle r)
190 {
191         int t, w, wid, off;
192         ulong *hp, *sp, *esp;
193
194         if(hardscreen == nil)
195                 return;
196         if(rectclip(&r, scr->gscreen->r) == 0)
197                 return;
198         sp = (ulong*)(scr->gscreendata->bdata + scr->gscreen->zero);
199         t = (r.max.x * scr->gscreen->depth + 2*BI2WD-1) / BI2WD;
200         w = (r.min.x * scr->gscreen->depth) / BI2WD;
201         w = (t - w) * BY2WD;
202         wid = scr->gscreen->width;
203         off = r.min.y * wid + (r.min.x * scr->gscreen->depth) / BI2WD;
204
205         hp = hardscreen;
206         hp += off;
207         sp += off;
208         esp = sp + Dy(r) * wid;
209         while(sp < esp){
210                 memmove(hp, sp, w);
211                 hp += wid;
212                 sp += wid;
213         }
214 }
215
216 VGAdev vgavesadev = {
217         "vesa",
218         0,
219         0,
220         0,
221         vesalinear,
222         0,
223         0,
224         0,
225         0,
226         vesaflush,
227 };