]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vmx/vesa.c
cwfs: fix listen filedescriptor leaks
[plan9front.git] / sys / src / cmd / vmx / vesa.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <draw.h>
5 #include "dat.h"
6 #include "fns.h"
7
8 static uchar vesabios[512] = {
9 0x55, 0xaa, 0x01, 0xcb, 0x60, 0x1e, 0x06, 0x8c, 0xd0, 0xba, 0xe0, 0xfe, 0xef, 0x89, 0xe0, 0xba, 0xe1, 0xfe, 0xef, 0xba, 0xe2, 0xfe, 0xed, 0x85, 0xc0, 0x7c, 0x28, 0x50, 0x25, 0x00, 
10 0xf0, 0x8e, 0xc0, 0xba, 0xe3, 0xfe, 0xed, 0x89, 0xc6, 0xc3, 0x26, 0x8b, 0x04, 0xba, 0xe4, 0xfe, 0xef, 0xeb, 0xe2, 0xba, 0xe4, 0xfe, 0xed, 0x26, 0x89, 0x04, 0xeb, 0xd9, 0xba, 0xe4, 
11 0xfe, 0xed, 0x26, 0x88, 0x04, 0xeb, 0xd0, 0x58, 0x58, 0x61, 0xcf,
12 };
13 enum {
14         READCMD = 0x28,
15         WRITEWCMD = 0x31,
16         WRITEBCMD = 0x3a,
17 };
18 typedef struct VESAIO VESAIO;
19 struct VESAIO {
20         u8int port;
21         u16int val;
22 };
23 Channel *vesawchan, *vesarchan;
24 typedef struct Ureg16 Ureg16;
25 struct Ureg16 {
26         u16int ax, bx, cx, dx;
27         u16int si, di, bp;
28         u16int ds, es;
29 };
30 #define ESDI(u) ((u).di + ((u).es<<4))
31 typedef struct Vesa Vesa;
32 struct Vesa {
33         u32int romptr;
34         u32int oemstring, oemvendor, oemproduct, oemproductrev;
35         u32int modetab;
36         u8int pal8;
37 } vesa;
38 #define FARPTR(x) (((x)&0xf0000)<<12|(u16int)(x))
39 extern VgaMode *modes, **modeslast, *curmode, *nextmode, textmode;
40 extern int curhbytes, nexthbytes;
41 extern uintptr fbaddr, fbsz;
42 extern int maxw, maxh;
43 enum { CMAP4 = CHAN1(CMap, 4) };
44
45
46 static VgaMode *
47 findmode(u16int m)
48 {
49         VgaMode *p;
50         
51         for(p = modes; p != nil; p = p->next)
52                 if(p->no == m)
53                         return p;
54         return nil;
55 }
56
57 static int
58 vesagetsp(void)
59 {
60         VESAIO io;
61         u32int rc;
62
63 loop:
64         while(recv(vesarchan, &io), io.port != 0)
65                 sendul(vesawchan, -1);
66         rc = io.val << 4;
67         sendul(vesawchan, -1);  
68         recv(vesarchan, &io);
69         sendul(vesawchan, -1);
70         if(io.port != 1) goto loop;
71         return rc + io.val;
72 }
73
74 static int
75 vesawrite(int addr, u32int val, int sz)
76 {
77         VESAIO io;
78
79         assert(sz == 1 || sz == 2 || sz == 4);
80         recv(vesarchan, &io);
81         if(io.port != 0x12){
82         no:     sendul(vesawchan, -1);
83                 return -1;
84         }
85         sendul(vesawchan, (sz > 1 ? WRITEWCMD : WRITEBCMD) | addr >> 4 & 0xf000);
86         recv(vesarchan, &io);
87         if(io.port != 0x13) goto no;
88         sendul(vesawchan, addr);
89         recv(vesarchan, &io);
90         if(io.port != 0x14) goto no;
91         sendul(vesawchan, val);
92         if(sz == 4)
93                 return vesawrite(addr + 2, val >> 16, 2);
94         return 0;       
95 }
96
97 static int
98 vesaread(int addr)
99 {
100         VESAIO io;
101
102         recv(vesarchan, &io);
103         if(io.port != 0x12){
104         no:     sendul(vesawchan, -1);
105                 return -1;
106         }
107         sendul(vesawchan, READCMD);
108         recv(vesarchan, &io);
109         if(io.port != 0x13) goto no;
110         sendul(vesawchan, addr);
111         recv(vesarchan, &io);
112         if(io.port != 0x4) goto no;
113         sendul(vesawchan, -1);
114         return io.val;  
115 }
116
117 static int
118 vesaregs(u32int sp, Ureg16 *ur)
119 {
120         int rc;
121         #define R(n, a) rc = vesaread(sp + n); if(rc < 0) return -1; ur->a = rc
122         
123         memset(ur, 0, sizeof(*ur));
124         R(0, es);
125         R(2, ds);
126         R(4, di);
127         R(6, si);
128         R(8, bp);
129         R(12, bx);
130         R(14, dx);
131         R(16, cx);
132         R(18, ax);
133         return 0;
134         #undef R
135 }
136
137 static int
138 vesasetregs(u32int sp, Ureg16 *ur)
139 {
140         #define R(n, a) if(vesawrite(sp + n, ur->a, 2) < 0) return -1;
141         
142         R(0, es);
143         R(2, ds);
144         R(4, di);
145         R(6, si);
146         R(8, bp);
147         R(12, bx);
148         R(14, dx);
149         R(16, cx);
150         R(18, ax);
151         return 0;
152         #undef R
153 }
154
155 #define vesasetax(sp, val) vesawrite(sp+18, val, 2)
156 #define vesasetbx(sp, val) vesawrite(sp+12, val, 2)
157
158 static int
159 vesapack(int addr, char *fmt, ...)
160 {
161         va_list va;
162         static u8int checksum;
163         int v;
164         char *p;
165         int numb;
166         
167         if(addr < 0) return -1;
168         numb = 0;
169         va_start(va, fmt);
170         for(; *fmt != 0; fmt++)
171                 switch(*fmt){
172                 case ' ': break;
173                 case 'b': v = va_arg(va, int); if(vesawrite(addr, v, 1) < 0) return -1; addr += 1; checksum += v; break;
174                 case 'w': v = va_arg(va, int); if(vesawrite(addr, v, 2) < 0) return -1; addr += 2; checksum += v + (v >> 8); break;
175                 case 'd': v = va_arg(va, int); if(vesawrite(addr, v, 4) < 0) return -1; addr += 4; checksum += v + (v >> 8) + (v >> 16) + (v >> 24); break;
176                 case 's': 
177                         p = va_arg(va, char *);
178                         for(; *p != 0; p++, addr++){
179                                 if(vesawrite(addr, *p, 1) < 0)
180                                         return -1;
181                                 checksum += *p;
182                         }
183                         break;
184                 case 'S':
185                         p = va_arg(va, char *);
186                         v = va_arg(va, int);
187                         while(v-- > 0){
188                                 if(vesawrite(addr++, *p, 1) < 0)
189                                         return -1;
190                                 checksum += *p++;
191                         }
192                         break;
193                 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
194                         numb = strtol(fmt, &fmt, 10);
195                         fmt--;
196                         break;
197                 case 'f':
198                         for(; numb >= 2; numb -= 2, addr += 2)
199                                 if(vesawrite(addr, 0, 2) < 0) return -1;
200                         if(numb == 1){
201                                 if(vesawrite(addr++, 0, 1) < 0) return -1;
202                                 numb = 0;
203                         }
204                         break;
205                 case 'c': if(vesawrite(addr, -checksum, 1) < 0) return -1; addr += 1; break;
206                 case 'C': checksum = 0; break;
207                 default: vmerror("vesapack: unknown char %c", *fmt); return -1;
208                 }
209         va_end(va);
210         return addr;
211 }
212
213 static int
214 vesarompack(char *fmt, ...)
215 {
216         va_list va;
217         uchar *v, *v0;
218         int rc, x;
219         void *s;
220         
221         v0 = gptr(vesa.romptr, 0x8000);
222         v = v0;
223         assert(v != nil);
224         va_start(va, fmt);
225         for(; *fmt != 0; fmt++)
226                 switch(*fmt){
227                 case 'b': *(u8int*)v = va_arg(va, int); v++; break;
228                 case 'w': *(u16int*)v = va_arg(va, int); v += 2; break;
229                 case 'd': *(u32int*)v = va_arg(va, int); v += 4; break;
230                 case 'a': v = (uchar*)strecpy((char*)v, (char*)v + 0x8000, va_arg(va, char*)); *v++ = 0; break;
231                 case 'S': s = va_arg(va, void *); x = va_arg(va, int); memcpy(v, s, x); v += x; break;
232                 default: sysfatal("vesarompack: unknown char %c", *fmt);
233                 }
234         va_end(va);
235         rc = vesa.romptr;
236         vesa.romptr += v - v0;
237         return rc;
238 }
239
240 static int
241 vesamodeget(int addr, u16int mode, u16int *retv)
242 {
243         VgaMode *p;
244         u8int model;
245         u8int nred, pred, ngreen, pgreen, nblue, pblue, nx, px;
246         int i, pos, s;
247         
248         p = findmode(mode);
249         if(p == nil){
250                 vmerror("vesa: Return VBE Mode Information: unknown mode %#x", mode);
251                 *retv = 0x014F;
252                 return 0;
253         }
254         *retv = 0x004F;
255         model = 6;
256         nred = pred = ngreen = pgreen = 0;
257         nblue = pblue = nx = px = 0;
258         pos = 0;
259         for(i = 0; i < 4; i++){
260                 s = p->chan >> 8 * i & 15;
261                 if(s == 0) continue;
262                 switch(p->chan >> 8 * i + 4 & 15){
263                 case CRed: nred = s; pred = pos; break;
264                 case CGreen: ngreen = s; pgreen = pos; break;
265                 case CBlue: nblue = s; pblue = pos; break;
266                 case CAlpha: case CIgnore: nx = s; px = pos; break;
267                 case CMap: model = 4; break;
268                 }
269                 pos += s;
270         }
271         return vesapack(addr, "wbbwwwwdw wwbbbbbbbbb bbbbbbbbb ddw wbbbbb bbbbbd 189f",
272                 1<<0|1<<1|1<<3|1<<4|1<<5|1<<6|1<<7, /* attributes: color graphics, vga incompatible, linear framebuffer */
273                 0, 0, 0, 0, 0, 0, 0, p->hbytes, /* windowing crap */
274                 p->w, p->h,
275                 0, 0, /* character size */
276                 1, chantodepth(p->chan), 1, /* 1 bank, 1 plane, N bpp */
277                 model, /* memory model */
278                 0, 0, 1, /* no banking/paging */
279                 nred, pred, ngreen, pgreen, nblue, pblue, nx, px, /* masks */
280                 0, /* no ramp, reserved bits are reserved */
281                 fbaddr,
282                 0, 0, /* reserved */
283                 p->hbytes, 0, 0,
284                 nred, pred, ngreen, pgreen, nblue, pblue, nx, px, /* masks */
285                 p->w * p->h * 60 * 2 /* max pixelclock */);
286 }
287
288 static int
289 vesamodeset(u16int mode, u16int *retv)
290 {
291         VgaMode *p;
292         
293         mode &= 0x1ff;
294         if(mode == 3){
295                 *retv = 0x04F;
296                 nextmode = &textmode;
297                 return 0;
298         }
299         p = findmode(mode);
300         if(p == nil){
301                 vmerror("vesa: Set VBE Mode: unknown mode %#x", mode);
302                 *retv = 0x14F;
303                 return 0;
304         }
305         *retv = 0x04F;
306         nextmode = p;
307         nexthbytes = p->hbytes;
308         vesa.pal8 = 0;
309         return 0;
310 }
311
312 static int
313 vesalinelen(Ureg16 *ur)
314 {
315         int d;
316         int nhb, x;
317         
318         d = chantodepth(nextmode->chan);
319         if(nextmode == &textmode || d == 0) goto fail;
320         switch(ur->bx & 0xff){
321         case 0:
322                 nhb = d * ur->cx / 8;
323         set:
324                 if((d & 7) != 0){
325                         vmerror("vesa: set logical length unsupported on bitdepth < 8");
326                 fail:   ur->ax = 0x014F;
327                         return 0;
328                 }
329                 if(nhb * nextmode->h > fbsz){
330                         ur->ax = 0x024F;
331                         return 0;
332                 }
333                 nexthbytes = nhb;
334                 ur->ax = 0x4F;
335                 ur->bx = nhb;
336                 ur->cx = nhb * 8 / d;
337                 ur->dx = fbsz / nhb;
338                 break;
339         case 1:
340                 ur->ax = 0x4F;
341                 ur->bx = nexthbytes;
342                 ur->cx = nexthbytes * 8 / d;
343                 ur->dx = fbsz / nexthbytes;
344                 break;
345         case 2:
346                 nhb = ur->cx;
347                 goto set;
348         case 3:
349                 x = fbsz / nextmode->h;
350                 ur->ax = 0x4F;
351                 ur->bx = x;
352                 ur->cx = x * 8 / d;
353                 ur->dx = nextmode->h;
354                 break;
355         default:
356                 vmerror("vesa: unsupported subfunction %#x of SetGetLogicalLineLength", ur->bx & 0xff);
357         }
358         return 0;
359 }
360
361 static int
362 vesapalformat(Ureg16 *ur)
363 {
364         switch(ur->bx & 0xff){
365         case 0:
366                 vesa.pal8 = (ur->bx >> 8) >= 8;
367         case 1:
368                 ur->ax = 0x4F;
369                 ur->bx = vesa.pal8 ? 8 : 6;
370                 break;
371         default:
372                 vmerror("vesa: unsupported subfunction %#x of SetGetDACPaletteFormat", ur->bx & 0xff);
373         }
374         return 0;
375 }
376
377 static int
378 vesapal(Ureg16 *ur)
379 {
380         int i;
381         int addr;
382         u32int c;
383         int r, g, b;
384
385         switch(ur->bx & 0xff){
386         case 0:
387         case 0x80:
388                 if(ur->dx >= 256 || ur->cx > 256){
389                         ur->ax = 0x014F;
390                         return 0;
391                 }
392                 ur->ax = 0x4F;
393                 addr = ESDI(*ur);
394                 for(i = ur->dx; i < ur->dx + ur->cx; i++){
395                         b = vesaread(addr);
396                         if(b < 0) return -1;
397                         g = b >> 8;
398                         b = b & 0xff;
399                         r = vesaread(addr + 2);
400                         if(r <  0) return -1;
401                         r &= 0xff;
402                         if(!vesa.pal8){
403                                 r <<= 2;
404                                 g <<= 2;
405                                 b <<= 2;
406                         }
407                         vgasetpal(i, r << 24 | g << 16 | b << 8 | 0xff);
408                         addr += 4;
409                 }
410                 break;
411         case 0x1:
412                 if(ur->dx >= 256 || ur->cx > 256){
413                         ur->ax = 0x014F;
414                         return 0;
415                 }
416                 ur->ax = 0x4F;
417                 addr = ESDI(*ur);
418                 for(i = ur->dx; i < ur->dx + ur->cx; i++){
419                         c = vgagetpal(i);
420                         r = c >> 24; g = c >> 16; b = c >> 8;
421                         if(!vesa.pal8){
422                                 r >>= 2;
423                                 g >>= 2;
424                                 b >>= 2;
425                         }
426                         addr = vesapack(addr, "bbbb", b, g, r, 0);
427                 }
428                 return addr >= 0 ? 0 : -1;
429         default:
430                 vmerror("vesa: unsupported subfunction %#x of SetGetPaletteData", ur->bx & 0xff);
431         }
432         return 0;
433 }
434
435 static void
436 stdtiming(u8int *arr)
437 {
438         VgaMode *m;
439         u8int s1, s2;
440         int i;
441         
442         memset(arr, 1, 16);
443         for(m = modes; m != nil; m = m->next){
444                 if(m->w < 256 || m->w > 2288 || m->w > maxw || m->h > maxh) continue;
445                 if((m->w & 7) != 0) continue;
446                 if(m->w == 640 && m->h == 480) continue;
447                 if(m->w == 800 && m->h == 600) continue;
448                 if(m->w == 1024 && m->h == 768) continue;
449                 if(m->w == 1280 && m->h == 1024) continue;
450                 if(m->w * 10 == m->w * 16)
451                         s2 = 0x00;
452                 else if(m->w * 3 == m->h * 4)
453                         s2 = 0x40;
454                 else if(m->w * 4 == m->h * 5)
455                         s2 = 0x80;
456                 else if(m->w * 9 == m->w * 16)
457                         s2 = 0xc0;
458                 else
459                         continue;
460                 s1 = m->w / 8 - 31;
461                 for(i = 0; i < 16; i += 2){
462                         if(arr[i] == s1 && arr[i+1] == s2)
463                                 goto skip;
464                         if(arr[i] == 1 && arr[i+1] == 1)
465                                 break;
466                 }
467                 if(i == 16) skip: continue;
468                 arr[i] = s1;
469                 arr[i+1] = s2;
470         }
471 }
472
473 static int
474 detailtiming(int addr, VgaMode **m)
475 {
476         u32int hv, hfp, hsp, hbp, hmm;
477         u32int vv, vfp, vsp, vbp, vmm;
478         u32int freq;
479
480 again:
481         if(*m == nil)
482                 return vesapack(addr, "d14f", 0x10000000);
483         /* when in doubt, make shit up */
484         hv = (*m)->w;
485         hfp = hv / 40;
486         hsp = hv * 3 / 20;
487         hbp = hfp * 4 + hsp;
488         vv = (*m)->h;
489         vfp = (vv + 24) / 48;
490         vsp = (vv + 120) / 240;
491         vbp = vfp * 3 + vsp;
492         freq = (hv + hfp + hsp + hbp) * (vv + vfp + vsp + vbp) * 60;
493         hmm = hv * 254 / 960; /* assume 96 dpi */
494         vmm = vv * 254 / 960;
495
496         *m = (*m)->next;
497         if(hv > maxw || vv > maxh || hv > 0xfff || hfp > 0x3ff || hsp > 0x3ff || vfp > 63 || vsp > 63)
498                 goto again;
499         return vesapack(addr, "w bbbbbbbbbb bbbbb b",
500                 freq / 10000,
501                 hv, hbp, hv >> 4 & 0xf0 | hbp >> 8 & 0xf,
502                 vv, vbp, vv >> 4 & 0xf0 | vbp >> 8 & 0xf,
503                 hfp, hsp,
504                 vfp << 4 & 0xf0 | vsp & 0xf,
505                 hfp >> 2 & 0xc0 | hsp >> 4 & 0x30 | vfp >> 2 & 0x0c | vsp >> 4 & 0x03,
506                 hmm, vmm,
507                 hmm >> 4 & 0xf0 | vmm >> 8 & 0xf,
508                 0, 0, 0x1f);
509                 
510 }
511
512 static int
513 vesaddc(Ureg16 *ur)
514 {
515         int addr;
516         u32int tim;
517         u8int std[16];
518         VgaMode *m;
519
520         switch(ur->bx & 0xff){
521         case 0:
522                 ur->ax = 0x004F;
523                 ur->bx = 3;
524                 break;
525         case 1:
526                 addr = ESDI(*ur);
527                 stdtiming(std);
528                 switch(ur->dx){
529                 case 0:
530                         ur->ax = 0x004F;
531                         tim = 0;
532                         if(maxw >= 640 && maxh >= 480) tim |= 0x3c;
533                         if(maxw >= 800 && maxh >= 600) tim |= 0xc003;
534                         if(maxw >= 1024 && maxh >= 768) tim |= 0xe00;
535                         if(maxw >= 1280 && maxh >= 1024) tim |= 0x100;
536                         addr = vesapack(addr, "Cdd bbbbdbb bb bbbbb bbbbb bbbbb wb S",
537                                 0xFFFFFF00,
538                                 0x00FFFFFF,
539                                 0x0c, 0x34, 0xa7, 0xac, /* manufacturer & product id */
540                                 1701, /* serial no */
541                                 0xff, 27, /* model year 2017 */
542                                 1, 4, /* edid version */
543                                 0xa1, /* DVI input */
544                                 maxw >= maxh ? maxw * 100 / maxh - 99 : 0, /* landscape aspect ratio */
545                                 maxw < maxh ? maxh * 100 / maxw - 99 : 0, /* portrait aspect ratio */
546                                 0x78, /* gamma=2.2 */
547                                 7, /* srgb & have preferred timing mode */
548                                 0, 0, 0, 0, 0, /* chromaticity coordinates */
549                                 0, 0, 0, 0, 0,
550                                 tim, tim >> 16,
551                                 std, 16);
552                         m = modes;
553                         addr = detailtiming(addr, &m);
554                         addr = detailtiming(addr, &m);
555                         addr = detailtiming(addr, &m);
556                         addr = vesapack(addr, "3fbb bbbb bbbb bbbbb",
557                                 0xfd, 0xa, 1, 0xff, 1, 0xff, 0xff, 0x04, 0x11,
558                                 maxw >> 11 & 3, maxw >> 3, 0xf8, 0x18, 0, 60); 
559                         addr = vesapack(addr, "bc", 0);
560                         if(addr < 0) return -1;
561                         break;
562                 default:
563                         ur->ax = 0x014F;
564                 }
565                 break;
566         default:
567                 vmerror("vesa: unsupported subfunction %#x of VBE/DDC", ur->bx & 0xff);
568         }
569         return 0;
570 }
571
572 static void
573 vesathread(void *)
574 {
575         u32int sp;
576         Ureg16 ur;
577
578         for(;;){
579                 sp = vesagetsp();
580 //              vmdebug("SP = %.8ux", sp);
581                 if(vesaregs(sp, &ur) < 0) continue;
582 //              vmdebug("AX = %.4x BX=%.4x CX=%.4x DX=%.4x", ur.ax, ur.bx, ur.cx, ur.dx);
583 //              vmdebug("SI = %.4x DI=%.4x BP=%.4x", ur.si, ur.di, ur.bp);
584 //              vmdebug("DS = %.4x ES=%.4x", ur.ds, ur.es);
585                 switch(ur.ax){
586                 case 0x4f00:
587                         if(vesapack(ESDI(ur), "swdddwwddd",
588                                 "VESA", /* VbeSignature */
589                                 0x0300, /* VbeVersion */
590                                 FARPTR(vesa.oemstring), /* OemStringPtr */
591                                 1, /* Capabilities (support 8 bit colors) */
592                                 FARPTR(vesa.modetab), /* VideoModePtr */
593                                 fbsz >> 16, /* TotalMemory */
594                                 0x100 /* OemSoftwareRev */,
595                                 FARPTR(vesa.oemvendor), /* OemVendorNamePtr */
596                                 FARPTR(vesa.oemproduct), /* OemProductNamePtr */
597                                 FARPTR(vesa.oemproductrev) /* OemProductRevPtr */) < 0)
598                                 continue;
599                         if(vesasetax(sp, 0x004F) < 0) continue;
600                         break;
601                 case 0x4f01:
602                         if(vesamodeget(ESDI(ur), ur.cx, &ur.ax) < 0) continue;
603                         if(vesasetax(sp, ur.ax) < 0) continue;
604                         break;
605                 case 0x4f02:
606                         if(vesamodeset(ur.bx, &ur.ax) < 0 || vesasetax(sp, ur.ax) < 0) continue;
607                         break;
608                 case 0x4f03:
609                         if(vesasetax(sp, 0x004F) < 0) continue;
610                         if(vesasetbx(sp, nextmode->no | 0x4000) < 0) continue;
611                         break;
612                 case 0x4f06:
613                         if(vesalinelen(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
614                         break;
615                 case 0x4f08:
616                         if(vesapalformat(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
617                         break;
618                 case 0x4f09:
619                         if(vesapal(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
620                         break;
621                 case 0x4f15:
622                         if(vesaddc(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
623                         break;
624                 default:
625                         vmerror("vesa: unsupported function %#x", ur.ax);
626                 }
627         }
628 }
629
630 static void
631 addmode(int no, int x, int y, u32int chan)
632 {
633         VgaMode *vm;
634         
635         vm = emalloc(sizeof(VgaMode));
636         vm->no = no;
637         vm->w = x;
638         vm->h = y;
639         vm->chan = chan;
640         vm->hbytes = chantodepth(chan) * vm->w + 7 >> 3;
641         vm->sz = vm->hbytes * y;
642         *modeslast = vm;
643         modeslast = &vm->next;
644 }
645
646 void
647 vesainit(void)
648 {
649         void *v;
650         int i, c;
651         int mno;
652         VgaMode *p;
653         
654         v = gptr(0xc0000, sizeof(vesabios));
655         if(v == nil) sysfatal("vesainit: gptr failed");
656         for(i = 0, c = 0; i < sizeof(vesabios) - 1; i++)
657                 c += vesabios[i];
658         vesabios[sizeof(vesabios) - 1] = -c;
659         vesa.romptr = 0xc0000;
660         vesarompack("S", vesabios, sizeof(vesabios));
661         
662         v = gptr(0, 1024);
663         if(v == nil) sysfatal("vesainit: gptr failed");
664         PUT32(v, 0x40, 0xc0000004);     
665         
666         vesa.oemstring = vesarompack("a", "9front vmx(1)");
667         vesa.oemvendor = vesarompack("a", "9front");
668         vesa.oemproduct = vesarompack("a", "cat graphics adapter");
669         vesa.oemproductrev = vesarompack("a", "∞");
670         
671         vesa.modetab = vesa.romptr;
672         mno = 0x120;
673         for(p = modes; p != nil; p = p->next){
674                 p->no = mno++;
675                 vesarompack("w", p->no);
676         }
677         vesarompack("w", 0xffff);
678
679         addmode(0x100, 640, 400, CMAP8);
680         addmode(0x101, 640, 480, CMAP8);
681         addmode(0x102, 800, 600, CMAP4);
682         addmode(0x6A, 800, 600, CMAP4);
683         addmode(0x103, 800, 600, CMAP8);
684         addmode(0x104, 1024, 768, CMAP4);
685         addmode(0x105, 1024, 768, CMAP8);
686         addmode(0x106, 1280, 1024, CMAP4);
687         addmode(0x107, 1280, 1024, CMAP8);
688         addmode(0x10D, 320, 200, RGB15);
689         addmode(0x10E, 320, 200, RGB16);
690         addmode(0x10F, 320, 200, RGB24);
691         addmode(0x110, 640, 480, RGB15);
692         addmode(0x111, 640, 480, RGB16);
693         addmode(0x112, 640, 480, RGB24);
694         addmode(0x113, 800, 600, RGB15);
695         addmode(0x114, 800, 600, RGB16);
696         addmode(0x115, 800, 600, RGB24);
697         addmode(0x116, 1024, 768, RGB15);
698         addmode(0x117, 1024, 768, RGB16);
699         addmode(0x118, 1024, 768, RGB24);
700         addmode(0x119, 1280, 1024, RGB15);
701         addmode(0x11A, 1280, 1024, RGB16);
702         addmode(0x11B, 1280, 1024, RGB24);
703         
704         vesarchan = chancreate(sizeof(VESAIO), 0);
705         vesawchan = chancreate(sizeof(ulong), 0);
706         threadcreate(vesathread, nil, 8192);
707 }
708
709 u32int
710 vesaio(int isin, u16int port, u32int val, int sz, void *)
711 {
712         VESAIO io;
713         
714         if(sz != 2) return iowhine(isin, port, val, sz, nil);
715         io.port = isin << 4 | port & 0xf;
716         io.val = val;
717         send(vesarchan, &io);
718         return recvul(vesawchan);
719 }