]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vgavesa.c
sdide: never timeout or retry scsi commands from the controller driver
[plan9front.git] / sys / src / 9 / pc / vgavesa.c
1 /*
2  * vga driver using just vesa bios to set up.
3  */
4 #include "u.h"
5 #include "../port/lib.h"
6 #include "mem.h"
7 #include "dat.h"
8 #include "fns.h"
9 #include "io.h"
10 #include "../port/error.h"
11
12 #define Ureg Ureg386
13 #include "/386/include/ureg.h"
14 typedef struct Ureg386 Ureg386;
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         Cdisable = 0,
24         Cenable,
25         Cblank,
26
27         RealModeBuf = 0x9000,
28 };
29
30 static uchar modebuf[0x1000];
31 static Chan *creg, *cmem;
32 static QLock vesaq;
33 static Rendez vesar;
34 static int vesactl;
35
36 #define WORD(p) ((p)[0] | ((p)[1]<<8))
37 #define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
38 #define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8
39 #define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24
40
41 static uchar*
42 vbesetup(Ureg386 *u, int ax)
43 {
44         memset(modebuf, 0, sizeof modebuf);
45         memset(u, 0, sizeof *u);
46         u->ax = ax;
47         u->es = (RealModeBuf>>4)&0xF000;
48         u->di = RealModeBuf&0xFFFF;
49         return modebuf;
50 }
51
52 static void
53 vbecall(Ureg386 *u)
54 {
55         if(devtab[cmem->type]->write(cmem, modebuf, sizeof(modebuf), RealModeBuf) != sizeof(modebuf))
56                 error("write modebuf");
57         u->trap = 0x10;
58         if(devtab[creg->type]->write(creg, u, sizeof(*u), 0) != sizeof(*u))
59                 error("write ureg");
60         if(devtab[creg->type]->read(creg, u, sizeof(*u), 0) != sizeof(*u))
61                 error("read ureg");
62         if((u->ax&0xFFFF) != 0x004F)
63                 error("vesa bios error");
64         if(devtab[cmem->type]->read(cmem, modebuf, sizeof(modebuf), RealModeBuf) != sizeof(modebuf))
65                 error("read modebuf");
66 }
67
68 static void
69 vbecheck(void)
70 {
71         Ureg386 u;
72         uchar *p;
73
74         p = vbesetup(&u, 0x4F00);
75         strcpy((char*)p, "VBE2");
76         vbecall(&u);
77         if(memcmp((char*)p, "VESA", 4) != 0)
78                 error("bad vesa signature");
79         if(p[5] < 2)
80                 error("bad vesa version");
81 }
82
83 static int
84 vbegetmode(void)
85 {
86         Ureg386 u;
87
88         vbesetup(&u, 0x4F03);
89         vbecall(&u);
90         return u.bx;
91 }
92
93 static uchar*
94 vbemodeinfo(int mode)
95 {
96         uchar *p;
97         Ureg386 u;
98
99         p = vbesetup(&u, 0x4F01);
100         u.cx = mode;
101         vbecall(&u);
102         return p;
103 }
104
105 static void
106 vesalinear(VGAscr *scr, int, int)
107 {
108         int i, mode, size, havesize;
109         ulong paddr;
110         Pcidev *pci;
111         uchar *p;
112
113         vbecheck();
114         mode = vbegetmode();
115         /*
116          * bochs loses the top bits - cannot use this
117         if((mode&(1<<14)) == 0)
118                 error("not in linear graphics mode");
119          */
120         mode &= 0x3FFF;
121         p = vbemodeinfo(mode);
122         if(!(WORD(p+0) & (1<<4)))
123                 error("not in VESA graphics mode");
124         if(!(WORD(p+0) & (1<<7)))
125                 error("not in linear graphics mode");
126
127         paddr = LONG(p+40);
128         size = WORD(p+20)*WORD(p+16);
129
130         /*
131          * figure out max size of memory so that we have
132          * enough if the screen is resized.
133          */
134         pci = nil;
135         havesize = 0;
136         while(!havesize && (pci = pcimatch(pci, 0, 0)) != nil){
137                 if(pci->ccrb != Pcibcdisp)
138                         continue;
139                 for(i=0; i<nelem(pci->mem); i++){
140                         ulong a, e;
141
142                         if(pci->mem[i].bar&1)   /* not memory */
143                                 continue;
144                         a = pci->mem[i].bar & ~0xF;
145                         e = a + pci->mem[i].size;
146                         if(paddr >= a && (paddr+size) <= e){
147                                 size = e - paddr;
148                                 havesize = 1;
149                                 break;
150                         }
151                 }
152         }
153
154         /* no pci - heuristic guess */
155         if(!havesize)
156                 if(size < 4*1024*1024)
157                         size = 4*1024*1024;
158                 else
159                         size = ROUND(size, 1024*1024);
160
161         vgalinearaddr(scr, paddr, size);
162         if(scr->apsize)
163                 addvgaseg("vesascreen", scr->paddr, scr->apsize);
164
165         scr->softscreen = 1;
166 }
167
168 static int
169 gotctl(void *arg)
170 {
171         return vesactl != *((int*)arg);
172 }
173
174 static void
175 vesaproc(void*)
176 {
177         Ureg386 u;
178         int ctl;
179
180         ctl = Cenable;
181         while(ctl != Cdisable){
182                 if(!waserror()){
183                         sleep(&vesar, gotctl, &ctl);
184                         ctl = vesactl;
185
186                         vbesetup(&u, 0x4f10);
187                         if(ctl == Cblank)
188                                 u.bx = 0x0101;
189                         else    
190                                 u.bx = 0x0001;
191
192                         /*
193                          * dont wait forever here. some BIOS get stuck
194                          * in i/o poll loop after blank/unblank for some
195                          * reason. (Thinkpad A22p)
196                          */
197                         procalarm(10000);
198                         vbecall(&u);
199
200                         poperror();
201                 }
202                 procalarm(0);
203                 up->notepending = 0;
204         }
205         cclose(cmem);
206         cclose(creg);
207         cmem = creg = nil;
208         qunlock(&vesaq);
209
210         pexit("", 1);
211 }
212
213 static void
214 vesaenable(VGAscr *)
215 {
216         eqlock(&vesaq);
217         if(waserror()){
218                 qunlock(&vesaq);
219                 nexterror();
220         }
221         cmem = namec("/dev/realmodemem", Aopen, ORDWR, 0);
222         if(waserror()){
223                 cclose(cmem);
224                 cmem = nil;
225                 nexterror();
226         }
227         creg = namec("/dev/realmode", Aopen, ORDWR, 0);
228         poperror();
229         poperror();
230
231         vesactl = Cenable;
232         kproc("vesa", vesaproc, nil);
233 }
234
235 static void
236 vesadisable(VGAscr *)
237 {
238         vesactl = Cdisable;
239         wakeup(&vesar);
240
241         /* wait for vesaproc to finish */
242         qlock(&vesaq);
243         qunlock(&vesaq);
244 }
245
246 static void
247 vesablank(VGAscr *, int blank)
248 {
249         if(vesactl != Cdisable){
250                 vesactl = blank ? Cblank : Cenable;
251                 wakeup(&vesar);
252         }
253 }
254
255 static void
256 vesadrawinit(VGAscr *scr)
257 {
258         scr->blank = vesablank;
259 }
260
261 VGAdev vgavesadev = {
262         "vesa",
263         vesaenable,
264         vesadisable,
265         0,
266         vesalinear,
267         vesadrawinit,
268 };