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*)phys_to_virt(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*)phys_to_virt((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*)phys_to_virt((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);
195 fprintf(fp, " %xkb/bank", (unsigned int)minf->bank_size);
199 if(minf->attr & VBE_ATTR_AVAIL) fprintf(fp, " avail");
200 if(minf->attr & VBE_ATTR_OPTINFO) fprintf(fp, " opt");
201 if(minf->attr & VBE_ATTR_TTY) fprintf(fp, " tty");
202 if(minf->attr & VBE_ATTR_COLOR) fprintf(fp, " color");
203 if(minf->attr & VBE_ATTR_GFX) fprintf(fp, " gfx");
204 if(minf->attr & VBE_ATTR_NOTVGA) fprintf(fp, " non-vga");
205 if(minf->attr & VBE_ATTR_BANKED) fprintf(fp, " banked");
206 if(minf->attr & VBE_ATTR_LFB) fprintf(fp, " lfb");
207 if(minf->attr & VBE_ATTR_DBLSCAN) fprintf(fp, " dblscan");
208 if(minf->attr & VBE_ATTR_ILACE) fprintf(fp, " ilace");
209 if(minf->attr & VBE_ATTR_TRIPLEBUF) fprintf(fp, " trplbuf");
210 if(minf->attr & VBE_ATTR_STEREO) fprintf(fp, " stereo");
211 if(minf->attr & VBE_ATTR_STEREO_2FB) fprintf(fp, " stdual");
216 int vbe_setmode(uint16_t mode)
218 struct dpmi_regs regs = {0};
222 dpmi_int(0x10, ®s);
224 if((regs.eax & 0xffff) != 0x4f) {
228 cur_pitch = vbe_getpitch();
232 int vbe_setmode_crtc(uint16_t mode, struct vbe_crtc_info *crtc)
236 struct dpmi_regs regs = {0};
238 assert(sizeof *crtc == 59);
240 if(!(seg = dpmi_alloc((sizeof *crtc + 15) / 16, &sel))) {
243 lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
245 memcpy(lowbuf, crtc, sizeof *crtc);
250 dpmi_int(0x10, ®s);
254 if((regs.eax & 0xffff) != 0x4f) {
258 cur_pitch = vbe_getpitch();
262 int vbe_getmode(void)
264 struct dpmi_regs regs = {0};
267 dpmi_int(0x10, ®s);
269 if((regs.eax & 0xffff) != 0x4f) {
272 return regs.ebx & 0xffff;
275 int vbe_state_size(unsigned int flags)
277 struct dpmi_regs regs = {0};
282 dpmi_int(0x10, ®s);
283 if((regs.eax & 0xffff) != 0x4f) {
286 return (regs.ebx & 0xffff) * 64;
289 int vbe_save(void *stbuf, int sz, unsigned int flags)
293 struct dpmi_regs regs = {0};
295 if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) {
298 lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
301 regs.edx = 1; /* save */
304 dpmi_int(0x10, ®s);
305 if((regs.eax & 0xffff) != 0x4f) {
310 memcpy(stbuf, lowbuf, sz);
315 int vbe_restore(void *stbuf, int sz, unsigned int flags)
319 struct dpmi_regs regs = {0};
321 if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) {
324 lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
326 memcpy(lowbuf, stbuf, sz);
329 regs.edx = 2; /* restore */
332 dpmi_int(0x10, ®s);
334 if((regs.eax & 0xffff) != 0x4f) {
340 int vbe_setwin(int wid, int pos)
342 struct dpmi_regs regs;
344 if(wid & ~1) return -1;
349 dpmi_int(0x10, ®s);
351 if((regs.eax & 0xffff) != 0x4f) {
357 int vbe_getwin(int wid)
359 struct dpmi_regs regs;
361 if(wid & ~1) return -1;
365 dpmi_int(0x10, ®s);
367 if((regs.eax & 0xffff) != 0x4f) {
371 return regs.edx & 0xffff;
374 int vbe_setscanlen(int len_pix)
376 struct dpmi_regs regs;
379 regs.ebx = 0; /* set scanline length in pixels */
381 dpmi_int(0x10, ®s);
383 if((regs.eax & 0xffff) != 0x4f) {
387 cur_pitch = vbe_getpitch();
391 int vbe_getscanlen(void)
393 struct dpmi_regs regs;
396 regs.ebx = 1; /* get scanline length */
397 dpmi_int(0x10, ®s);
399 if((regs.eax & 0xffff) != 0x4f) {
405 int vbe_getpitch(void)
407 struct dpmi_regs regs;
410 regs.ebx = 1; /* get scanline length */
411 dpmi_int(0x10, ®s);
413 if((regs.eax & 0xffff) != 0x4f) {
419 int vbe_scanline_info(struct vbe_scanline_info *sinf)
421 struct dpmi_regs regs;
424 regs.ebx = 1; /* get scanline length */
425 dpmi_int(0x10, ®s);
427 if((regs.eax & 0xffff) != 0x4f) {
431 sinf->size = regs.ebx & 0xffff;
432 sinf->num_pixels = regs.ecx & 0xffff;
433 sinf->max_scanlines = regs.edx & 0xffff;
441 SDISP_SET_STEREO = 0x03,
442 SDISP_GETSCHED = 0x04,
443 SDISP_STEREO_ON = 0x05,
444 SDISP_STEREO_OFF = 0x06,
445 SDISP_SET_VBLANK = 0x80,
446 SDISP_ALTSET_VBLANK = 0x82,
447 SDISP_SET_STEREO_VBLANK = 0x83
450 int vbe_setdisp(int x, int y, int when)
452 struct dpmi_regs regs;
455 regs.ebx = (when == VBE_SWAP_VBLANK) ? SDISP_SET_VBLANK : SDISP_SET;
458 dpmi_int(0x10, ®s);
460 if((regs.eax & 0xffff) != 0x4f) {
466 int vbe_swap(uint32_t voffs, int when)
468 struct dpmi_regs regs;
477 /* XXX is this the only way? */
478 return vbe_setdisp(voffs % cur_pitch, voffs / cur_pitch, when);
480 case VBE_SWAP_VBLANK:
482 op = SDISP_ALTSET_VBLANK;
490 dpmi_int(0x10, ®s);
492 if((regs.eax & 0xffff) != 0x4f) {
498 int vbe_swap_pending(void)
500 struct dpmi_regs regs;
503 regs.ebx = SDISP_GETSCHED;
504 dpmi_int(0x10, ®s);
506 if((regs.eax & 0xffff) != 0x4f) {