/* ** thinlib (c) 2001 Matthew Conte (matt@conte.com) ** ** ** tl_vesa.c ** ** VESA code. ** ** $Id: $ */ #include #include #include #include #include #include #include "tl_types.h" #include "tl_log.h" #include "tl_bmp.h" #include "tl_djgpp.h" #include "tl_video.h" #include "tl_vesa.h" #define __PACKED__ __attribute__ ((packed)) /* VESA information block structure */ typedef struct vesainfo_s { char VESASignature[4] __PACKED__; uint16 VESAVersion __PACKED__; uint32 OEMStringPtr __PACKED__; char Capabilities[4] __PACKED__; uint32 VideoModePtr __PACKED__; uint16 TotalMemory __PACKED__; uint16 OemSoftwareRev __PACKED__; uint32 OemVendorNamePtr __PACKED__; uint32 OemProductNamePtr __PACKED__; uint32 OemProductRevPtr __PACKED__; uint8 Reserved[222] __PACKED__; } vesainfo_t; /* SuperVGA mode information block */ typedef struct modeinfo_s { uint16 ModeAttributes __PACKED__; uint8 WinAAttributes __PACKED__; uint8 WinBAttributes __PACKED__; uint16 WinGranularity __PACKED__; uint16 WinSize __PACKED__; uint16 WinASegment __PACKED__; uint16 WinBSegment __PACKED__; uint32 WinFuncPtr __PACKED__; uint16 BytesPerScanLine __PACKED__; uint16 XResolution __PACKED__; uint16 YResolution __PACKED__; uint8 XCharSize __PACKED__; uint8 YCharSize __PACKED__; uint8 NumberOfPlanes __PACKED__; uint8 BitsPerPixel __PACKED__; uint8 NumberOfBanks __PACKED__; uint8 MemoryModel __PACKED__; uint8 BankSize __PACKED__; uint8 NumberOfImagePages __PACKED__; uint8 Reserved_page __PACKED__; uint8 RedMaskSize __PACKED__; uint8 RedMaskPos __PACKED__; uint8 GreenMaskSize __PACKED__; uint8 GreenMaskPos __PACKED__; uint8 BlueMaskSize __PACKED__; uint8 BlueMaskPos __PACKED__; uint8 ReservedMaskSize __PACKED__; uint8 ReservedMaskPos __PACKED__; uint8 DirectColorModeInfo __PACKED__; /* VBE 2.0 extensions */ uint32 PhysBasePtr __PACKED__; uint32 OffScreenMemOffset __PACKED__; uint16 OffScreenMemSize __PACKED__; /* VBE 3.0 extensions */ uint16 LinBytesPerScanLine __PACKED__; uint8 BnkNumberOfPages __PACKED__; uint8 LinNumberOfPages __PACKED__; uint8 LinRedMaskSize __PACKED__; uint8 LinRedFieldPos __PACKED__; uint8 LinGreenMaskSize __PACKED__; uint8 LinGreenFieldPos __PACKED__; uint8 LinBlueMaskSize __PACKED__; uint8 LinBlueFieldPos __PACKED__; uint8 LinRsvdMaskSize __PACKED__; uint8 LinRsvdFieldPos __PACKED__; uint32 MaxPixelClock __PACKED__; uint8 Reserved[190] __PACKED__; } modeinfo_t; #define MASK_LINEAR(addr) (addr & 0x000FFFFF) #define RM_TO_LINEAR(addr) (((addr & 0xFFFF0000) >> 12) + (addr & 0xFFFF)) #define RM_OFFSET(addr) (addr & 0xF) #define RM_SEGMENT(addr) ((addr >> 4) & 0xFFFF) #define VBE_LINEAR_ADDR 0x4000 #define VBE_LINEAR_AVAIL 0x0080 #define VBE_INT 0x10 #define VBE_SUCCESS 0x004F #define VBE_FUNC_DETECT 0x4F00 #define VBE_FUNC_GETMODEINFO 0x4F01 #define VBE_FUNC_SETMODE 0x4F02 #define VBE_FUNC_GETMODE 0x4F03 #define VBE_FUNC_FLIPPAGE 0x4F07 #define MAX_NUM_MODES 256 short int vid_selector = -1; static uint16 modelist[MAX_NUM_MODES]; static bitmap_t *screen = NULL; static bitmap_t *hardware = NULL; static int total_memory = 0; static bool vesa_hardware = false; /* look for vesa */ static int vesa_detect(void) { vesainfo_t vesa_info; __dpmi_regs regs; long list_ptr; int mode_pos; /* Use DOS transfer buffer to hold VBE info */ THIN_ASSERT(sizeof(vesainfo_t) < _go32_info_block.size_of_transfer_buffer); memset(®s, 0, sizeof(__dpmi_regs)); strncpy(vesa_info.VESASignature, "VBE2", 4); dosmemput(&vesa_info, sizeof(vesainfo_t), MASK_LINEAR(__tb)); regs.x.ax = VBE_FUNC_DETECT; regs.x.es = RM_SEGMENT(__tb); regs.x.di = RM_OFFSET(__tb); __dpmi_int(VBE_INT, ®s); if (VBE_SUCCESS != regs.x.ax) return -1; dosmemget(MASK_LINEAR(__tb), sizeof(vesainfo_t), &vesa_info); if (strncmp(vesa_info.VESASignature, "VESA", 4) != 0) return -1; /* check to see if linear framebuffer is available */ if ((vesa_info.VESAVersion >> 8) < 2) { thin_printf("thinlib.vesa: no linear framebuffer available\n"); return -1; } /* build list of available modes */ memset(&modelist, 0, MAX_NUM_MODES * sizeof(uint16)); mode_pos = 0; list_ptr = RM_TO_LINEAR(vesa_info.VideoModePtr); while (1) { uint16 mode; dosmemget(list_ptr + mode_pos * 2, 2, &mode); if (0xFFFF == mode) { modelist[mode_pos] = 0; break; } modelist[mode_pos++] = mode; } total_memory = vesa_info.TotalMemory; return 0; } static int vesa_getmodeinfo(uint16 mode, modeinfo_t *modeinfo) { __dpmi_regs regs; THIN_ASSERT(sizeof(modeinfo_t) < _go32_info_block.size_of_transfer_buffer); memset(®s, 0, sizeof(regs)); regs.x.ax = VBE_FUNC_GETMODEINFO; regs.x.cx = mode; regs.x.es = RM_SEGMENT(__tb); regs.x.di = RM_OFFSET(__tb); __dpmi_int(VBE_INT, ®s); if (VBE_SUCCESS != regs.x.ax) return -1; dosmemget(MASK_LINEAR(__tb), sizeof(modeinfo_t), modeinfo); return 0; } static uint16 vesa_findmode(int width, int height, int bpp) { modeinfo_t mode_info; uint16 mode; int mode_pos; for (mode_pos = 0; ; mode_pos++) { mode = modelist[mode_pos]; if (0 == mode) break; if (vesa_getmodeinfo(mode, &mode_info)) break; /* we are definitely screwed */ if (mode_info.XResolution == width && mode_info.YResolution == height && mode_info.BitsPerPixel == bpp) { return mode; } } return 0; } int thin_vesa_setmode(int width, int height, int bpp) { uint16 mode; __dpmi_regs regs; __dpmi_meminfo mi; modeinfo_t mode_info; unsigned int address; mode = vesa_findmode(width, height, bpp); if (0 == mode) { thin_printf("thinlib.vesa: yikes, couldn't find mode\n"); return -1; } if (vesa_getmodeinfo(mode, &mode_info)) { thin_printf("thinlib.vesa: error in vesa_getmodeinfo\n"); return -1; } mi.size = mode_info.BytesPerScanLine * mode_info.YResolution; mi.address = mode_info.PhysBasePtr; if (-1 == __dpmi_physical_address_mapping(&mi)) { thin_printf("thinlib.vesa: error in __dpmi_physical_address_mapping\n"); return -1; } if (false == vesa_hardware) { vid_selector = __dpmi_allocate_ldt_descriptors(1); if (-1 == vid_selector) { thin_printf("thinlib.vesa: error in __dpmi_allocate_ldt_descriptors\n"); return -1; } /* paranoid */ if (-1 == __dpmi_set_descriptor_access_rights(vid_selector, 0x40f3)) { thin_printf("thinlib.vesa: error in __dpmi_set_descriptor_access_rights\n"); return -1; } if (-1 == __dpmi_set_segment_base_address(vid_selector, mi.address)) { thin_printf("thinlib.vesa: error in __dpmi_set_segment_base_address\n"); return -1; } if (-1 == __dpmi_set_segment_limit(vid_selector, total_memory << 16 | 0xfff)) { thin_printf("thinlib.vesa: error in __dpmi_set_segment_limit\n"); return -1; } } memset(®s, 0, sizeof(regs)); regs.x.ax = VBE_FUNC_SETMODE; regs.x.bx = mode | VBE_LINEAR_ADDR; __dpmi_int(VBE_INT, ®s); if (VBE_SUCCESS != regs.x.ax) { thin_printf("thinlib.vesa: vesa dpmi int failed\n"); return -1; } if (false == vesa_hardware) address = 0; else address = mi.address; if (NULL != screen) thin_bmp_destroy(&screen); if (vesa_hardware) { screen = thin_bmp_createhw((uint8 *) THIN_PHYSICAL_ADDR(address), mode_info.XResolution, mode_info.YResolution, mode_info.BitsPerPixel, mode_info.XResolution); if (NULL == screen) { thin_printf("thinlib.vesa: failed creating hardware surface\n"); return -1; } } else { if (NULL != hardware) thin_bmp_destroy(&hardware); hardware = thin_bmp_createhw((uint8 *) address, mode_info.XResolution, mode_info.YResolution, mode_info.BitsPerPixel, mode_info.XResolution); if (NULL == hardware) { thin_printf("thinlib.vesa: failed creating hardware surface\n"); return -1; } screen = thin_bmp_create(mode_info.XResolution, mode_info.YResolution, mode_info.BitsPerPixel, 0); if (NULL == screen) { thin_printf("thinlib.vesa: failed creating software surface\n"); return -1; } } return 0; } void thin_vesa_shutdown(void) { __dpmi_regs regs; /* set text mode */ memset(®s, 0, sizeof(regs)); regs.x.ax = 0x0003; __dpmi_int(VBE_INT, ®s); if (NULL != screen) thin_bmp_destroy(&screen); if (NULL != hardware) thin_bmp_destroy(&hardware); } int thin_vesa_init(int width, int height, int bpp, int param) { screen = NULL; hardware = NULL; /* check to see if VESA card is present */ if (vesa_detect()) return -1; if (thinlib_nearptr && (param & THIN_VIDEO_HWSURFACE)) vesa_hardware = true; else vesa_hardware = false; return thin_vesa_setmode(width, height, bpp); } bitmap_t *thin_vesa_lockwrite(void) { return screen; } void thin_vesa_freewrite(int num_dirties, rect_t *dirty_rects) { UNUSED(num_dirties); UNUSED(dirty_rects); /* if we don't have a hardware surface, blat it out */ if (false == vesa_hardware) { _movedatal(_my_ds(), (unsigned) screen->line[0], vid_selector, (unsigned) hardware->line[0], hardware->pitch * hardware->height / 4); } } /* ** $Log: $ */