DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include <string.h> 00021 #include <stddef.h> 00022 00023 #include "dosbox.h" 00024 #include "callback.h" 00025 #include "regs.h" 00026 #include "mem.h" 00027 #include "inout.h" 00028 #include "int10.h" 00029 #include "render.h" 00030 #include "dos_inc.h" 00031 00032 int hack_lfb_yadjust = 0; 00033 00034 bool vesa_zero_on_get_information = true; 00035 00036 extern int vesa_mode_width_cap; 00037 extern int vesa_mode_height_cap; 00038 extern bool enable_vga_8bit_dac; 00039 extern bool allow_hd_vesa_modes; 00040 extern bool allow_unusual_vesa_modes; 00041 extern bool allow_explicit_vesa_24bpp; 00042 extern bool allow_vesa_lowres_modes; 00043 extern bool allow_vesa_4bpp_packed; 00044 extern bool vesa12_modes_32bpp; 00045 extern bool allow_vesa_32bpp; 00046 extern bool allow_vesa_24bpp; 00047 extern bool allow_vesa_16bpp; 00048 extern bool allow_vesa_15bpp; 00049 extern bool allow_vesa_8bpp; 00050 extern bool allow_vesa_4bpp; 00051 extern bool allow_vesa_tty; 00052 extern bool vga_8bit_dac; 00053 00054 #define VESA_SUCCESS 0x00 00055 #define VESA_FAIL 0x01 00056 #define VESA_HW_UNSUPPORTED 0x02 00057 #define VESA_MODE_UNSUPPORTED 0x03 00058 // internal definition to pass to the caller 00059 #define VESA_UNIMPLEMENTED 0xFF 00060 00061 static struct { 00062 Bitu rmWindow; 00063 Bitu pmStart; 00064 Bitu pmWindow; 00065 Bitu pmPalette; 00066 } callback = {0}; 00067 00068 void CALLBACK_DeAllocate(Bitu in); 00069 00070 static char string_oem[]="S3 Incorporated. Trio64"; 00071 static char string_vendorname[]="DOSBox Development Team"; 00072 static char string_productname[]="DOSBox - The DOS Emulator"; 00073 static char string_productrev[]="2"; 00074 00075 #ifdef _MSC_VER 00076 #pragma pack (1) 00077 #endif 00078 struct MODE_INFO{ 00079 Bit16u ModeAttributes; 00080 Bit8u WinAAttributes; 00081 Bit8u WinBAttributes; 00082 Bit16u WinGranularity; 00083 Bit16u WinSize; 00084 Bit16u WinASegment; 00085 Bit16u WinBSegment; 00086 Bit32u WinFuncPtr; 00087 Bit16u BytesPerScanLine; 00088 Bit16u XResolution; 00089 Bit16u YResolution; 00090 Bit8u XCharSize; 00091 Bit8u YCharSize; 00092 Bit8u NumberOfPlanes; 00093 Bit8u BitsPerPixel; 00094 Bit8u NumberOfBanks; 00095 Bit8u MemoryModel; 00096 Bit8u BankSize; 00097 Bit8u NumberOfImagePages; 00098 Bit8u Reserved_page; 00099 Bit8u RedMaskSize; 00100 Bit8u RedMaskPos; 00101 Bit8u GreenMaskSize; 00102 Bit8u GreenMaskPos; 00103 Bit8u BlueMaskSize; 00104 Bit8u BlueMaskPos; 00105 Bit8u ReservedMaskSize; 00106 Bit8u ReservedMaskPos; 00107 Bit8u DirectColorModeInfo; 00108 Bit32u PhysBasePtr; 00109 Bit32u OffScreenMemOffset; 00110 Bit16u OffScreenMemSize; 00111 Bit8u Reserved[206]; 00112 } GCC_ATTRIBUTE(packed); 00113 #ifdef _MSC_VER 00114 #pragma pack() 00115 #endif 00116 00117 void VESA_OnReset_Clear_Callbacks(void) { 00118 if (callback.rmWindow != 0) { 00119 CALLBACK_DeAllocate(callback.rmWindow); 00120 callback.rmWindow = 0; 00121 } 00122 if (callback.pmPalette != 0) { 00123 CALLBACK_DeAllocate(callback.pmPalette); 00124 callback.pmPalette = 0; 00125 } 00126 if (callback.pmStart != 0) { 00127 CALLBACK_DeAllocate(callback.pmStart); 00128 callback.pmStart = 0; 00129 } 00130 if (callback.pmWindow != 0) { 00131 CALLBACK_DeAllocate(callback.pmWindow); 00132 callback.pmWindow = 0; 00133 } 00134 } 00135 00136 extern bool vesa_bios_modelist_in_info; 00137 00138 Bit8u VESA_GetSVGAInformation(Bit16u seg,Bit16u off) { 00139 /* Fill 256 byte buffer with VESA information */ 00140 PhysPt buffer=PhysMake(seg,off); 00141 Bitu i; 00142 bool vbe2=false;Bit16u vbe2_pos; 00143 Bitu id=mem_readd(buffer); 00144 if (((id==0x56424532)||(id==0x32454256)) && (!int10.vesa_oldvbe)) vbe2=true; 00145 00146 /* The reason this is an option is that there are some old DOS games that assume the BIOS 00147 * fills in only the structure members. These games do not provide enough room for the 00148 * full 256-byte block. If we zero the entire block, unrelated data next to the buffer 00149 * gets wiped and the game crashes. */ 00150 if (vesa_zero_on_get_information) { 00151 if (vbe2) { 00152 for (i=0;i<0x200;i++) mem_writeb((PhysPt)(buffer+i),0); 00153 } else { 00154 for (i=0;i<0x100;i++) mem_writeb((PhysPt)(buffer+i),0); 00155 } 00156 } 00157 00158 /* Fill common data */ 00159 MEM_BlockWrite(buffer,(void *)"VESA",4); //Identification 00160 if (!int10.vesa_oldvbe) mem_writew(buffer+0x04,0x200); //Vesa version 2.0 00161 else mem_writew(buffer+0x04,0x102); //Vesa version 1.2 00162 if (vbe2) { 00163 vbe2_pos=256+off; 00164 00165 mem_writed(buffer+0x06,RealMake(seg,vbe2_pos)); 00166 for (i=0;i<sizeof(string_oem);i++) real_writeb(seg,vbe2_pos++,(Bit8u)string_oem[i]); 00167 mem_writew(buffer+0x14,0x200); //VBE 2 software revision 00168 mem_writed(buffer+0x16,RealMake(seg,vbe2_pos)); 00169 for (i=0;i<sizeof(string_vendorname);i++) real_writeb(seg,vbe2_pos++,(Bit8u)string_vendorname[i]); 00170 mem_writed(buffer+0x1a,RealMake(seg,vbe2_pos)); 00171 for (i=0;i<sizeof(string_productname);i++) real_writeb(seg,vbe2_pos++,(Bit8u)string_productname[i]); 00172 mem_writed(buffer+0x1e,RealMake(seg,vbe2_pos)); 00173 for (i=0;i<sizeof(string_productrev);i++) real_writeb(seg,vbe2_pos++,(Bit8u)string_productrev[i]); 00174 } else { 00175 vbe2_pos=0x20+off; 00176 00177 mem_writed(buffer+0x06,int10.rom.oemstring); //Oemstring 00178 } 00179 00180 if (vesa_bios_modelist_in_info) { 00181 /* put the modelist into the VBE struct itself, as modern BIOSes like to do. 00182 * NOTICE: This limits the modelist to what is able to fit! Extended modes may not fit, which is why the option is OFF by default. */ 00183 uint16_t modesg = int10.rom.vesa_modes >> 16; 00184 uint16_t modoff = int10.rom.vesa_modes & 0xFFFF; 00185 00186 mem_writed(buffer+0x0e,RealMake(seg,vbe2_pos)); //VESA Mode list 00187 00188 do { 00189 if (vbe2) { 00190 if (vbe2_pos >= (509+off)) break; 00191 } 00192 else { 00193 if (vbe2_pos >= (253+off)) break; 00194 } 00195 uint16_t m = real_readw(modesg,modoff); 00196 if (m == 0xFFFF) break; 00197 real_writew(seg,vbe2_pos,m); 00198 vbe2_pos += 2; 00199 modoff += 2; 00200 } while (1); 00201 real_writew(seg,vbe2_pos,0xFFFF); 00202 } 00203 else { 00204 mem_writed(buffer+0x0e,int10.rom.vesa_modes); //VESA Mode list 00205 } 00206 00207 mem_writed(buffer+0x0a,(enable_vga_8bit_dac ? 1 : 0)); //Capabilities and flags 00208 mem_writew(buffer+0x12,(Bit16u)(vga.mem.memsize/(64*1024))); // memory size in 64kb blocks 00209 return VESA_SUCCESS; 00210 } 00211 00212 Bit8u VESA_GetSVGAModeInformation(Bit16u mode,Bit16u seg,Bit16u off) { 00213 MODE_INFO minfo; 00214 memset(&minfo,0,sizeof(minfo)); 00215 PhysPt buf=PhysMake(seg,off); 00216 Bitu pageSize; 00217 Bit8u modeAttributes; 00218 Bitu i=0; 00219 00220 mode&=0x3fff; // vbe2 compatible, ignore lfb and keep screen content bits 00221 if (mode<0x100) return 0x01; 00222 while (ModeList_VGA[i].mode!=0xffff) { 00223 /* Hack for VBE 1.2 modes and 24/32bpp ambiguity */ 00224 if (ModeList_VGA[i].mode >= 0x100 && ModeList_VGA[i].mode <= 0x11F && 00225 !(ModeList_VGA[i].special & _USER_MODIFIED) && 00226 ((ModeList_VGA[i].type == M_LIN32 && !vesa12_modes_32bpp) || 00227 (ModeList_VGA[i].type == M_LIN24 && vesa12_modes_32bpp))) { 00228 /* ignore */ 00229 i++; 00230 } 00231 /* ignore deleted modes */ 00232 else if (ModeList_VGA[i].type == M_ERROR) { 00233 /* ignore */ 00234 i++; 00235 } 00236 else if (mode==ModeList_VGA[i].mode) 00237 goto foundit; 00238 else 00239 i++; 00240 } 00241 return VESA_FAIL; 00242 foundit: 00243 if ((int10.vesa_oldvbe) && (ModeList_VGA[i].mode>=0x120)) return 0x01; 00244 VideoModeBlock * mblock=&ModeList_VGA[i]; 00245 00246 /* Don't allow querying modes the SVGA card does not accept, 00247 * unless the user modified the mode. */ 00248 if (svga.accepts_mode && !(mblock->special & _USER_MODIFIED)) { 00249 if (!svga.accepts_mode(mode)) return 0x01; 00250 } 00251 00252 /* do not return information on deleted modes */ 00253 if (mblock->type == M_ERROR) return 0x01; 00254 00255 bool allow_res = allow_vesa_lowres_modes || 00256 (ModeList_VGA[i].swidth >= 640 && ModeList_VGA[i].sheight >= 400); 00257 00258 switch (mblock->type) { 00259 case M_PACKED4: 00260 if (!allow_vesa_4bpp_packed) return VESA_FAIL;//TODO: New option to disable 00261 pageSize = mblock->sheight * mblock->swidth/2; 00262 var_write(&minfo.BytesPerScanLine,(Bit16u)((((mblock->swidth+15U)/8U)&(~1U))*4)); /* NTS: 4bpp requires even value due to VGA registers, round up */ 00263 var_write(&minfo.NumberOfPlanes,0x1); 00264 var_write(&minfo.BitsPerPixel,4); 00265 var_write(&minfo.MemoryModel,4); //packed pixel 00266 modeAttributes = 0x1b; // Color, graphics 00267 if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer 00268 break; 00269 case M_LIN4: 00270 if (!allow_vesa_4bpp) return VESA_FAIL; 00271 pageSize = mblock->sheight * mblock->swidth/2; 00272 var_write(&minfo.BytesPerScanLine,(Bit16u)(((mblock->swidth+15U)/8U)&(~1U))); /* NTS: 4bpp requires even value due to VGA registers, round up */ 00273 var_write(&minfo.NumberOfPlanes,0x4); 00274 var_write(&minfo.BitsPerPixel,4);//FIXME: Shouldn't this say 4 planes, 1 bit per pixel?? 00275 var_write(&minfo.MemoryModel,3); //ega planar mode 00276 modeAttributes = 0x1b; // Color, graphics, no linear buffer 00277 break; 00278 case M_LIN8: 00279 if (!allow_vesa_8bpp || !allow_res) return VESA_FAIL; 00280 pageSize = mblock->sheight * mblock->swidth; 00281 var_write(&minfo.BytesPerScanLine,(Bit16u)mblock->swidth); 00282 var_write(&minfo.NumberOfPlanes,0x1); 00283 var_write(&minfo.BitsPerPixel,8); 00284 var_write(&minfo.MemoryModel,4); //packed pixel 00285 modeAttributes = 0x1b; // Color, graphics 00286 if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer 00287 break; 00288 case M_LIN15: 00289 if (!allow_vesa_15bpp || !allow_res) return VESA_FAIL; 00290 pageSize = mblock->sheight * mblock->swidth*2; 00291 var_write(&minfo.BytesPerScanLine,(Bit16u)(mblock->swidth*2)); 00292 var_write(&minfo.NumberOfPlanes,0x1); 00293 var_write(&minfo.BitsPerPixel,15); 00294 var_write(&minfo.MemoryModel,6); //HiColour 00295 var_write(&minfo.RedMaskSize,5); 00296 var_write(&minfo.RedMaskPos,10); 00297 var_write(&minfo.GreenMaskSize,5); 00298 var_write(&minfo.GreenMaskPos,5); 00299 var_write(&minfo.BlueMaskSize,5); 00300 var_write(&minfo.BlueMaskPos,0); 00301 var_write(&minfo.ReservedMaskSize,0x01); 00302 var_write(&minfo.ReservedMaskPos,0x0f); 00303 modeAttributes = 0x1b; // Color, graphics 00304 if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer 00305 break; 00306 case M_LIN16: 00307 if (!allow_vesa_16bpp || !allow_res) return VESA_FAIL; 00308 pageSize = mblock->sheight * mblock->swidth*2; 00309 var_write(&minfo.BytesPerScanLine,(Bit16u)(mblock->swidth*2)); 00310 var_write(&minfo.NumberOfPlanes,0x1); 00311 var_write(&minfo.BitsPerPixel,16); 00312 var_write(&minfo.MemoryModel,6); //HiColour 00313 var_write(&minfo.RedMaskSize,5); 00314 var_write(&minfo.RedMaskPos,11); 00315 var_write(&minfo.GreenMaskSize,6); 00316 var_write(&minfo.GreenMaskPos,5); 00317 var_write(&minfo.BlueMaskSize,5); 00318 var_write(&minfo.BlueMaskPos,0); 00319 modeAttributes = 0x1b; // Color, graphics 00320 if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer 00321 break; 00322 case M_LIN24: 00323 if (!allow_vesa_24bpp || !allow_res) return VESA_FAIL; 00324 if (mode >= 0x120 && !allow_explicit_vesa_24bpp) return VESA_FAIL; 00325 pageSize = mblock->sheight * mblock->swidth*3; 00326 var_write(&minfo.BytesPerScanLine,(Bit16u)(mblock->swidth*3)); 00327 var_write(&minfo.NumberOfPlanes,0x1); 00328 var_write(&minfo.BitsPerPixel,24); 00329 var_write(&minfo.MemoryModel,6); //HiColour 00330 var_write(&minfo.RedMaskSize,8); 00331 var_write(&minfo.RedMaskPos,0x10); 00332 var_write(&minfo.GreenMaskSize,0x8); 00333 var_write(&minfo.GreenMaskPos,0x8); 00334 var_write(&minfo.BlueMaskSize,0x8); 00335 var_write(&minfo.BlueMaskPos,0x0); 00336 modeAttributes = 0x1b; // Color, graphics 00337 if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer 00338 break; 00339 case M_LIN32: 00340 if (!allow_vesa_32bpp || !allow_res) return VESA_FAIL; 00341 pageSize = mblock->sheight * mblock->swidth*4; 00342 var_write(&minfo.BytesPerScanLine,(Bit16u)(mblock->swidth*4)); 00343 var_write(&minfo.NumberOfPlanes,0x1); 00344 var_write(&minfo.BitsPerPixel,32); 00345 var_write(&minfo.MemoryModel,6); //HiColour 00346 var_write(&minfo.RedMaskSize,8); 00347 var_write(&minfo.RedMaskPos,0x10); 00348 var_write(&minfo.GreenMaskSize,0x8); 00349 var_write(&minfo.GreenMaskPos,0x8); 00350 var_write(&minfo.BlueMaskSize,0x8); 00351 var_write(&minfo.BlueMaskPos,0x0); 00352 var_write(&minfo.ReservedMaskSize,0x8); 00353 var_write(&minfo.ReservedMaskPos,0x18); 00354 modeAttributes = 0x1b; // Color, graphics 00355 if (!int10.vesa_nolfb) modeAttributes |= 0x80; // linear framebuffer 00356 break; 00357 case M_TEXT: 00358 if (!allow_vesa_tty) return VESA_FAIL; 00359 pageSize = 0; 00360 var_write(&minfo.BytesPerScanLine, (Bit16u)(mblock->twidth * 2)); 00361 var_write(&minfo.NumberOfPlanes,0x4); 00362 var_write(&minfo.BitsPerPixel,4); 00363 var_write(&minfo.MemoryModel,0); // text 00364 modeAttributes = 0x0f; //Color, text, bios output 00365 break; 00366 default: 00367 return VESA_FAIL; 00368 } 00369 if (pageSize & 0xFFFFu) { 00370 // It is documented that many applications assume 64k-aligned page sizes 00371 // VBETEST is one of them 00372 pageSize += 0xFFFFu; 00373 pageSize &= ~0xFFFFu; 00374 } 00375 Bitu pages = 0; 00376 if (pageSize > vga.mem.memsize || (mblock->special & _USER_DISABLED)) { 00377 // mode not supported by current hardware configuration 00378 modeAttributes &= ~0x1; 00379 } else if (pageSize) { 00380 pages = (vga.mem.memsize / pageSize)-1; 00381 } 00382 var_write(&minfo.NumberOfImagePages, (Bit8u)pages); 00383 var_write(&minfo.ModeAttributes, modeAttributes); 00384 var_write(&minfo.WinAAttributes, 0x7); // Exists/readable/writable 00385 00386 if (mblock->type==M_TEXT) { 00387 var_write(&minfo.WinGranularity,32); 00388 var_write(&minfo.WinSize,32); 00389 var_write(&minfo.WinASegment,(Bit16u)0xb800); 00390 var_write(&minfo.XResolution,(Bit16u)mblock->twidth); 00391 var_write(&minfo.YResolution,(Bit16u)mblock->theight); 00392 } else { 00393 var_write(&minfo.WinGranularity,64); 00394 var_write(&minfo.WinSize,64); 00395 var_write(&minfo.WinASegment,(Bit16u)0xa000); 00396 var_write(&minfo.XResolution,(Bit16u)mblock->swidth); 00397 var_write(&minfo.YResolution,(Bit16u)mblock->sheight); 00398 } 00399 var_write(&minfo.WinFuncPtr,int10.rom.set_window); 00400 var_write(&minfo.NumberOfBanks,0x1); 00401 var_write(&minfo.Reserved_page,0x1); 00402 var_write(&minfo.XCharSize,(Bit8u)mblock->cwidth); 00403 var_write(&minfo.YCharSize,(Bit8u)mblock->cheight); 00404 if (!int10.vesa_nolfb) var_write(&minfo.PhysBasePtr,S3_LFB_BASE + (hack_lfb_yadjust*(long)host_readw((HostPt)(&minfo.BytesPerScanLine)))); 00405 00406 MEM_BlockWrite(buf,&minfo,sizeof(MODE_INFO)); 00407 return VESA_SUCCESS; 00408 } 00409 00410 00411 Bit8u VESA_SetSVGAMode(Bit16u mode) { 00412 if (INT10_SetVideoMode(mode)) { 00413 int10.vesa_setmode=mode&0x7fff; 00414 return VESA_SUCCESS; 00415 } 00416 return VESA_FAIL; 00417 } 00418 00419 Bit8u VESA_GetSVGAMode(Bit16u & mode) { 00420 if (int10.vesa_setmode!=0xffff) mode=int10.vesa_setmode; 00421 else mode=CurMode->mode; 00422 return VESA_SUCCESS; 00423 } 00424 00425 Bit8u VESA_SetCPUWindow(Bit8u window,Bit8u address) { 00426 if (window) return VESA_FAIL; 00427 if ((Bit32u)(address)*64*1024<vga.mem.memsize) { 00428 IO_Write(0x3d4,0x6a); 00429 IO_Write(0x3d5,(Bit8u)address); 00430 return VESA_SUCCESS; 00431 } else return VESA_FAIL; 00432 } 00433 00434 Bit8u VESA_GetCPUWindow(Bit8u window,Bit16u & address) { 00435 if (window) return VESA_FAIL; 00436 IO_Write(0x3d4,0x6a); 00437 address=IO_Read(0x3d5); 00438 return VESA_SUCCESS; 00439 } 00440 00441 00442 Bit8u VESA_SetPalette(PhysPt data,Bitu index,Bitu count,bool wait) { 00443 //Structure is (vesa 3.0 doc): blue,green,red,alignment 00444 if (index>255) return VESA_FAIL; 00445 if (index+count>256) return VESA_FAIL; 00446 00447 // Wait for retrace if requested 00448 if (wait) CALLBACK_RunRealFar(RealSeg(int10.rom.wait_retrace),RealOff(int10.rom.wait_retrace)); 00449 00450 IO_Write(0x3c8,(Bit8u)index); 00451 while (count) { 00452 Bit8u b = mem_readb(data++); 00453 Bit8u g = mem_readb(data++); 00454 Bit8u r = mem_readb(data++); 00455 data++; 00456 IO_Write(0x3c9,r); 00457 IO_Write(0x3c9,g); 00458 IO_Write(0x3c9,b); 00459 count--; 00460 } 00461 return VESA_SUCCESS; 00462 } 00463 00464 00465 Bit8u VESA_GetPalette(PhysPt data,Bitu index,Bitu count) { 00466 if (index>255) return VESA_FAIL; 00467 if (index+count>256) return VESA_FAIL; 00468 IO_Write(0x3c7,(Bit8u)index); 00469 while (count) { 00470 Bit8u r = IO_Read(0x3c9); 00471 Bit8u g = IO_Read(0x3c9); 00472 Bit8u b = IO_Read(0x3c9); 00473 mem_writeb(data++,b); 00474 mem_writeb(data++,g); 00475 mem_writeb(data++,r); 00476 data++; 00477 count--; 00478 } 00479 return VESA_SUCCESS; 00480 } 00481 00482 // maximum offset for the S3 Trio64 is 10 bits 00483 #define S3_MAX_OFFSET 0x3ff 00484 00485 Bit8u VESA_ScanLineLength(Bit8u subcall,Bit16u val, Bit16u & bytes,Bit16u & pixels,Bit16u & lines) { 00486 // offset register: virtual scanline length 00487 Bitu pixels_per_offset; 00488 Bitu bytes_per_offset = 8; 00489 Bitu vmemsize = vga.mem.memsize; 00490 Bitu new_offset = vga.config.scan_len; 00491 Bitu screen_height = CurMode->sheight; 00492 00493 switch (CurMode->type) { 00494 case M_TEXT: 00495 vmemsize = 0x8000; // we have only the 32kB window here 00496 screen_height = CurMode->theight; 00497 pixels_per_offset = 16; // two characters each 8 pixels wide 00498 bytes_per_offset = 4; // 2 characters + 2 attributes 00499 break; 00500 case M_LIN4: 00501 case M_PACKED4: 00502 pixels_per_offset = 16; 00503 break; 00504 case M_LIN8: 00505 pixels_per_offset = 8; 00506 break; 00507 case M_LIN15: 00508 case M_LIN16: 00509 pixels_per_offset = 4; 00510 break; 00511 case M_LIN32: 00512 pixels_per_offset = 2; 00513 break; 00514 default: 00515 return VESA_MODE_UNSUPPORTED; 00516 } 00517 switch (subcall) { 00518 case 0x00: // set scan length in pixels 00519 new_offset = val / pixels_per_offset; 00520 if (val % pixels_per_offset) new_offset++; 00521 00522 if (new_offset > S3_MAX_OFFSET) 00523 return VESA_HW_UNSUPPORTED; // scanline too long 00524 vga.config.scan_len = new_offset; 00525 VGA_CheckScanLength(); 00526 break; 00527 00528 case 0x01: // get current scanline length 00529 // implemented at the end of this function 00530 break; 00531 00532 case 0x02: // set scan length in bytes 00533 new_offset = val / bytes_per_offset; 00534 if (val % bytes_per_offset) new_offset++; 00535 00536 if (new_offset > S3_MAX_OFFSET) 00537 return VESA_HW_UNSUPPORTED; // scanline too long 00538 vga.config.scan_len = new_offset; 00539 VGA_CheckScanLength(); 00540 break; 00541 00542 case 0x03: // get maximum scan line length 00543 // the smaller of either the hardware maximum scanline length or 00544 // the limit to get full y resolution of this mode 00545 new_offset = S3_MAX_OFFSET; 00546 if ((new_offset * bytes_per_offset * screen_height) > vmemsize) 00547 new_offset = vmemsize / (bytes_per_offset * screen_height); 00548 break; 00549 00550 default: 00551 return VESA_UNIMPLEMENTED; 00552 } 00553 00554 // set up the return values 00555 bytes = (Bit16u)(new_offset * bytes_per_offset); 00556 pixels = (Bit16u)(new_offset * pixels_per_offset); 00557 if (!bytes) 00558 // return failure on division by zero 00559 // some real VESA BIOS implementations may crash here 00560 return VESA_FAIL; 00561 00562 lines = (Bit16u)(vmemsize / bytes); 00563 00564 if (CurMode->type==M_TEXT) 00565 lines *= (Bit16u)(CurMode->cheight); 00566 00567 return VESA_SUCCESS; 00568 } 00569 00570 Bit8u VESA_SetDisplayStart(Bit16u x,Bit16u y,bool wait) { 00571 Bitu pixels_per_offset; 00572 Bitu panning_factor = 1; 00573 00574 switch (CurMode->type) { 00575 case M_TEXT: 00576 case M_LIN4: 00577 case M_PACKED4: 00578 pixels_per_offset = 16; 00579 break; 00580 case M_LIN8: 00581 panning_factor = 2; // the panning register ignores bit0 in this mode 00582 pixels_per_offset = 8; 00583 break; 00584 case M_LIN15: 00585 case M_LIN16: 00586 panning_factor = 2; // this may be DOSBox specific 00587 pixels_per_offset = 4; 00588 break; 00589 case M_LIN32: 00590 pixels_per_offset = 2; 00591 break; 00592 default: 00593 return VESA_MODE_UNSUPPORTED; 00594 } 00595 // We would have to divide y by the character height for text modes and 00596 // write the remainder to the CRTC preset row scan register, 00597 // but VBE2 BIOSes that actually get that far also don't. 00598 // Only a VBE3 BIOS got it right. 00599 Bitu virtual_screen_width = vga.config.scan_len * pixels_per_offset; 00600 Bitu new_start_pixel = virtual_screen_width * y + x; 00601 Bitu new_crtc_start = new_start_pixel / (pixels_per_offset/2); 00602 Bitu new_panning = new_start_pixel % (pixels_per_offset/2); 00603 new_panning *= panning_factor; 00604 00605 vga.config.display_start = new_crtc_start; 00606 00607 // Setting the panning register is nice as it allows for super smooth 00608 // scrolling, but if we hit the retrace pulse there may be flicker as 00609 // panning and display start are latched at different times. 00610 00611 IO_Read(0x3da); // reset attribute flipflop 00612 IO_Write(0x3c0,0x13 | 0x20); // panning register, screen on 00613 IO_Write(0x3c0,(Bit8u)new_panning); 00614 00615 // Wait for retrace if requested 00616 if (wait) CALLBACK_RunRealFar(RealSeg(int10.rom.wait_retrace),RealOff(int10.rom.wait_retrace)); 00617 00618 return VESA_SUCCESS; 00619 } 00620 00621 Bit8u VESA_GetDisplayStart(Bit16u & x,Bit16u & y) { 00622 Bitu pixels_per_offset; 00623 Bitu panning_factor = 1; 00624 00625 switch (CurMode->type) { 00626 case M_TEXT: 00627 pixels_per_offset = 16; 00628 break; 00629 case M_LIN4: 00630 case M_PACKED4: 00631 pixels_per_offset = 16; 00632 break; 00633 case M_LIN8: 00634 panning_factor = 2; 00635 pixels_per_offset = 8; 00636 break; 00637 case M_LIN15: 00638 case M_LIN16: 00639 panning_factor = 2; 00640 pixels_per_offset = 4; 00641 break; 00642 case M_LIN32: 00643 pixels_per_offset = 2; 00644 break; 00645 default: 00646 return VESA_MODE_UNSUPPORTED; 00647 } 00648 00649 IO_Read(0x3da); // reset attribute flipflop 00650 IO_Write(0x3c0,0x13 | 0x20); // panning register, screen on 00651 Bit8u panning = IO_Read(0x3c1); 00652 00653 Bitu virtual_screen_width = vga.config.scan_len * pixels_per_offset; 00654 Bitu start_pixel = vga.config.display_start * (pixels_per_offset/2) 00655 + panning / panning_factor; 00656 00657 y = (Bit16u)(start_pixel / virtual_screen_width); 00658 x = (Bit16u)(start_pixel % virtual_screen_width); 00659 return VESA_SUCCESS; 00660 } 00661 00662 static Bitu VESA_SetWindow(void) { 00663 if (reg_bh) reg_ah=VESA_GetCPUWindow(reg_bl,reg_dx); 00664 else reg_ah=VESA_SetCPUWindow(reg_bl,(Bit8u)reg_dx); 00665 reg_al=0x4f; 00666 return CBRET_NONE; 00667 } 00668 00669 static Bitu VESA_PMSetWindow(void) { 00670 IO_Write(0x3d4,0x6a); 00671 IO_Write(0x3d5,reg_dl); 00672 return CBRET_NONE; 00673 } 00674 static Bitu VESA_PMSetPalette(void) { 00675 PhysPt data=SegPhys(es)+reg_edi; 00676 Bit32u count=reg_cx; 00677 IO_Write(0x3c8,reg_dl); 00678 do { 00679 IO_Write(0x3c9,mem_readb(data+2)); 00680 IO_Write(0x3c9,mem_readb(data+1)); 00681 IO_Write(0x3c9,mem_readb(data)); 00682 data+=4; 00683 } while (--count); 00684 return CBRET_NONE; 00685 } 00686 static Bitu VESA_PMSetStart(void) { 00687 Bit32u start = (Bit32u)(((unsigned int)reg_dx << 16u) | (unsigned int)reg_cx); 00688 vga.config.display_start = start; 00689 return CBRET_NONE; 00690 } 00691 00692 00693 00694 extern int vesa_modelist_cap; 00695 00696 Bitu INT10_WriteVESAModeList(Bitu max_modes) { 00697 Bitu mode_wptr = int10.rom.vesa_modes; 00698 Bitu i=0,modecount=0; 00699 00700 //TODO Maybe add normal vga modes too, but only seems to complicate things 00701 while (ModeList_VGA[i].mode!=0xffff) { 00702 bool canuse_mode=false; 00703 00704 /* Hack for VBE 1.2 modes and 24/32bpp ambiguity */ 00705 if (ModeList_VGA[i].mode >= 0x100 && ModeList_VGA[i].mode <= 0x11F && 00706 ((ModeList_VGA[i].type == M_LIN32 && !vesa12_modes_32bpp) || 00707 (ModeList_VGA[i].type == M_LIN24 && vesa12_modes_32bpp))) { 00708 /* ignore */ 00709 } 00710 /* ignore deleted modes */ 00711 else if (ModeList_VGA[i].type == M_ERROR) { 00712 /* ignore */ 00713 } 00714 else { 00715 /* If there is no "accepts mode" then accept. 00716 * 00717 * If the user modified the mode, then accept. 00718 * If the mode exceeds video memory, then the mode will be reported as not supported by VESA BIOS functions. 00719 * 00720 * If the SVGA card would accept the mode (generally it's a memsize check), then accept. */ 00721 if (!svga.accepts_mode) 00722 canuse_mode=true; 00723 else if (ModeList_VGA[i].special & _USER_MODIFIED) 00724 canuse_mode=true; 00725 else if (svga.accepts_mode(ModeList_VGA[i].mode)) 00726 canuse_mode=true; 00727 00728 if (canuse_mode) { 00729 if (ModeList_VGA[i].mode >= 0x100) { 00730 bool allow1 = allow_vesa_lowres_modes || 00731 (ModeList_VGA[i].swidth >= 640 && ModeList_VGA[i].sheight >= 400); 00732 bool allow2 = 00733 allow_explicit_vesa_24bpp || ModeList_VGA[i].type != M_LIN24 || 00734 (ModeList_VGA[i].type == M_LIN24 && ModeList_VGA[i].mode < 0x120); 00735 bool allow3 = 00736 allow_hd_vesa_modes || 00737 !(ModeList_VGA[i].special & _HIGH_DEFINITION); 00738 bool allow4 = 00739 allow_unusual_vesa_modes || 00740 !(ModeList_VGA[i].special & _UNUSUAL_MODE); 00741 bool allow5 = /* either user modified or within the limits of the render scaler architecture */ 00742 (ModeList_VGA[i].special & _USER_MODIFIED) || 00743 (ModeList_VGA[i].swidth <= SCALER_MAXWIDTH && ModeList_VGA[i].sheight <= SCALER_MAXHEIGHT); 00744 bool allow_res = allow1 && allow2 && allow3 && allow4 && allow5; 00745 00746 switch (ModeList_VGA[i].type) { 00747 case M_LIN32: canuse_mode=allow_vesa_32bpp && allow_res; break; 00748 case M_LIN24: canuse_mode=allow_vesa_24bpp && allow_res; break; 00749 case M_LIN16: canuse_mode=allow_vesa_16bpp && allow_res; break; 00750 case M_LIN15: canuse_mode=allow_vesa_15bpp && allow_res; break; 00751 case M_LIN8: canuse_mode=allow_vesa_8bpp && allow_res; break; 00752 case M_LIN4: canuse_mode=allow_vesa_4bpp && allow_res; break; 00753 case M_PACKED4: canuse_mode=allow_vesa_4bpp_packed && allow_res; break; 00754 case M_TEXT: canuse_mode=allow_vesa_tty && allow_res; break; 00755 default: break; 00756 } 00757 } 00758 } 00759 } 00760 00761 if (canuse_mode && vesa_modelist_cap > 0 && (unsigned int)modecount >= (unsigned int)vesa_modelist_cap) 00762 canuse_mode = false; 00763 if (canuse_mode && (unsigned int)modecount >= (unsigned int)max_modes) 00764 canuse_mode = false; 00765 00766 if (ModeList_VGA[i].type != M_TEXT) { 00767 if (canuse_mode && vesa_mode_width_cap > 0 && (unsigned int)ModeList_VGA[i].swidth > (unsigned int)vesa_mode_width_cap) 00768 canuse_mode = false; 00769 00770 if (canuse_mode && vesa_mode_height_cap > 0 && (unsigned int)ModeList_VGA[i].sheight > (unsigned int)vesa_mode_height_cap) 00771 canuse_mode = false; 00772 } 00773 00774 if (ModeList_VGA[i].mode>=0x100 && canuse_mode) { 00775 if ((!int10.vesa_oldvbe) || (ModeList_VGA[i].mode<0x120)) { 00776 phys_writew(PhysMake((Bit16u)0xc000,(Bit16u)mode_wptr),(Bit16u)ModeList_VGA[i].mode); 00777 mode_wptr+=2; 00778 modecount++; 00779 } 00780 } 00781 00782 i++; 00783 } 00784 00785 assert(modecount <= int10.rom.vesa_alloc_modes); /* do not overrun the buffer */ 00786 00787 /* after the buffer, is 0xFFFF */ 00788 phys_writew(PhysMake((Bit16u)0xc000,(Bit16u)mode_wptr),(Bit16u)0xFFFF); 00789 mode_wptr+=2; 00790 00791 return modecount; 00792 } 00793 00794 void INT10_SetupVESA(void) { 00795 Bitu i,modecount=0; 00796 00797 /* BUGFIX: Generating VESA BIOS data when machine=ega or machine=vgaonly is dumb. 00798 * Stop wasting ROM space! --J.C. */ 00799 if (machine != MCH_VGA) return; 00800 if (svgaCard == SVGA_None) return; 00801 00802 /* Put the mode list somewhere in memory */ 00803 int10.rom.vesa_alloc_modes = (Bit16u)(~0u); 00804 int10.rom.vesa_modes = RealMake(0xc000,int10.rom.used); 00805 modecount = INT10_WriteVESAModeList(0xFFFF/*max mode count*/); 00806 int10.rom.vesa_alloc_modes = (Bit16u)modecount; 00807 int10.rom.used += (Bit16u)(modecount * 2u); 00808 phys_writew(PhysMake(0xc000,int10.rom.used),0xffff); 00809 int10.rom.used+=2; 00810 int10.rom.oemstring=RealMake(0xc000,int10.rom.used); 00811 Bitu len=(Bitu)(strlen(string_oem)+1); 00812 for (i=0;i<len;i++) { 00813 phys_writeb(0xc0000u+(int10.rom.used++),(Bit8u)string_oem[i]); 00814 } 00815 /* Prepare the real mode interface */ 00816 int10.rom.wait_retrace=RealMake(0xc000,int10.rom.used); 00817 int10.rom.used += (Bit16u)CALLBACK_Setup(0, NULL, CB_VESA_WAIT, PhysMake(0xc000,int10.rom.used), ""); 00818 callback.rmWindow=CALLBACK_Allocate(); 00819 int10.rom.set_window=RealMake(0xc000,int10.rom.used); 00820 int10.rom.used += (Bit16u)CALLBACK_Setup(callback.rmWindow, VESA_SetWindow, CB_RETF, PhysMake(0xc000,int10.rom.used), "VESA Real Set Window"); 00821 /* Prepare the pmode interface */ 00822 int10.rom.pmode_interface=RealMake(0xc000,int10.rom.used); 00823 int10.rom.used += 8; //Skip the byte later used for offsets 00824 /* PM Set Window call */ 00825 int10.rom.pmode_interface_window = int10.rom.used - RealOff( int10.rom.pmode_interface ); 00826 phys_writew( Real2Phys(int10.rom.pmode_interface) + 0, int10.rom.pmode_interface_window ); 00827 callback.pmWindow=CALLBACK_Allocate(); 00828 int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmWindow, VESA_PMSetWindow, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Window"); 00829 /* PM Set start call */ 00830 int10.rom.pmode_interface_start = int10.rom.used - RealOff( int10.rom.pmode_interface ); 00831 phys_writew( Real2Phys(int10.rom.pmode_interface) + 2, int10.rom.pmode_interface_start); 00832 callback.pmStart=CALLBACK_Allocate(); 00833 int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmStart, VESA_PMSetStart, CB_VESA_PM, PhysMake(0xc000,int10.rom.used), "VESA PM Set Start"); 00834 /* PM Set Palette call */ 00835 int10.rom.pmode_interface_palette = int10.rom.used - RealOff( int10.rom.pmode_interface ); 00836 phys_writew( Real2Phys(int10.rom.pmode_interface) + 4, int10.rom.pmode_interface_palette); 00837 callback.pmPalette=CALLBACK_Allocate(); 00838 int10.rom.used += (Bit16u)CALLBACK_Setup(0, NULL, CB_VESA_PM, PhysMake(0xc000,int10.rom.used), ""); 00839 int10.rom.used += (Bit16u)CALLBACK_Setup(callback.pmPalette, VESA_PMSetPalette, CB_RETN, PhysMake(0xc000,int10.rom.used), "VESA PM Set Palette"); 00840 /* Finalize the size and clear the required ports pointer */ 00841 phys_writew( Real2Phys(int10.rom.pmode_interface) + 6, 0); 00842 int10.rom.pmode_interface_size=int10.rom.used - RealOff( int10.rom.pmode_interface ); 00843 } 00844