1 /*
2  *  Copyright (C) 2002-2015  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 
20 #include "dosbox.h"
21 #include "mem.h"
22 #include "callback.h"
23 #include "regs.h"
24 #include "inout.h"
25 #include "int10.h"
26 #include "mouse.h"
27 #include "setup.h"
28 
29 Int10Data int10;
30 static Bitu call_10;
31 static bool warned_ff=false;
32 
INT10_Handler(void)33 static Bitu INT10_Handler(void) {
34 #if 0
35 	switch (reg_ah) {
36 	case 0x02:
37 	case 0x03:
38 	case 0x09:
39 	case 0xc:
40 	case 0xd:
41 	case 0x0e:
42 	case 0x10:
43 	case 0x4f:
44 
45 		break;
46 	default:
47 		LOG(LOG_INT10,LOG_NORMAL)("Function AX:%04X , BX %04X DX %04X",reg_ax,reg_bx,reg_dx);
48 		break;
49 	}
50 #endif
51 	INT10_SetCurMode();
52 
53 	switch (reg_ah) {
54 	case 0x00:								/* Set VideoMode */
55 		Mouse_BeforeNewVideoMode(true);
56 		INT10_SetVideoMode(reg_al);
57 		Mouse_AfterNewVideoMode(true);
58 		break;
59 	case 0x01:								/* Set TextMode Cursor Shape */
60 		INT10_SetCursorShape(reg_ch,reg_cl);
61 		break;
62 	case 0x02:								/* Set Cursor Pos */
63 		INT10_SetCursorPos(reg_dh,reg_dl,reg_bh);
64 		break;
65 	case 0x03:								/* get Cursor Pos and Cursor Shape*/
66 //		reg_ah=0;
67 		reg_dl=CURSOR_POS_COL(reg_bh);
68 		reg_dh=CURSOR_POS_ROW(reg_bh);
69 		reg_cx=real_readw(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE);
70 		break;
71 	case 0x04:								/* read light pen pos YEAH RIGHT */
72 		/* Light pen is not supported */
73 		reg_ax=0;
74 		break;
75 	case 0x05:								/* Set Active Page */
76 		if ((reg_al & 0x80) && IS_TANDY_ARCH) {
77 			Bit8u crtcpu=real_readb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE);
78 			switch (reg_al) {
79 			case 0x80:
80 				reg_bh=crtcpu & 7;
81 				reg_bl=(crtcpu >> 3) & 0x7;
82 				break;
83 			case 0x81:
84 				crtcpu=(crtcpu & 0xc7) | ((reg_bl & 7) << 3);
85 				break;
86 			case 0x82:
87 				crtcpu=(crtcpu & 0xf8) | (reg_bh & 7);
88 				break;
89 			case 0x83:
90 				crtcpu=(crtcpu & 0xc0) | (reg_bh & 7) | ((reg_bl & 7) << 3);
91 				break;
92 			}
93 			if (machine==MCH_PCJR) {
94 				/* always return graphics mapping, even for invalid values of AL */
95 				reg_bh=crtcpu & 7;
96 				reg_bl=(crtcpu >> 3) & 0x7;
97 			}
98 			IO_WriteB(0x3df,crtcpu);
99 			real_writeb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE,crtcpu);
100 		}
101 		else INT10_SetActivePage(reg_al);
102 		break;
103 	case 0x06:								/* Scroll Up */
104 		INT10_ScrollWindow(reg_ch,reg_cl,reg_dh,reg_dl,-reg_al,reg_bh,0xFF);
105 		break;
106 	case 0x07:								/* Scroll Down */
107 		INT10_ScrollWindow(reg_ch,reg_cl,reg_dh,reg_dl,reg_al,reg_bh,0xFF);
108 		break;
109 	case 0x08:								/* Read character & attribute at cursor */
110 		INT10_ReadCharAttr(&reg_ax,reg_bh);
111 		break;
112 	case 0x09:								/* Write Character & Attribute at cursor CX times */
113 		if (real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)==0x11)
114 			INT10_WriteChar(reg_al,(reg_bl&0x80)|0x3f,reg_bh,reg_cx,true);
115 		else INT10_WriteChar(reg_al,reg_bl,reg_bh,reg_cx,true);
116 		break;
117 	case 0x0A:								/* Write Character at cursor CX times */
118 		INT10_WriteChar(reg_al,reg_bl,reg_bh,reg_cx,false);
119 		break;
120 	case 0x0B:								/* Set Background/Border Colour & Set Palette*/
121 		switch (reg_bh) {
122 		case 0x00:		//Background/Border color
123 			INT10_SetBackgroundBorder(reg_bl);
124 			break;
125 		case 0x01:		//Set color Select
126 		default:
127 			INT10_SetColorSelect(reg_bl);
128 			break;
129 		}
130 		break;
131 	case 0x0C:								/* Write Graphics Pixel */
132 		INT10_PutPixel(reg_cx,reg_dx,reg_bh,reg_al);
133 		break;
134 	case 0x0D:								/* Read Graphics Pixel */
135 		INT10_GetPixel(reg_cx,reg_dx,reg_bh,&reg_al);
136 		break;
137 	case 0x0E:								/* Teletype OutPut */
138 		INT10_TeletypeOutput(reg_al,reg_bl);
139 		break;
140 	case 0x0F:								/* Get videomode */
141 		reg_bh=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
142 		reg_al=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)|(real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)&0x80);
143 		reg_ah=(Bit8u)real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS);
144 		break;
145 	case 0x10:								/* Palette functions */
146 		if (!IS_EGAVGA_ARCH && (reg_al>0x02)) break;
147 		else if (!IS_VGA_ARCH && (reg_al>0x03)) break;
148 		switch (reg_al) {
149 		case 0x00:							/* SET SINGLE PALETTE REGISTER */
150 			INT10_SetSinglePaletteRegister(reg_bl,reg_bh);
151 			break;
152 		case 0x01:							/* SET BORDER (OVERSCAN) COLOR*/
153 			INT10_SetOverscanBorderColor(reg_bh);
154 			break;
155 		case 0x02:							/* SET ALL PALETTE REGISTERS */
156 			INT10_SetAllPaletteRegisters(SegPhys(es)+reg_dx);
157 			break;
158 		case 0x03:							/* TOGGLE INTENSITY/BLINKING BIT */
159 			INT10_ToggleBlinkingBit(reg_bl);
160 			break;
161 		case 0x07:							/* GET SINGLE PALETTE REGISTER */
162 			INT10_GetSinglePaletteRegister(reg_bl,&reg_bh);
163 			break;
164 		case 0x08:							/* READ OVERSCAN (BORDER COLOR) REGISTER */
165 			INT10_GetOverscanBorderColor(&reg_bh);
166 			break;
167 		case 0x09:							/* READ ALL PALETTE REGISTERS AND OVERSCAN REGISTER */
168 			INT10_GetAllPaletteRegisters(SegPhys(es)+reg_dx);
169 			break;
170 		case 0x10:							/* SET INDIVIDUAL DAC REGISTER */
171 			INT10_SetSingleDACRegister(reg_bl,reg_dh,reg_ch,reg_cl);
172 			break;
173 		case 0x12:							/* SET BLOCK OF DAC REGISTERS */
174 			INT10_SetDACBlock(reg_bx,reg_cx,SegPhys(es)+reg_dx);
175 			break;
176 		case 0x13:							/* SELECT VIDEO DAC COLOR PAGE */
177 			INT10_SelectDACPage(reg_bl,reg_bh);
178 			break;
179 		case 0x15:							/* GET INDIVIDUAL DAC REGISTER */
180 			INT10_GetSingleDACRegister(reg_bl,&reg_dh,&reg_ch,&reg_cl);
181 			break;
182 		case 0x17:							/* GET BLOCK OF DAC REGISTER */
183 			INT10_GetDACBlock(reg_bx,reg_cx,SegPhys(es)+reg_dx);
184 			break;
185 		case 0x18:							/* undocumented - SET PEL MASK */
186 			INT10_SetPelMask(reg_bl);
187 			break;
188 		case 0x19:							/* undocumented - GET PEL MASK */
189 			INT10_GetPelMask(reg_bl);
190 			reg_bh=0;	// bx for get mask
191 			break;
192 		case 0x1A:							/* GET VIDEO DAC COLOR PAGE */
193 			INT10_GetDACPage(&reg_bl,&reg_bh);
194 			break;
195 		case 0x1B:							/* PERFORM GRAY-SCALE SUMMING */
196 			INT10_PerformGrayScaleSumming(reg_bx,reg_cx);
197 			break;
198 		case 0xF0:							/* ET4000: SET HiColor GRAPHICS MODE */
199 		case 0xF1:							/* ET4000: GET DAC TYPE */
200 		case 0xF2:							/* ET4000: CHECK/SET HiColor MODE */
201 		default:
202 			LOG(LOG_INT10,LOG_ERROR)("Function 10:Unhandled EGA/VGA Palette Function %2X",reg_al);
203 			break;
204 		}
205 		break;
206 	case 0x11:								/* Character generator functions */
207 		if (!IS_EGAVGA_ARCH)
208 			break;
209 		if ((reg_al&0xf0)==0x10) Mouse_BeforeNewVideoMode(false);
210 		switch (reg_al) {
211 /* Textmode calls */
212 		case 0x00:			/* Load user font */
213 		case 0x10:
214 			INT10_LoadFont(SegPhys(es)+reg_bp,reg_al==0x10,reg_cx,reg_dx,reg_bl&0x7f,reg_bh);
215 			break;
216 		case 0x01:			/* Load 8x14 font */
217 		case 0x11:
218 			INT10_LoadFont(Real2Phys(int10.rom.font_14),reg_al==0x11,256,0,reg_bl&0x7f,14);
219 			break;
220 		case 0x02:			/* Load 8x8 font */
221 		case 0x12:
222 			INT10_LoadFont(Real2Phys(int10.rom.font_8_first),reg_al==0x12,256,0,reg_bl&0x7f,8);
223 			break;
224 		case 0x03:			/* Set Block Specifier */
225 			IO_Write(0x3c4,0x3);IO_Write(0x3c5,reg_bl);
226 			break;
227 		case 0x04:			/* Load 8x16 font */
228 		case 0x14:
229 			if (!IS_VGA_ARCH) break;
230 			INT10_LoadFont(Real2Phys(int10.rom.font_16),reg_al==0x14,256,0,reg_bl&0x7f,16);
231 			break;
232 /* Graphics mode calls */
233 		case 0x20:			/* Set User 8x8 Graphics characters */
234 			RealSetVec(0x1f,RealMake(SegValue(es),reg_bp));
235 			break;
236 		case 0x21:			/* Set user graphics characters */
237 			RealSetVec(0x43,RealMake(SegValue(es),reg_bp));
238 			real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,reg_cx);
239 			goto graphics_chars;
240 		case 0x22:			/* Rom 8x14 set */
241 			RealSetVec(0x43,int10.rom.font_14);
242 			real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,14);
243 			goto graphics_chars;
244 		case 0x23:			/* Rom 8x8 double dot set */
245 			RealSetVec(0x43,int10.rom.font_8_first);
246 			real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,8);
247 			goto graphics_chars;
248 		case 0x24:			/* Rom 8x16 set */
249 			if (!IS_VGA_ARCH) break;
250 			RealSetVec(0x43,int10.rom.font_16);
251 			real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,16);
252 			goto graphics_chars;
253 graphics_chars:
254 			switch (reg_bl) {
255 			case 0x00:real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,reg_dl-1);break;
256 			case 0x01:real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,13);break;
257 			case 0x03:real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,42);break;
258 			case 0x02:
259 			default:real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,24);break;
260 			}
261 			break;
262 /* General */
263 		case 0x30:/* Get Font Information */
264 			switch (reg_bh) {
265 			case 0x00:	/* interupt 0x1f vector */
266 				{
267 					RealPt int_1f=RealGetVec(0x1f);
268 					SegSet16(es,RealSeg(int_1f));
269 					reg_bp=RealOff(int_1f);
270 				}
271 				break;
272 			case 0x01:	/* interupt 0x43 vector */
273 				{
274 					RealPt int_43=RealGetVec(0x43);
275 					SegSet16(es,RealSeg(int_43));
276 					reg_bp=RealOff(int_43);
277 				}
278 				break;
279 			case 0x02:	/* font 8x14 */
280 				SegSet16(es,RealSeg(int10.rom.font_14));
281 				reg_bp=RealOff(int10.rom.font_14);
282 				break;
283 			case 0x03:	/* font 8x8 first 128 */
284 				SegSet16(es,RealSeg(int10.rom.font_8_first));
285 				reg_bp=RealOff(int10.rom.font_8_first);
286 				break;
287 			case 0x04:	/* font 8x8 second 128 */
288 				SegSet16(es,RealSeg(int10.rom.font_8_second));
289 				reg_bp=RealOff(int10.rom.font_8_second);
290 				break;
291 			case 0x05:	/* alpha alternate 9x14 */
292 				SegSet16(es,RealSeg(int10.rom.font_14_alternate));
293 				reg_bp=RealOff(int10.rom.font_14_alternate);
294 				break;
295 			case 0x06:	/* font 8x16 */
296 				if (!IS_VGA_ARCH) break;
297 				SegSet16(es,RealSeg(int10.rom.font_16));
298 				reg_bp=RealOff(int10.rom.font_16);
299 				break;
300 			case 0x07:	/* alpha alternate 9x16 */
301 				if (!IS_VGA_ARCH) break;
302 				SegSet16(es,RealSeg(int10.rom.font_16_alternate));
303 				reg_bp=RealOff(int10.rom.font_16_alternate);
304 				break;
305 			default:
306 				LOG(LOG_INT10,LOG_ERROR)("Function 11:30 Request for font %2X",reg_bh);
307 				break;
308 			}
309 			if ((reg_bh<=7) || (svgaCard==SVGA_TsengET4K)) {
310 				reg_cx=real_readw(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT);
311 				reg_dl=real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS);
312 			}
313 			break;
314 		default:
315 			LOG(LOG_INT10,LOG_ERROR)("Function 11:Unsupported character generator call %2X",reg_al);
316 			break;
317 		}
318 		if ((reg_al&0xf0)==0x10) Mouse_AfterNewVideoMode(false);
319 		break;
320 	case 0x12:								/* alternate function select */
321 		if (!IS_EGAVGA_ARCH)
322 			break;
323 		switch (reg_bl) {
324 		case 0x10:							/* Get EGA Information */
325 			reg_bh=(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)==0x3B4);
326 			reg_bl=3;	//256 kb
327 			reg_cl=real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES) & 0x0F;
328 			reg_ch=real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES) >> 4;
329 			break;
330 		case 0x20:							/* Set alternate printscreen */
331 			break;
332 		case 0x30:							/* Select vertical resolution */
333 			{
334 				if (!IS_VGA_ARCH) break;
335 				LOG(LOG_INT10,LOG_WARN)("Function 12:Call %2X (select vertical resolution)",reg_bl);
336 				if (svgaCard != SVGA_None) {
337 					if (reg_al > 2) {
338 						reg_al=0;		// invalid subfunction
339 						break;
340 					}
341 				}
342 				Bit8u modeset_ctl = real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
343 				Bit8u video_switches = real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES)&0xf0;
344 				switch(reg_al) {
345 				case 0: // 200
346 					modeset_ctl &= 0xef;
347 					modeset_ctl |= 0x80;
348 					video_switches |= 8;	// ega normal/cga emulation
349 					break;
350 				case 1: // 350
351 					modeset_ctl &= 0x6f;
352 					video_switches |= 9;	// ega enhanced
353 					break;
354 				case 2: // 400
355 					modeset_ctl &= 0x6f;
356 					modeset_ctl |= 0x10;	// use 400-line mode at next mode set
357 					video_switches |= 9;	// ega enhanced
358 					break;
359 				default:
360 					modeset_ctl &= 0xef;
361 					video_switches |= 8;	// ega normal/cga emulation
362 					break;
363 				}
364 				real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,modeset_ctl);
365 				real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,video_switches);
366 				reg_al=0x12;	// success
367 				break;
368 			}
369 		case 0x31:							/* Palette loading on modeset */
370 			{
371 				if (!IS_VGA_ARCH) break;
372 				if (svgaCard==SVGA_TsengET4K) reg_al&=1;
373 				if (reg_al>1) {
374 					reg_al=0;		//invalid subfunction
375 					break;
376 				}
377 				Bit8u temp = real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL) & 0xf7;
378 				if (reg_al&1) temp|=8;		// enable if al=0
379 				real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,temp);
380 				reg_al=0x12;
381 				break;
382 			}
383 		case 0x32:							/* Video addressing */
384 			if (!IS_VGA_ARCH) break;
385 			LOG(LOG_INT10,LOG_ERROR)("Function 12:Call %2X not handled",reg_bl);
386 			if (svgaCard==SVGA_TsengET4K) reg_al&=1;
387 			if (reg_al>1) reg_al=0;		//invalid subfunction
388 			else reg_al=0x12;			//fake a success call
389 			break;
390 		case 0x33: /* SWITCH GRAY-SCALE SUMMING */
391 			{
392 				if (!IS_VGA_ARCH) break;
393 				if (svgaCard==SVGA_TsengET4K) reg_al&=1;
394 				if (reg_al>1) {
395 					reg_al=0;
396 					break;
397 				}
398 				Bit8u temp = real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL) & 0xfd;
399 				if (!(reg_al&1)) temp|=2;		// enable if al=0
400 				real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,temp);
401 				reg_al=0x12;
402 				break;
403 			}
404 		case 0x34: /* ALTERNATE FUNCTION SELECT (VGA) - CURSOR EMULATION */
405 			{
406 				// bit 0: 0=enable, 1=disable
407 				if (!IS_VGA_ARCH) break;
408 				if (svgaCard==SVGA_TsengET4K) reg_al&=1;
409 				if (reg_al>1) {
410 					reg_al=0;
411 					break;
412 				}
413 				Bit8u temp = real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & 0xfe;
414 				real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,temp|reg_al);
415 				reg_al=0x12;
416 				break;
417 			}
418 		case 0x35:
419 			if (!IS_VGA_ARCH) break;
420 			LOG(LOG_INT10,LOG_ERROR)("Function 12:Call %2X not handled",reg_bl);
421 			reg_al=0x12;
422 			break;
423 		case 0x36: {						/* VGA Refresh control */
424 			if (!IS_VGA_ARCH) break;
425 			if ((svgaCard==SVGA_S3Trio) && (reg_al>1)) {
426 				reg_al=0;
427 				break;
428 			}
429 			IO_Write(0x3c4,0x1);
430 			Bit8u clocking = IO_Read(0x3c5);
431 
432 			if (reg_al==0) clocking &= ~0x20;
433 			else clocking |= 0x20;
434 
435 			IO_Write(0x3c4,0x1);
436 			IO_Write(0x3c5,clocking);
437 
438 			reg_al=0x12; // success
439 			break;
440 		}
441 		default:
442 			LOG(LOG_INT10,LOG_ERROR)("Function 12:Call %2X not handled",reg_bl);
443 			if (machine!=MCH_EGA) reg_al=0;
444 			break;
445 		}
446 		break;
447 	case 0x13:								/* Write String */
448 		INT10_WriteString(reg_dh,reg_dl,reg_al,reg_bl,SegPhys(es)+reg_bp,reg_cx,reg_bh);
449 		break;
450 	case 0x1A:								/* Display Combination */
451 		if (!IS_VGA_ARCH) break;
452 		if (reg_al==0) {	// get dcc
453 			// walk the tables...
454 			RealPt vsavept=real_readd(BIOSMEM_SEG,BIOSMEM_VS_POINTER);
455 			RealPt svstable=real_readd(RealSeg(vsavept),RealOff(vsavept)+0x10);
456 			if (svstable) {
457 				RealPt dcctable=real_readd(RealSeg(svstable),RealOff(svstable)+0x02);
458 				Bit8u entries=real_readb(RealSeg(dcctable),RealOff(dcctable)+0x00);
459 				Bit8u idx=real_readb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX);
460 				// check if index within range
461 				if (idx<entries) {
462 					Bit16u dccentry=real_readw(RealSeg(dcctable),RealOff(dcctable)+0x04+idx*2);
463 					if ((dccentry&0xff)==0) reg_bx=dccentry>>8;
464 					else reg_bx=dccentry;
465 				} else reg_bx=0xffff;
466 			} else reg_bx=0xffff;
467 			reg_ax=0x1A;	// high part destroyed or zeroed depending on BIOS
468 		} else if (reg_al==1) {	// set dcc
469 			Bit8u newidx=0xff;
470 			// walk the tables...
471 			RealPt vsavept=real_readd(BIOSMEM_SEG,BIOSMEM_VS_POINTER);
472 			RealPt svstable=real_readd(RealSeg(vsavept),RealOff(vsavept)+0x10);
473 			if (svstable) {
474 				RealPt dcctable=real_readd(RealSeg(svstable),RealOff(svstable)+0x02);
475 				Bit8u entries=real_readb(RealSeg(dcctable),RealOff(dcctable)+0x00);
476 				if (entries) {
477 					Bitu ct;
478 					Bit16u swpidx=reg_bh|(reg_bl<<8);
479 					// search the ddc index in the dcc table
480 					for (ct=0; ct<entries; ct++) {
481 						Bit16u dccentry=real_readw(RealSeg(dcctable),RealOff(dcctable)+0x04+ct*2);
482 						if ((dccentry==reg_bx) || (dccentry==swpidx)) {
483 							newidx=(Bit8u)ct;
484 							break;
485 						}
486 					}
487 				}
488 			}
489 
490 			real_writeb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,newidx);
491 			reg_ax=0x1A;	// high part destroyed or zeroed depending on BIOS
492 		}
493 		break;
494 	case 0x1B:								/* functionality State Information */
495 		if (!IS_VGA_ARCH) break;
496 		switch (reg_bx) {
497 		case 0x0000:
498 			INT10_GetFuncStateInformation(SegPhys(es)+reg_di);
499 			reg_al=0x1B;
500 			break;
501 		default:
502 			LOG(LOG_INT10,LOG_ERROR)("1B:Unhandled call BX %2X",reg_bx);
503 			reg_al=0;
504 			break;
505 		}
506 		break;
507 	case 0x1C:	/* Video Save Area */
508 		if (!IS_VGA_ARCH) break;
509 		switch (reg_al) {
510 			case 0: {
511 				Bitu ret=INT10_VideoState_GetSize(reg_cx);
512 				if (ret) {
513 					reg_al=0x1c;
514 					reg_bx=(Bit16u)ret;
515 				} else reg_al=0;
516 				}
517 				break;
518 			case 1:
519 				if (INT10_VideoState_Save(reg_cx,RealMake(SegValue(es),reg_bx))) reg_al=0x1c;
520 				else reg_al=0;
521 				break;
522 			case 2:
523 				if (INT10_VideoState_Restore(reg_cx,RealMake(SegValue(es),reg_bx))) reg_al=0x1c;
524 				else reg_al=0;
525 				break;
526 			default:
527 				if (svgaCard==SVGA_TsengET4K) reg_ax=0;
528 				else reg_al=0;
529 				break;
530 		}
531 		break;
532 	case 0x4f:								/* VESA Calls */
533 		if ((!IS_VGA_ARCH) || (svgaCard!=SVGA_S3Trio)) break;
534 		switch (reg_al) {
535 		case 0x00:							/* Get SVGA Information */
536 			reg_al=0x4f;
537 			reg_ah=VESA_GetSVGAInformation(SegValue(es),reg_di);
538 			break;
539 		case 0x01:							/* Get SVGA Mode Information */
540 			reg_al=0x4f;
541 			reg_ah=VESA_GetSVGAModeInformation(reg_cx,SegValue(es),reg_di);
542 			break;
543 		case 0x02:							/* Set videomode */
544 			Mouse_BeforeNewVideoMode(true);
545 			reg_al=0x4f;
546 			reg_ah=VESA_SetSVGAMode(reg_bx);
547 			Mouse_AfterNewVideoMode(true);
548 			break;
549 		case 0x03:							/* Get videomode */
550 			reg_al=0x4f;
551 			reg_ah=VESA_GetSVGAMode(reg_bx);
552 			break;
553 		case 0x04:							/* Save/restore state */
554 			reg_al=0x4f;
555 			switch (reg_dl) {
556 				case 0: {
557 					Bitu ret=INT10_VideoState_GetSize(reg_cx);
558 					if (ret) {
559 						reg_ah=0;
560 						reg_bx=(Bit16u)ret;
561 					} else reg_ah=1;
562 					}
563 					break;
564 				case 1:
565 					if (INT10_VideoState_Save(reg_cx,RealMake(SegValue(es),reg_bx))) reg_ah=0;
566 					else reg_ah=1;
567 					break;
568 				case 2:
569 					if (INT10_VideoState_Restore(reg_cx,RealMake(SegValue(es),reg_bx))) reg_ah=0;
570 					else reg_ah=1;
571 					break;
572 				default:
573 					reg_ah=1;
574 					break;
575 			}
576 			break;
577 		case 0x05:
578 			if (reg_bh==0) {				/* Set CPU Window */
579 				reg_ah=VESA_SetCPUWindow(reg_bl,reg_dl);
580 				reg_al=0x4f;
581 			} else if (reg_bh == 1) {		/* Get CPU Window */
582 				reg_ah=VESA_GetCPUWindow(reg_bl,reg_dx);
583 				reg_al=0x4f;
584 			} else {
585 				LOG(LOG_INT10,LOG_ERROR)("Unhandled VESA Function %X Subfunction %X",reg_al,reg_bh);
586 				reg_ah=0x01;
587 			}
588 			break;
589 		case 0x06:
590 			reg_al=0x4f;
591 			reg_ah=VESA_ScanLineLength(reg_bl,reg_cx,reg_bx,reg_cx,reg_dx);
592 			break;
593 		case 0x07:
594 			switch (reg_bl) {
595 			case 0x80:						/* Set Display Start during retrace ?? */
596 			case 0x00:						/* Set display Start */
597 				reg_al=0x4f;
598 				reg_ah=VESA_SetDisplayStart(reg_cx,reg_dx);
599 				break;
600 			case 0x01:
601 				reg_al=0x4f;
602 				reg_bh=0x00;				//reserved
603 				reg_ah=VESA_GetDisplayStart(reg_cx,reg_dx);
604 				break;
605 			default:
606 				LOG(LOG_INT10,LOG_ERROR)("Unhandled VESA Function %X Subfunction %X",reg_al,reg_bl);
607 				reg_ah=0x1;
608 				break;
609 			}
610 			break;
611 		case 0x09:
612 			switch (reg_bl) {
613 			case 0x80:						/* Set Palette during retrace */
614 				//TODO
615 			case 0x00:						/* Set Palette */
616 				reg_ah=VESA_SetPalette(SegPhys(es)+reg_di,reg_dx,reg_cx);
617 				reg_al=0x4f;
618 				break;
619 			case 0x01:						/* Get Palette */
620 				reg_ah=VESA_GetPalette(SegPhys(es)+reg_di,reg_dx,reg_cx);
621 				reg_al=0x4f;
622 				break;
623 			default:
624 				LOG(LOG_INT10,LOG_ERROR)("Unhandled VESA Function %X Subfunction %X",reg_al,reg_bl);
625 				reg_ah=0x01;
626 				break;
627 			}
628 			break;
629 		case 0x0a:							/* Get Pmode Interface */
630 			if (int10.vesa_oldvbe) {
631 				reg_ax=0x014f;
632 				break;
633 			}
634 			switch (reg_bl) {
635 			case 0x00:
636 				reg_edi=RealOff(int10.rom.pmode_interface);
637 				SegSet16(es,RealSeg(int10.rom.pmode_interface));
638 				reg_cx=int10.rom.pmode_interface_size;
639 				reg_ax=0x004f;
640 				break;
641 			case 0x01:						/* Get code for "set window" */
642 				reg_edi=RealOff(int10.rom.pmode_interface)+int10.rom.pmode_interface_window;
643 				SegSet16(es,RealSeg(int10.rom.pmode_interface));
644 				reg_cx=0x10;		//0x10 should be enough for the callbacks
645 				reg_ax=0x004f;
646 				break;
647 			case 0x02:						/* Get code for "set display start" */
648 				reg_edi=RealOff(int10.rom.pmode_interface)+int10.rom.pmode_interface_start;
649 				SegSet16(es,RealSeg(int10.rom.pmode_interface));
650 				reg_cx=0x10;		//0x10 should be enough for the callbacks
651 				reg_ax=0x004f;
652 				break;
653 			case 0x03:						/* Get code for "set palette" */
654 				reg_edi=RealOff(int10.rom.pmode_interface)+int10.rom.pmode_interface_palette;
655 				SegSet16(es,RealSeg(int10.rom.pmode_interface));
656 				reg_cx=0x10;		//0x10 should be enough for the callbacks
657 				reg_ax=0x004f;
658 				break;
659 			default:
660 				reg_ax=0x014f;
661 				break;
662 			}
663 			break;
664 
665 		default:
666 			LOG(LOG_INT10,LOG_ERROR)("Unhandled VESA Function %X",reg_al);
667 			reg_al=0x0;
668 			break;
669 		}
670 		break;
671 	case 0xf0:
672 		INT10_EGA_RIL_ReadRegister(reg_bl, reg_dx);
673 		break;
674 	case 0xf1:
675 		INT10_EGA_RIL_WriteRegister(reg_bl, reg_bh, reg_dx);
676 		break;
677 	case 0xf2:
678 		INT10_EGA_RIL_ReadRegisterRange(reg_ch, reg_cl, reg_dx, SegPhys(es)+reg_bx);
679 		break;
680 	case 0xf3:
681 		INT10_EGA_RIL_WriteRegisterRange(reg_ch, reg_cl, reg_dx, SegPhys(es)+reg_bx);
682 		break;
683 	case 0xf4:
684 		INT10_EGA_RIL_ReadRegisterSet(reg_cx, SegPhys(es)+reg_bx);
685 		break;
686 	case 0xf5:
687 		INT10_EGA_RIL_WriteRegisterSet(reg_cx, SegPhys(es)+reg_bx);
688 		break;
689 	case 0xfa: {
690 		RealPt pt=INT10_EGA_RIL_GetVersionPt();
691 		SegSet16(es,RealSeg(pt));
692 		reg_bx=RealOff(pt);
693 		}
694 		break;
695 	case 0xff:
696 		if (!warned_ff) LOG(LOG_INT10,LOG_NORMAL)("INT10:FF:Weird NC call");
697 		warned_ff=true;
698 		break;
699 	default:
700 		LOG(LOG_INT10,LOG_ERROR)("Function %4X not supported",reg_ax);
701 //		reg_al=0x00;		//Successfull, breaks marriage
702 		break;
703 	};
704 	return CBRET_NONE;
705 }
706 
INT10_Seg40Init(void)707 static void INT10_Seg40Init(void) {
708 	// the default char height
709 	real_writeb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,16);
710 	// Clear the screen
711 	real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,0x60);
712 	// Set the basic screen we have
713 	real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
714 	// Set the basic modeset options
715 	real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,0x51);
716 	// Set the  default MSR
717 	real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x09);
718 	// Set the pointer to video save pointer table
719 	real_writed(BIOSMEM_SEG,BIOSMEM_VS_POINTER,int10.rom.video_save_pointers);
720 }
721 
722 
INT10_InitVGA(void)723 static void INT10_InitVGA(void) {
724 	if (IS_EGAVGA_ARCH) {
725 		/* switch to color mode and enable CPU access 480 lines */
726 		IO_Write(0x3c2,0xc3);
727 		/* More than 64k */
728 		IO_Write(0x3c4,0x04);
729 		IO_Write(0x3c5,0x02);
730 		if (IS_VGA_ARCH) {
731 			/* Initialize DAC */
732 			IO_Write(0x3c8,0);
733 			for (Bitu i=0;i<3*256;i++) IO_Write(0x3c9,0);
734 		}
735 	}
736 }
737 
SetupTandyBios(void)738 static void SetupTandyBios(void) {
739 	static Bit8u TandyConfig[130]= {
740 		0x21, 0x42, 0x49, 0x4f, 0x53, 0x20, 0x52, 0x4f, 0x4d, 0x20, 0x76, 0x65, 0x72,
741 		0x73, 0x69, 0x6f, 0x6e, 0x20, 0x30, 0x32, 0x2e, 0x30, 0x30, 0x2e, 0x30, 0x30,
742 		0x0d, 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69,
743 		0x74, 0x79, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0d, 0x0a,
744 		0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29,
745 		0x20, 0x31, 0x39, 0x38, 0x34, 0x2c, 0x31, 0x39, 0x38, 0x35, 0x2c, 0x31, 0x39,
746 		0x38, 0x36, 0x2c, 0x31, 0x39, 0x38, 0x37, 0x0d, 0x0a, 0x50, 0x68, 0x6f, 0x65,
747 		0x6e, 0x69, 0x78, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20,
748 		0x41, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x73, 0x20, 0x4c, 0x74,
749 		0x64, 0x2e, 0x0d, 0x0a, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x61, 0x6e, 0x64, 0x79
750 	};
751 	if (machine==MCH_TANDY) {
752 		Bitu i;
753 		for(i=0;i<130;i++) {
754 			phys_writeb(0xf0000+i+0xc000, TandyConfig[i]);
755 		}
756 	}
757 }
758 
INT10_Init(Section *)759 void INT10_Init(Section* /*sec*/) {
760 	INT10_InitVGA();
761 	if (IS_TANDY_ARCH) SetupTandyBios();
762 	/* Setup the INT 10 vector */
763 	call_10=CALLBACK_Allocate();
764 	CALLBACK_Setup(call_10,&INT10_Handler,CB_IRET,"Int 10 video");
765 	RealSetVec(0x10,CALLBACK_RealPointer(call_10));
766 	//Init the 0x40 segment and init the datastructures in the the video rom area
767 	INT10_SetupRomMemory();
768 	INT10_Seg40Init();
769 	INT10_SetVideoMode(0x3);
770 }
771