12 uint32_t paddr = (uint32_t)(ptr); \
13 uint16_t pseg = paddr >> 16; \
14 uint16_t poffs = paddr & 0xffff; \
15 if(pseg == seg && poffs < 512) { \
16 paddr = ((uint32_t)seg << 4) + poffs; \
18 paddr = ((uint32_t)pseg << 4) + poffs; \
20 (ptr) = (void*)phys_to_virt(paddr); \
23 /* hijack the "VESA" sig field, to pre-cache number of modes */
24 #define NMODES(inf) *(uint16_t*)((inf)->sig)
25 #define NACCMODES(inf) *(uint16_t*)((inf)->sig + 2)
28 /* TODO update cur_pitch on mode-change and on setscanlen */
30 int vbe_info(struct vbe_info *info)
36 struct dpmi_regs regs = {0};
38 assert(sizeof *info == 512);
40 if(!(seg = dpmi_alloc(sizeof *info / 16, &sel))) {
43 lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
45 memcpy(lowbuf, "VBE2", 4);
50 dpmi_int(0x10, ®s);
52 if((regs.eax & 0xffff) != 0x4f) {
53 errormsg("vbe_get_info (4f00) failed\n");
58 memcpy(info, lowbuf, sizeof *info);
61 FIXPTR(info->oem_name);
63 FIXPTR(info->product);
66 /* implementations without the accel capability, will use the space taken
67 * by the accel_modes pointer for other data (probably video modes). We
68 * need to check for the capability before "fixing" this pointer, otherwise
69 * we'll shuffle random data.
71 if(info->caps & VBE_ACCEL) {
72 FIXPTR(info->accel_modes);
75 /* info->modes should be pointing somewhere at the end of the original
76 * low memory buffer. make it point at the same offset in the info
77 * buffer where we copied everything instead.
79 offs = (char*)info->modes - (char*)lowbuf;
80 if(offs < sizeof *info) { /* this should always be true */
81 info->modes = (uint16_t*)((char*)info + offs);
84 modeptr = info->modes;
85 while(*modeptr != 0xffff) {
86 if(modeptr - info->modes >= 256) {
87 modeptr = info->modes;
92 NMODES(info) = modeptr - info->modes;
94 if(info->caps & VBE_ACCEL) {
95 modeptr = info->accel_modes;
96 while(*modeptr != 0xffff) {
97 if(modeptr - info->accel_modes >= 256) {
98 modeptr = info->accel_modes;
103 NACCMODES(info) = modeptr - info->accel_modes;
108 int vbe_num_modes(struct vbe_info *info)
113 int vbe_mode_info(int mode, struct vbe_mode_info *minf)
117 struct dpmi_regs regs = {0};
119 assert(sizeof *minf == 256);
120 assert(offsetof(struct vbe_mode_info, max_pixel_clock) == 0x3e);
122 if(!(seg = dpmi_alloc(sizeof *minf / 16, &sel))) {
125 lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
130 dpmi_int(0x10, ®s);
132 if((regs.eax & 0xffff) != 0x4f) {
133 errormsg("vbe_mode_info (4f01) failed\n");
138 memcpy(minf, lowbuf, sizeof *minf);
143 void vbe_print_info(FILE *fp, struct vbe_info *vinf)
145 infomsg("vbe version: %u.%u\n", VBE_VER_MAJOR(vinf->ver), VBE_VER_MINOR(vinf->ver));
146 if(VBE_VER_MAJOR(vinf->ver) >= 2) {
147 infomsg("%s - %s (%s)\n", vinf->vendor, vinf->product, vinf->revstr);
148 if(vinf->caps & VBE_ACCEL) {
149 infomsg("vbe/af %d.%d\n", VBE_VER_MAJOR(vinf->accel_ver), VBE_VER_MINOR(vinf->accel_ver));
152 infomsg("oem: %s\n", vinf->oem_name);
154 infomsg("video memory: %dkb\n", vinf->vmem_blk * 64);
158 if(vinf->caps & VBE_8BIT_DAC) infomsg(" dac8");
159 if(vinf->caps & VBE_NON_VGA) infomsg(" non-vga");
160 if(vinf->caps & VBE_DAC_BLANK) infomsg(" dac-blank");
161 if(vinf->caps & VBE_ACCEL) infomsg(" af");
162 if(vinf->caps & VBE_MUSTLOCK) infomsg(" af-lock");
163 if(vinf->caps & VBE_HWCURSOR) infomsg(" af-curs");
164 if(vinf->caps & VBE_HWCLIP) infomsg(" af-clip");
165 if(vinf->caps & VBE_TRANSP_BLT) infomsg(" af-tblt");
169 infomsg("%d video modes available\n", NMODES(vinf));
170 if(vinf->caps & VBE_ACCEL) {
171 infomsg("%d accelerated (VBE/AF) modes available\n", NACCMODES(vinf));
176 void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf)
178 infomsg("%dx%d %dbpp", minf->xres, minf->yres, minf->bpp);
180 switch(minf->mem_model) {
181 case VBE_TYPE_DIRECT:
187 infomsg(" %d%d%d)", minf->rsize, minf->gsize, minf->bsize);
189 case VBE_TYPE_PLANAR:
190 infomsg(" (%d planes)", minf->num_planes);
192 case VBE_TYPE_PACKED:
193 infomsg(" (packed)");
196 infomsg(" (%dx%d cells)", minf->xcharsz, minf->ycharsz);
201 case VBE_TYPE_UNCHAIN:
202 infomsg(" (unchained-%d)", minf->num_planes);
205 infomsg(" %dpg", minf->num_img_pages);
207 if(minf->attr & VBE_ATTR_LFB) {
208 infomsg(" lfb@%lx", (unsigned long)minf->fb_addr);
210 infomsg(" (%dk gran)", (int)minf->win_gran);
214 if(minf->attr & VBE_ATTR_AVAIL) infomsg(" avail");
215 if(minf->attr & VBE_ATTR_OPTINFO) infomsg(" opt");
216 if(minf->attr & VBE_ATTR_TTY) infomsg(" tty");
217 if(minf->attr & VBE_ATTR_COLOR) infomsg(" color");
218 if(minf->attr & VBE_ATTR_GFX) infomsg(" gfx");
219 if(minf->attr & VBE_ATTR_NOTVGA) infomsg(" non-vga");
220 if(minf->attr & VBE_ATTR_BANKED) infomsg(" banked");
221 if(minf->attr & VBE_ATTR_LFB) infomsg(" lfb");
222 if(minf->attr & VBE_ATTR_DBLSCAN) infomsg(" dblscan");
223 if(minf->attr & VBE_ATTR_ILACE) infomsg(" ilace");
224 if(minf->attr & VBE_ATTR_TRIPLEBUF) infomsg(" trplbuf");
225 if(minf->attr & VBE_ATTR_STEREO) infomsg(" stereo");
226 if(minf->attr & VBE_ATTR_STEREO_2FB) infomsg(" stdual");
231 int vbe_setmode(uint16_t mode)
233 struct dpmi_regs regs = {0};
237 dpmi_int(0x10, ®s);
239 if((regs.eax & 0xffff) != 0x4f) {
243 cur_pitch = vbe_getpitch();
247 int vbe_setmode_crtc(uint16_t mode, struct vbe_crtc_info *crtc)
251 struct dpmi_regs regs = {0};
253 assert(sizeof *crtc == 59);
255 if(!(seg = dpmi_alloc((sizeof *crtc + 15) / 16, &sel))) {
258 lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
260 memcpy(lowbuf, crtc, sizeof *crtc);
265 dpmi_int(0x10, ®s);
269 if((regs.eax & 0xffff) != 0x4f) {
273 cur_pitch = vbe_getpitch();
277 int vbe_getmode(void)
279 struct dpmi_regs regs = {0};
282 dpmi_int(0x10, ®s);
284 if((regs.eax & 0xffff) != 0x4f) {
287 return regs.ebx & 0xffff;
290 int vbe_state_size(unsigned int flags)
292 struct dpmi_regs regs = {0};
297 dpmi_int(0x10, ®s);
298 if((regs.eax & 0xffff) != 0x4f) {
301 return (regs.ebx & 0xffff) * 64;
304 int vbe_save(void *stbuf, int sz, unsigned int flags)
308 struct dpmi_regs regs = {0};
310 if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) {
313 lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
316 regs.edx = 1; /* save */
319 dpmi_int(0x10, ®s);
320 if((regs.eax & 0xffff) != 0x4f) {
325 memcpy(stbuf, lowbuf, sz);
330 int vbe_restore(void *stbuf, int sz, unsigned int flags)
334 struct dpmi_regs regs = {0};
336 if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) {
339 lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
341 memcpy(lowbuf, stbuf, sz);
344 regs.edx = 2; /* restore */
347 dpmi_int(0x10, ®s);
349 if((regs.eax & 0xffff) != 0x4f) {
355 int vbe_setwin(int wid, int pos)
357 struct dpmi_regs regs;
359 if(wid & ~1) return -1;
364 dpmi_int(0x10, ®s);
366 if((regs.eax & 0xffff) != 0x4f) {
372 int vbe_getwin(int wid)
374 struct dpmi_regs regs;
376 if(wid & ~1) return -1;
380 dpmi_int(0x10, ®s);
382 if((regs.eax & 0xffff) != 0x4f) {
386 return regs.edx & 0xffff;
389 int vbe_setscanlen(int len_pix)
391 struct dpmi_regs regs;
394 regs.ebx = 0; /* set scanline length in pixels */
396 dpmi_int(0x10, ®s);
398 if((regs.eax & 0xffff) != 0x4f) {
402 cur_pitch = vbe_getpitch();
406 int vbe_getscanlen(void)
408 struct dpmi_regs regs;
411 regs.ebx = 1; /* get scanline length */
412 dpmi_int(0x10, ®s);
414 if((regs.eax & 0xffff) != 0x4f) {
420 int vbe_getpitch(void)
422 struct dpmi_regs regs;
425 regs.ebx = 1; /* get scanline length */
426 dpmi_int(0x10, ®s);
428 if((regs.eax & 0xffff) != 0x4f) {
434 int vbe_scanline_info(struct vbe_scanline_info *sinf)
436 struct dpmi_regs regs;
439 regs.ebx = 1; /* get scanline length */
440 dpmi_int(0x10, ®s);
442 if((regs.eax & 0xffff) != 0x4f) {
446 sinf->size = regs.ebx & 0xffff;
447 sinf->num_pixels = regs.ecx & 0xffff;
448 sinf->max_scanlines = regs.edx & 0xffff;
456 SDISP_SET_STEREO = 0x03,
457 SDISP_GETSCHED = 0x04,
458 SDISP_STEREO_ON = 0x05,
459 SDISP_STEREO_OFF = 0x06,
460 SDISP_SET_VBLANK = 0x80,
461 SDISP_ALTSET_VBLANK = 0x82,
462 SDISP_SET_STEREO_VBLANK = 0x83
465 int vbe_setdisp(int x, int y, int when)
467 struct dpmi_regs regs;
470 regs.ebx = (when == VBE_SWAP_VBLANK) ? SDISP_SET_VBLANK : SDISP_SET;
473 dpmi_int(0x10, ®s);
475 if((regs.eax & 0xffff) != 0x4f) {
481 int vbe_swap(uint32_t voffs, int when)
483 struct dpmi_regs regs;
492 /* XXX is this the only way? */
493 return vbe_setdisp(voffs % cur_pitch, voffs / cur_pitch, when);
495 case VBE_SWAP_VBLANK:
497 op = SDISP_ALTSET_VBLANK;
505 dpmi_int(0x10, ®s);
507 if((regs.eax & 0xffff) != 0x4f) {
513 int vbe_swap_pending(void)
515 struct dpmi_regs regs;
518 regs.ebx = SDISP_GETSCHED;
519 dpmi_int(0x10, ®s);
521 if((regs.eax & 0xffff) != 0x4f) {