#include <stdio.h>
#include <string.h>
-#include <conio.h>
+#include <stddef.h>
+#include <assert.h>
#include "vbe.h"
#include "cdpmi.h"
-#include "inttypes.h"
-#ifdef __DJGPP__
-#include <pc.h>
-#include <sys/nearptr.h>
-#define SEG_ADDR(s) (((uint32_t)(s) << 4) - __djgpp_base_address)
-
-#define outp(p, v) outportb(p, v)
-#else
-#define SEG_ADDR(s) ((uint32_t)(s) << 4)
-#endif
-
-/* VGA DAC registers used for palette setting in 8bpp modes */
-#define VGA_DAC_STATE 0x3c7
-#define VGA_DAC_ADDR_RD 0x3c7
-#define VGA_DAC_ADDR_WR 0x3c8
-#define VGA_DAC_DATA 0x3c9
-
-#define MODE_LFB (1 << 14)
+#define FIXPTR(ptr) \
+ do { \
+ uint32_t paddr = (uint32_t)(ptr); \
+ uint16_t pseg = paddr >> 16; \
+ uint16_t poffs = paddr & 0xffff; \
+ if(pseg == seg && poffs < 512) { \
+ paddr = ((uint32_t)seg << 4) + poffs; \
+ } else { \
+ paddr = ((uint32_t)pseg << 4) + poffs; \
+ } \
+ (ptr) = (void*)paddr; \
+ } while(0)
+
+/* hijack the "VESA" sig field, to pre-cache number of modes */
+#define NMODES(inf) *(uint16_t*)((inf)->sig)
+#define NACCMODES(inf) *(uint16_t*)((inf)->sig + 2)
+
+int vbe_info(struct vbe_info *info)
+{
+ int i, num;
+ void *lowbuf;
+ uint16_t seg, sel;
+ uint16_t *modeptr;
+ struct dpmi_regs regs = {0};
+ assert(sizeof *info == 512);
-struct vbe_info *vbe_get_info(void)
-{
- static uint16_t info_block_seg, info_block_selector;
- static struct vbe_info *info;
- struct dpmi_real_regs regs;
-
- if(!info) {
- /* allocate 32 paragraphs (512 bytes) */
- info_block_seg = dpmi_alloc(32, &info_block_selector);
- info = (struct vbe_info*)SEG_ADDR(info_block_seg);
+ if(!(seg = dpmi_alloc(sizeof *info / 16, &sel))) {
+ return -1;
}
+ lowbuf = (void*)((uint32_t)seg << 4);
- memcpy(info->sig, "VBE2", 4);
+ memcpy(lowbuf, "VBE2", 4);
- memset(®s, 0, sizeof regs);
- regs.es = info_block_seg;
regs.eax = 0x4f00;
+ regs.es = seg;
+ regs.edi = 0;
+ dpmi_int(0x10, ®s);
- dpmi_real_int(0x10, ®s);
-
- return info;
-}
-
-struct vbe_mode_info *vbe_get_mode_info(int mode)
-{
- static uint16_t mode_info_seg, mode_info_selector;
- static struct vbe_mode_info *mi;
- struct dpmi_real_regs regs;
-
- if(!mi) {
- /* allocate 16 paragraphs (256 bytes) */
- mode_info_seg = dpmi_alloc(16, &mode_info_selector);
- mi = (struct vbe_mode_info*)SEG_ADDR(mode_info_seg);
+ if((regs.eax & 0xffff) != 0x4f) {
+ fprintf(stderr, "vbe_get_info (4f00) failed\n");
+ dpmi_free(sel);
+ return -1;
}
- memset(®s, 0, sizeof regs);
- regs.es = mode_info_seg;
- regs.eax = 0x4f01;
- regs.ecx = mode;
- regs.es = mode_info_seg;
-
- dpmi_real_int(0x10, ®s);
- if(regs.eax & 0xff00) {
- return 0;
+ memcpy(info, lowbuf, sizeof *info);
+ dpmi_free(sel);
+
+ FIXPTR(info->oem_name);
+ FIXPTR(info->vendor);
+ FIXPTR(info->product);
+ FIXPTR(info->revstr);
+ FIXPTR(info->modes);
+ FIXPTR(info->accel_modes);
+
+ modeptr = info->modes;
+ while(*modeptr != 0xffff) {
+ if(modeptr - info->modes >= 256) {
+ modeptr = info->modes;
+ break;
+ }
+ modeptr++;
}
-
- return mi;
-}
-
-int vbe_set_mode(int mode)
-{
- struct dpmi_real_regs regs;
-
- memset(®s, 0, sizeof regs);
- regs.eax = 0x4f02;
- regs.ebx = mode;
- dpmi_real_int(0x10, ®s);
-
- if(regs.eax == 0x100) {
- return -1;
+ NMODES(info) = modeptr - info->modes;
+
+ if(info->caps & VBE_ACCEL) {
+ modeptr = info->accel_modes;
+ while(*modeptr != 0xffff) {
+ if(modeptr - info->accel_modes >= 256) {
+ modeptr = info->accel_modes;
+ break;
+ }
+ modeptr++;
+ }
+ NACCMODES(info) = modeptr - info->accel_modes;
}
return 0;
}
-int vbe_set_palette_bits(int bits)
+int vbe_num_modes(struct vbe_info *info)
{
- struct dpmi_real_regs regs;
-
- memset(®s, 0, sizeof regs);
- regs.eax = 0x4f08;
- regs.ebx = bits << 8; /* bits in bh */
- dpmi_real_int(0x10, ®s);
-
- if(((regs.eax >> 8) & 0xff) == 3) {
- return -1;
- }
- return regs.ebx >> 8 & 0xff; /* new color bits in bh */
+ return NMODES(info);
}
-/* TODO: implement palette setting through the VBE2 interface for
- * non-VGA displays (actually don't).
- */
-void vbe_set_palette(int idx, int *col, int count, int bits)
+int vbe_mode_info(int mode, struct vbe_mode_info *minf)
{
- int i, shift = 8 - bits;
+ int i, num;
+ void *lowbuf;
+ uint16_t seg, sel;
+ struct dpmi_regs regs = {0};
- outp(VGA_DAC_ADDR_WR, idx);
+ assert(sizeof *minf == 256);
+ assert(offsetof(struct vbe_mode_info, max_pixel_clock) == 0x3e);
- for(i=0; i<count; i++) {
- unsigned char r = *col++;
- unsigned char g = *col++;
- unsigned char b = *col++;
-
- if(shift) {
- r >>= shift;
- g >>= shift;
- b >>= shift;
- }
-
- outp(VGA_DAC_DATA, r);
- outp(VGA_DAC_DATA, g);
- outp(VGA_DAC_DATA, b);
+ if(!(seg = dpmi_alloc(sizeof *minf / 16, &sel))) {
+ return -1;
}
-}
-
-int vbe_set_disp_start(int x, int y, int when)
-{
- struct dpmi_real_regs regs;
+ lowbuf = (void*)((uint32_t)seg << 4);
- memset(®s, 0, sizeof regs);
- regs.eax = 0x4f07;
- regs.ebx = when & 0xffff;
- regs.ecx = x & 0xffff;
- regs.edx = y & 0xffff;
- dpmi_real_int(0x10, ®s);
+ regs.eax = 0x4f01;
+ regs.ecx = mode;
+ regs.es = seg;
+ dpmi_int(0x10, ®s);
- if(regs.eax == 0x100) {
+ if((regs.eax & 0xffff) != 0x4f) {
+ fprintf(stderr, "vbe_mode_info (4f01) failed\n");
+ dpmi_free(sel);
return -1;
}
+
+ memcpy(minf, lowbuf, sizeof *minf);
+ dpmi_free(sel);
return 0;
}
-int vbe_set_scanlen(int len, int mode)
+void vbe_print_info(FILE *fp, struct vbe_info *vinf)
{
- struct dpmi_real_regs regs;
-
- memset(®s, 0, sizeof regs);
- regs.eax = 0x4f06;
- regs.ebx = mode;
- regs.ecx = len & 0xffff;
- dpmi_real_int(0x10, ®s);
-
- if(regs.eax == 0x100) {
- return -1;
+ fprintf(fp, "vbe version: %u.%u\n", VBE_VER_MAJOR(vinf->ver), VBE_VER_MINOR(vinf->ver));
+ if(VBE_VER_MAJOR(vinf->ver) >= 2) {
+ fprintf(fp, "%s - %s (%s)\n", vinf->vendor, vinf->product, vinf->revstr);
+ if(vinf->caps & VBE_ACCEL) {
+ fprintf(fp, "vbe/af %d.%d\n", VBE_VER_MAJOR(vinf->accel_ver), VBE_VER_MINOR(vinf->accel_ver));
+ }
+ } else {
+ fprintf(fp, "oem: %s\n", vinf->oem_name);
}
- return regs.ecx & 0xffff;
-}
-
-int vbe_get_scanlen(int mode)
-{
- int res;
- struct dpmi_real_regs regs;
-
- memset(®s, 0, sizeof regs);
- regs.eax = 0x4f06;
- regs.ebx = 1;
- dpmi_real_int(0x10, ®s);
-
- if(regs.eax == 0x100) {
- return -1;
+ fprintf(fp, "video memory: %dkb\n", vinf->vmem_blk * 64);
+
+ if(vinf->caps) {
+ fprintf(fp, "caps:");
+ if(vinf->caps & VBE_8BIT_DAC) fprintf(fp, " dac8");
+ if(vinf->caps & VBE_NON_VGA) fprintf(fp, " non-vga");
+ if(vinf->caps & VBE_DAC_BLANK) fprintf(fp, " dac-blank");
+ if(vinf->caps & VBE_ACCEL) fprintf(fp, " af");
+ if(vinf->caps & VBE_MUSTLOCK) fprintf(fp, " af-lock");
+ if(vinf->caps & VBE_HWCURSOR) fprintf(fp, " af-curs");
+ if(vinf->caps & VBE_HWCLIP) fprintf(fp, " af-clip");
+ if(vinf->caps & VBE_TRANSP_BLT) fprintf(fp, " af-tblt");
+ fprintf(fp, "\n");
}
- if(mode == VBE_SCANLEN_PIXELS) {
- res = regs.ecx & 0xffff;
- } else {
- res = regs.ebx & 0xffff;
+ fprintf(fp, "%d video modes available\n", NMODES(vinf));
+ if(vinf->caps & VBE_ACCEL) {
+ fprintf(fp, "%d accelerated (VBE/AF) modes available\n", NACCMODES(vinf));
}
- return res;
+ fflush(fp);
}
-
-static unsigned int get_mask(int sz, int pos)
+void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf)
{
- unsigned int i, mask = 0;
+ fprintf(fp, "%dx%d %dbpp", minf->xres, minf->yres, minf->bpp);
+
+ switch(minf->mem_model) {
+ case VBE_TYPE_DIRECT:
+ fprintf(fp, " (rgb");
+ if(0) {
+ case VBE_TYPE_YUV:
+ fprintf(fp, " (yuv");
+ }
+ fprintf(fp, " %d%d%d)", minf->rsize, minf->gsize, minf->bsize);
+ break;
+ case VBE_TYPE_PLANAR:
+ fprintf(fp, " (%d planes)", minf->num_planes);
+ break;
+ case VBE_TYPE_PACKED:
+ fprintf(fp, " (packed)");
+ break;
+ case VBE_TYPE_TEXT:
+ fprintf(fp, " (%dx%d cells)", minf->xcharsz, minf->ycharsz);
+ break;
+ case VBE_TYPE_CGA:
+ fprintf(fp, " (CGA)");
+ break;
+ case VBE_TYPE_UNCHAIN:
+ fprintf(fp, " (unchained-%d)", minf->num_planes);
+ break;
+ }
+ fprintf(fp, " %dpg", minf->num_img_pages);
- for(i=0; i<sz; i++) {
- mask |= 1 << i;
+ if(minf->attr & VBE_ATTR_LFB) {
+ fprintf(fp, " lfb@%lx", (unsigned long)minf->fb_addr);
}
- return mask << pos;
-}
-void print_mode_info(FILE *fp, struct vbe_mode_info *mi)
-{
- fprintf(fp, "resolution: %dx%d\n", mi->xres, mi->yres);
- fprintf(fp, "color depth: %d\n", mi->bpp);
- fprintf(fp, "mode attributes: %x\n", mi->mode_attr);
- fprintf(fp, "bytes per scanline: %d\n", mi->scanline_bytes);
- fprintf(fp, "number of planes: %d\n", (int)mi->num_planes);
- fprintf(fp, "number of banks: %d\n", (int)mi->num_banks);
- fprintf(fp, "mem model: %d\n", (int)mi->mem_model);
- fprintf(fp, "red bits: %d (mask: %x)\n", (int)mi->rmask_size, get_mask(mi->rmask_size, mi->rpos));
- fprintf(fp, "green bits: %d (mask: %x)\n", (int)mi->gmask_size, get_mask(mi->gmask_size, mi->gpos));
- fprintf(fp, "blue bits: %d (mask: %x)\n", (int)mi->bmask_size, get_mask(mi->bmask_size, mi->bpos));
- fprintf(fp, "framebuffer address: %x\n", (unsigned int)mi->fb_addr);
+ fprintf(fp, " [");
+ if(minf->attr & VBE_ATTR_AVAIL) fprintf(fp, " avail");
+ if(minf->attr & VBE_ATTR_OPTINFO) fprintf(fp, " opt");
+ if(minf->attr & VBE_ATTR_TTY) fprintf(fp, " tty");
+ if(minf->attr & VBE_ATTR_COLOR) fprintf(fp, " color");
+ if(minf->attr & VBE_ATTR_GFX) fprintf(fp, " gfx");
+ if(minf->attr & VBE_ATTR_NOTVGA) fprintf(fp, " non-vga");
+ if(minf->attr & VBE_ATTR_BANKED) fprintf(fp, " banked");
+ if(minf->attr & VBE_ATTR_LFB) fprintf(fp, " lfb");
+ if(minf->attr & VBE_ATTR_2XSCAN) fprintf(fp, " dblscan");
+ if(minf->attr & VBE_ATTR_ILACE) fprintf(fp, " ilace");
+ if(minf->attr & VBE_ATTR_TRIPLEBUF) fprintf(fp, " trplbuf");
+ if(minf->attr & VBE_ATTR_STEREO) fprintf(fp, " stereo");
+ if(minf->attr & VBE_ATTR_STEREO_2FB) fprintf(fp, " stdual");
+ fprintf(fp, " ]\n");
+ fflush(fp);
}