11 uint32_t paddr = (uint32_t)(ptr); \
12 uint16_t pseg = paddr >> 16; \
13 uint16_t poffs = paddr & 0xffff; \
14 if(pseg == seg && poffs < 512) { \
15 paddr = ((uint32_t)seg << 4) + poffs; \
17 paddr = ((uint32_t)pseg << 4) + poffs; \
19 (ptr) = (void*)paddr; \
22 /* hijack the "VESA" sig field, to pre-cache number of modes */
23 #define NMODES(inf) *(uint16_t*)((inf)->sig)
24 #define NACCMODES(inf) *(uint16_t*)((inf)->sig + 2)
27 /* 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*)((uint32_t)seg << 4);
45 memcpy(lowbuf, "VBE2", 4);
50 dpmi_int(0x10, ®s);
52 if((regs.eax & 0xffff) != 0x4f) {
53 fprintf(stderr, "vbe_get_info (4f00) failed\n");
58 memcpy(info, lowbuf, sizeof *info);
61 FIXPTR(info->oem_name);
63 FIXPTR(info->product);
66 FIXPTR(info->accel_modes);
68 modeptr = info->modes;
69 while(*modeptr != 0xffff) {
70 if(modeptr - info->modes >= 256) {
71 modeptr = info->modes;
76 NMODES(info) = modeptr - info->modes;
78 if(info->caps & VBE_ACCEL) {
79 modeptr = info->accel_modes;
80 while(*modeptr != 0xffff) {
81 if(modeptr - info->accel_modes >= 256) {
82 modeptr = info->accel_modes;
87 NACCMODES(info) = modeptr - info->accel_modes;
92 int vbe_num_modes(struct vbe_info *info)
97 int vbe_mode_info(int mode, struct vbe_mode_info *minf)
102 struct dpmi_regs regs = {0};
104 assert(sizeof *minf == 256);
105 assert(offsetof(struct vbe_mode_info, max_pixel_clock) == 0x3e);
107 if(!(seg = dpmi_alloc(sizeof *minf / 16, &sel))) {
110 lowbuf = (void*)((uint32_t)seg << 4);
115 dpmi_int(0x10, ®s);
117 if((regs.eax & 0xffff) != 0x4f) {
118 fprintf(stderr, "vbe_mode_info (4f01) failed\n");
123 memcpy(minf, lowbuf, sizeof *minf);
128 void vbe_print_info(FILE *fp, struct vbe_info *vinf)
130 fprintf(fp, "vbe version: %u.%u\n", VBE_VER_MAJOR(vinf->ver), VBE_VER_MINOR(vinf->ver));
131 if(VBE_VER_MAJOR(vinf->ver) >= 2) {
132 fprintf(fp, "%s - %s (%s)\n", vinf->vendor, vinf->product, vinf->revstr);
133 if(vinf->caps & VBE_ACCEL) {
134 fprintf(fp, "vbe/af %d.%d\n", VBE_VER_MAJOR(vinf->accel_ver), VBE_VER_MINOR(vinf->accel_ver));
137 fprintf(fp, "oem: %s\n", vinf->oem_name);
139 fprintf(fp, "video memory: %dkb\n", vinf->vmem_blk * 64);
142 fprintf(fp, "caps:");
143 if(vinf->caps & VBE_8BIT_DAC) fprintf(fp, " dac8");
144 if(vinf->caps & VBE_NON_VGA) fprintf(fp, " non-vga");
145 if(vinf->caps & VBE_DAC_BLANK) fprintf(fp, " dac-blank");
146 if(vinf->caps & VBE_ACCEL) fprintf(fp, " af");
147 if(vinf->caps & VBE_MUSTLOCK) fprintf(fp, " af-lock");
148 if(vinf->caps & VBE_HWCURSOR) fprintf(fp, " af-curs");
149 if(vinf->caps & VBE_HWCLIP) fprintf(fp, " af-clip");
150 if(vinf->caps & VBE_TRANSP_BLT) fprintf(fp, " af-tblt");
154 fprintf(fp, "%d video modes available\n", NMODES(vinf));
155 if(vinf->caps & VBE_ACCEL) {
156 fprintf(fp, "%d accelerated (VBE/AF) modes available\n", NACCMODES(vinf));
161 void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf)
163 fprintf(fp, "%dx%d %dbpp", minf->xres, minf->yres, minf->bpp);
165 switch(minf->mem_model) {
166 case VBE_TYPE_DIRECT:
167 fprintf(fp, " (rgb");
170 fprintf(fp, " (yuv");
172 fprintf(fp, " %d%d%d)", minf->rsize, minf->gsize, minf->bsize);
174 case VBE_TYPE_PLANAR:
175 fprintf(fp, " (%d planes)", minf->num_planes);
177 case VBE_TYPE_PACKED:
178 fprintf(fp, " (packed)");
181 fprintf(fp, " (%dx%d cells)", minf->xcharsz, minf->ycharsz);
184 fprintf(fp, " (CGA)");
186 case VBE_TYPE_UNCHAIN:
187 fprintf(fp, " (unchained-%d)", minf->num_planes);
190 fprintf(fp, " %dpg", minf->num_img_pages);
192 if(minf->attr & VBE_ATTR_LFB) {
193 fprintf(fp, " lfb@%lx", (unsigned long)minf->fb_addr);
197 if(minf->attr & VBE_ATTR_AVAIL) fprintf(fp, " avail");
198 if(minf->attr & VBE_ATTR_OPTINFO) fprintf(fp, " opt");
199 if(minf->attr & VBE_ATTR_TTY) fprintf(fp, " tty");
200 if(minf->attr & VBE_ATTR_COLOR) fprintf(fp, " color");
201 if(minf->attr & VBE_ATTR_GFX) fprintf(fp, " gfx");
202 if(minf->attr & VBE_ATTR_NOTVGA) fprintf(fp, " non-vga");
203 if(minf->attr & VBE_ATTR_BANKED) fprintf(fp, " banked");
204 if(minf->attr & VBE_ATTR_LFB) fprintf(fp, " lfb");
205 if(minf->attr & VBE_ATTR_DBLSCAN) fprintf(fp, " dblscan");
206 if(minf->attr & VBE_ATTR_ILACE) fprintf(fp, " ilace");
207 if(minf->attr & VBE_ATTR_TRIPLEBUF) fprintf(fp, " trplbuf");
208 if(minf->attr & VBE_ATTR_STEREO) fprintf(fp, " stereo");
209 if(minf->attr & VBE_ATTR_STEREO_2FB) fprintf(fp, " stdual");
214 int vbe_setmode(uint16_t mode)
216 struct dpmi_regs regs = {0};
220 dpmi_int(0x10, ®s);
222 if((regs.eax & 0xffff) != 0x4f) {
228 int vbe_setmode_crtc(uint16_t mode, struct vbe_crtc_info *crtc)
232 struct dpmi_regs regs = {0};
234 assert(sizeof *crtc == 59);
236 if(!(seg = dpmi_alloc((sizeof *crtc + 15) / 16, &sel))) {
239 lowbuf = (void*)((uint32_t)seg << 4);
241 memcpy(lowbuf, crtc, sizeof *crtc);
246 dpmi_int(0x10, ®s);
250 if((regs.eax & 0xffff) != 0x4f) {
256 int vbe_getmode(void)
258 struct dpmi_regs regs = {0};
261 dpmi_int(0x10, ®s);
263 if((regs.eax & 0xffff) != 0x4f) {
266 return regs.ebx & 0xffff;
269 int vbe_state_size(unsigned int flags)
271 struct dpmi_regs regs = {0};
276 dpmi_int(0x10, ®s);
277 if((regs.eax & 0xffff) != 0x4f) {
280 return (regs.ebx & 0xffff) * 64;
283 int vbe_save(void *stbuf, int sz, unsigned int flags)
287 struct dpmi_regs regs = {0};
289 if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) {
292 lowbuf = (void*)((uint32_t)seg << 4);
295 regs.edx = 1; /* save */
298 dpmi_int(0x10, ®s);
299 if((regs.eax & 0xffff) != 0x4f) {
304 memcpy(stbuf, lowbuf, sz);
309 int vbe_restore(void *stbuf, int sz, unsigned int flags)
313 struct dpmi_regs regs = {0};
315 if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) {
318 lowbuf = (void*)((uint32_t)seg << 4);
320 memcpy(lowbuf, stbuf, sz);
323 regs.edx = 2; /* restore */
326 dpmi_int(0x10, ®s);
328 if((regs.eax & 0xffff) != 0x4f) {
334 int vbe_setwin(int wid, int pos)
336 struct dpmi_regs regs;
338 if(wid & ~1) return -1;
343 dpmi_int(0x10, ®s);
345 if((regs.eax & 0xffff) != 0x4f) {
351 int vbe_getwin(int wid)
353 struct dpmi_regs regs;
355 if(wid & ~1) return -1;
359 dpmi_int(0x10, ®s);
361 if((regs.eax & 0xffff) != 0x4f) {
365 return regs.edx & 0xffff;
368 int vbe_setscanlen(int len_pix)
370 struct dpmi_regs regs;
373 regs.ebx = 0; /* set scanline length in pixels */
375 dpmi_int(0x10, ®s);
377 if((regs.eax & 0xffff) != 0x4f) {
384 int vbe_getscanlen(void)
386 struct dpmi_regs regs;
389 regs.ebx = 1; /* get scanline length */
390 dpmi_int(0x10, ®s);
392 if((regs.eax & 0xffff) != 0x4f) {
398 int vbe_getpitch(void)
400 struct dpmi_regs regs;
403 regs.ebx = 1; /* get scanline length */
404 dpmi_int(0x10, ®s);
406 if((regs.eax & 0xffff) != 0x4f) {
412 int vbe_scanline_info(struct vbe_scanline_info *sinf)
414 struct dpmi_regs regs;
417 regs.ebx = 1; /* get scanline length */
418 dpmi_int(0x10, ®s);
420 if((regs.eax & 0xffff) != 0x4f) {
424 sinf->size = regs.ebx & 0xffff;
425 sinf->num_pixels = regs.ecx & 0xffff;
426 sinf->max_scanlines = regs.edx & 0xffff;
434 SDISP_SET_STEREO = 0x03,
435 SDISP_GETSCHED = 0x04,
436 SDISP_STEREO_ON = 0x05,
437 SDISP_STEREO_OFF = 0x06,
438 SDISP_SET_VBLANK = 0x80,
439 SDISP_ALTSET_VBLANK = 0x82,
440 SDISP_SET_STEREO_VBLANK = 0x83
443 int vbe_setdisp(int x, int y, int when)
445 struct dpmi_regs regs;
448 regs.ebx = (when == VBE_SWAP_VBLANK) ? SDISP_SET_VBLANK : SDISP_SET;
451 dpmi_int(0x10, ®s);
453 if((regs.eax & 0xffff) != 0x4f) {
459 int vbe_swap(uint32_t voffs, int when)
461 struct dpmi_regs regs;
470 /* XXX is this the only way? */
471 return vbe_setdisp(voffs % cur_pitch, voffs / cur_pitch, when);
473 case VBE_SWAP_VBLANK:
475 op = SDISP_ALTSET_VBLANK;
483 dpmi_int(0x10, ®s);
485 if((regs.eax & 0xffff) != 0x4f) {
491 int vbe_swap_pending(void)
493 struct dpmi_regs regs;
496 regs.ebx = SDISP_GETSCHED;
497 dpmi_int(0x10, ®s);
499 if((regs.eax & 0xffff) != 0x4f) {