/* * Copyright (C) 2002-2007 The DOSBox Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* $Id: int10_vesa.cpp,v 1.27 2007/06/12 20:22:09 c2woody Exp $ */ #include #include #include "dosbox.h" #include "callback.h" #include "regs.h" #include "mem.h" #include "inout.h" #include "int10.h" #include "dos_inc.h" static struct { Bitu setwindow; Bitu pmStart; Bitu pmWindow; Bitu pmPalette; } callback; static char string_oem[]="S3 Incorporated. Trio64"; static char string_vendorname[]="DOSBox Development Team"; static char string_productname[]="DOSBox - The DOS Emulator"; static char string_productrev[]="DOSBox "VERSION; #ifdef _MSC_VER #pragma pack (1) #endif struct MODE_INFO{ Bit16u ModeAttributes; Bit8u WinAAttributes; Bit8u WinBAttributes; Bit16u WinGranularity; Bit16u WinSize; Bit16u WinASegment; Bit16u WinBSegment; Bit32u WinFuncPtr; Bit16u BytesPerScanLine; Bit16u XResolution; Bit16u YResolution; Bit8u XCharSize; Bit8u YCharSize; Bit8u NumberOfPlanes; Bit8u BitsPerPixel; Bit8u NumberOfBanks; Bit8u MemoryModel; Bit8u BankSize; Bit8u NumberOfImagePages; Bit8u Reserved_page; Bit8u RedMaskSize; Bit8u RedMaskPos; Bit8u GreenMaskSize; Bit8u GreenMaskPos; Bit8u BlueMaskSize; Bit8u BlueMaskPos; Bit8u ReservedMaskSize; Bit8u ReservedMaskPos; Bit8u DirectColorModeInfo; Bit32u PhysBasePtr; Bit32u OffScreenMemOffset; Bit16u OffScreenMemSize; Bit8u Reserved[206]; } GCC_ATTRIBUTE(packed); #ifdef _MSC_VER #pragma pack() #endif Bit8u VESA_GetSVGAInformation(Bit16u seg,Bit16u off) { /* Fill 256 byte buffer with VESA information */ PhysPt buffer=PhysMake(seg,off); Bitu i; bool vbe2=false;Bit16u vbe2_pos=256+off; Bitu id=mem_readd(buffer); if ((id==0x56424532)||(id==0x32454256)) vbe2=true; if (vbe2) { for (i=0;i<0x200;i++) mem_writeb(buffer+i,0); } else { for (i=0;i<0x100;i++) mem_writeb(buffer+i,0); } /* Fill common data */ MEM_BlockWrite(buffer,(void *)"VESA",4); //Identification mem_writew(buffer+0x04,0x200); //Vesa version 0x200 if (vbe2) { mem_writed(buffer+0x06,RealMake(seg,vbe2_pos)); for (i=0;itype) { case M_LIN4: pageSize = mblock->sheight * mblock->swidth/2; pageSize = (pageSize | 15) & ~ 15; var_write(&minfo.NumberOfImagePages,(512*1024 / pageSize)-1); var_write(&minfo.BytesPerScanLine,mblock->swidth/8); var_write(&minfo.BitsPerPixel,4); var_write(&minfo.MemoryModel,3); //ega planar mode var_write(&minfo.ModeAttributes,0x1b); //Color, graphics, no linear buffer break; case M_LIN8: pageSize = mblock->sheight * mblock->swidth; pageSize = (pageSize | 15) & ~ 15; var_write(&minfo.NumberOfImagePages,(2*1024*1024 / pageSize)-1); var_write(&minfo.BytesPerScanLine,mblock->swidth); var_write(&minfo.BitsPerPixel,8); var_write(&minfo.MemoryModel,4); //packed pixel var_write(&minfo.ModeAttributes,0x9b); //Color, graphics, linear buffer break; case M_LIN15: pageSize = mblock->sheight * mblock->swidth*2; pageSize = (pageSize | 15) & ~ 15; var_write(&minfo.NumberOfImagePages,(2*1024*1024 / pageSize)-1); var_write(&minfo.BytesPerScanLine,mblock->swidth*2); var_write(&minfo.BitsPerPixel,15); var_write(&minfo.MemoryModel,6); //HiColour var_write(&minfo.RedMaskSize,5); var_write(&minfo.RedMaskPos,10); var_write(&minfo.GreenMaskSize,5); var_write(&minfo.GreenMaskPos,5); var_write(&minfo.BlueMaskSize,5); var_write(&minfo.BlueMaskPos,0); var_write(&minfo.ModeAttributes,0x9b); //Color, graphics, linear buffer break; case M_LIN16: pageSize = mblock->sheight * mblock->swidth*2; pageSize = (pageSize | 15) & ~ 15; var_write(&minfo.NumberOfImagePages,(2*1024*1024 / pageSize)-1); var_write(&minfo.BytesPerScanLine,mblock->swidth*2); var_write(&minfo.BitsPerPixel,16); var_write(&minfo.MemoryModel,6); //HiColour var_write(&minfo.RedMaskSize,5); var_write(&minfo.RedMaskPos,11); var_write(&minfo.GreenMaskSize,6); var_write(&minfo.GreenMaskPos,5); var_write(&minfo.BlueMaskSize,5); var_write(&minfo.BlueMaskPos,0); var_write(&minfo.ModeAttributes,0x9b); //Color, graphics, linear buffer break; case M_LIN32: pageSize = mblock->sheight * mblock->swidth*4; pageSize = (pageSize | 15) & ~ 15; var_write(&minfo.NumberOfImagePages,(2*1024*1024 / pageSize)-1); var_write(&minfo.BytesPerScanLine,mblock->swidth*4); var_write(&minfo.BitsPerPixel,32); var_write(&minfo.MemoryModel,6); //HiColour var_write(&minfo.RedMaskSize,8); var_write(&minfo.RedMaskPos,0x10); var_write(&minfo.GreenMaskSize,0x8); var_write(&minfo.GreenMaskPos,0x8); var_write(&minfo.BlueMaskSize,0x8); var_write(&minfo.BlueMaskPos,0x0); var_write(&minfo.ReservedMaskSize,0x8); var_write(&minfo.ReservedMaskPos,0x18); var_write(&minfo.ModeAttributes,0x9b); //Color, graphics, linear buffer break; default: return 0x1; } var_write(&minfo.WinAAttributes,0x7); //Exists/readable/writable var_write(&minfo.WinGranularity,64); var_write(&minfo.WinSize,64); var_write(&minfo.WinASegment,0xa000); var_write(&minfo.WinFuncPtr,CALLBACK_RealPointer(callback.setwindow)); var_write(&minfo.NumberOfPlanes,0x1); var_write(&minfo.NumberOfBanks,0x1); var_write(&minfo.Reserved_page,0x1); var_write(&minfo.XResolution,mblock->swidth); var_write(&minfo.YResolution,mblock->sheight); var_write(&minfo.XCharSize,mblock->cwidth); var_write(&minfo.YCharSize,mblock->cheight); var_write(&minfo.PhysBasePtr,S3_LFB_BASE); MEM_BlockWrite(buf,&minfo,sizeof(MODE_INFO)); return 0x00; } Bit8u VESA_SetSVGAMode(Bit16u mode) { if (INT10_SetVideoMode(mode)) return 0x00; return 0x01; }; Bit8u VESA_GetSVGAMode(Bit16u & mode) { mode=(Bit16u)(CurMode->mode); return 0x00; } Bit8u VESA_SetCPUWindow(Bit8u window,Bit8u address) { if (window) return 0x1; if ((address<32)) { IO_Write(0x3d4,0x6a); IO_Write(0x3d5,(Bit8u)address); return 0x0; } else return 0x1; } Bit8u VESA_GetCPUWindow(Bit8u window,Bit16u & address) { if (window) return 0x1; IO_Write(0x3d4,0x6a); address=IO_Read(0x3d5); return 0x0; } Bit8u VESA_SetPalette(PhysPt data,Bitu index,Bitu count) { //Structure is (vesa 3.0 doc): blue,green,red,alignment Bit8u r,g,b; if (index>255) return 0x1; if (index+count>256) return 0x1; IO_Write(0x3c8,index); while (count) { b = mem_readb(data++); g = mem_readb(data++); r = mem_readb(data++); data++; IO_Write(0x3c9,r); IO_Write(0x3c9,g); IO_Write(0x3c9,b); count--; } return 0x00; } Bit8u VESA_GetPalette(PhysPt data,Bitu index,Bitu count) { Bit8u r,g,b; if (index>255) return 0x1; if (index+count>256) return 0x1; IO_Write(0x3c7,index); while (count) { r = IO_Read(0x3c9); g = IO_Read(0x3c9); b = IO_Read(0x3c9); mem_writeb(data++,b); mem_writeb(data++,g); mem_writeb(data++,r); data++; count--; } return 0x00; } Bit8u VESA_ScanLineLength(Bit8u subcall,Bit16u val, Bit16u & bytes,Bit16u & pixels,Bit16u & lines) { Bit8u bpp; switch (CurMode->type) { case M_LIN4: bpp = 1; break; case M_LIN8: bpp=1; break; case M_LIN15: case M_LIN16: bpp=2; break; case M_LIN32: bpp=4; break; default: return 0x1; } switch (subcall) { case 0x00: /* Set in pixels */ vga.config.scan_len = (val * bpp); break; case 0x02: /* Set in bytes */ vga.config.scan_len = val; break; case 0x03: /* Get maximum */ bytes=0x400*4; pixels=bytes/bpp; lines = 2*1024*1024 / bytes; return 0x00; case 0x01: /* Get lengths */ break; default: return 0x1; //Illegal call } if (subcall!=0x01) { /* Write the scan line to video card the simple way */ if (vga.config.scan_len & 7) vga.config.scan_len += 8; vga.config.scan_len /= 8; } pixels=(vga.config.scan_len*8)/bpp; bytes=vga.config.scan_len*8; lines = 2*1024*1024 / bytes; VGA_StartResize(); return 0x0; } Bit8u VESA_SetDisplayStart(Bit16u x,Bit16u y) { //TODO Maybe do things differently with lowres double line modes? Bitu start; switch (CurMode->type) { case M_LIN4: start=vga.config.scan_len*8*y+x; vga.config.display_start=start/8; IO_Read(0x3da); IO_Write(0x3c0,0x13+32); IO_Write(0x3c0,start % 8); break; case M_LIN8: start=vga.config.scan_len*8*y+x; vga.config.display_start=start/4; IO_Read(0x3da); IO_Write(0x3c0,0x13+32); IO_Write(0x3c0,(start % 4)*2); break; case M_LIN16: case M_LIN15: start=vga.config.scan_len*8*y+x*2; vga.config.display_start=start/4; break; case M_LIN32: start=vga.config.scan_len*8*y+x*4; vga.config.display_start=start/4; break; default: return 0x1; } return 0x00; } Bit8u VESA_GetDisplayStart(Bit16u & x,Bit16u & y) { Bitu times=(vga.config.display_start*4)/(vga.config.scan_len*8); Bitu rem=(vga.config.display_start*4) % (vga.config.scan_len*8); Bitu pan=vga.config.pel_panning; switch (CurMode->type) { case M_LIN8: y=times; x=rem+pan; break; default: return 0x1; } return 0x00; } static Bitu VESA_SetWindow(void) { if (reg_bh) reg_ah=VESA_GetCPUWindow(reg_bl,reg_dx); else reg_ah=VESA_SetCPUWindow(reg_bl,(Bit8u)reg_dx); reg_al=0x4f; return 0; } static Bitu VESA_PMSetWindow(void) { VESA_SetCPUWindow(reg_bl,(Bit8u)reg_dx); return 0; } static Bitu VESA_PMSetPalette(void) { VESA_SetPalette(SegPhys(es) + reg_edi, reg_dx, reg_cx ); return 0; } static Bitu VESA_PMSetStart(void) { Bit32u start = (reg_dx << 16) | reg_cx; vga.config.display_start = start; return 0; } void INT10_SetupVESA(void) { /* Put the mode list somewhere in memory */ Bitu i; i=0; int10.rom.vesa_modes=RealMake(0xc000,int10.rom.used); //TODO Maybe add normal vga modes too, but only seems to complicate things while (ModeList_VGA[i].mode!=0xffff) { if (ModeList_VGA[i].mode>=0x100){ phys_writew(PhysMake(0xc000,int10.rom.used),ModeList_VGA[i].mode); int10.rom.used+=2; } i++; } phys_writew(PhysMake(0xc000,int10.rom.used),0xffff); int10.rom.used+=2; int10.rom.oemstring=RealMake(0xc000,int10.rom.used); Bitu len=strlen(string_oem)+1; for (i=0;i