ftp.nice.ch/pub/next/developer/languages/c/djgpp-NS.s.tar.gz#/djgpp/go32/graphics.c

This is graphics.c in view mode; [Download] [Up]

/* This is file GRAPHICS.C */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
** Copyright (C) 1993 Grzegorz Mazur, gbm@ii.pw.edu.pl
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained.  This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

#pragma inline

/* History:42,23 */
#include <dos.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <alloc.h>
#include <string.h>
#include <io.h>

#include "gotypes.h"
#include "paging.h"
#include "graphics.h"
#include "tss.h"
#include "gdt.h"
#include "grdriver.h"

extern fillgdt(int sel, word32 limit, word32 base, word8 type, int G);

/* DJ - tcc 2.0 can't handle far arrays */
/* extern char far builtin_driver_code[]; */
extern char builtin_driver_code[];
/* DJ - end */

extern int  builtin_driver_size;

/* driver version defs */
#define BAD	(-2)			/* tried loading -- driver reports error */
#define UNK	(-1)			/* unknown -- no graphics call made yet */
#define GRD	0			/* DJ's original 256 color driver */
#define GRN	1			/* GRX 1.01+ programmable color driver */
#define VDR	2			/* GRX 1.03+ VESA compatible extended driver */

/* driver stuff */
static GrDriverHeader far *driver = NULL;
static char *drv_name = NULL;
static char  drv_version = UNK;

/* driver default parameters filled out from GO32 env. var. */
int gr_def_tw = 0;
int gr_def_th = 0;
int gr_def_gw = 0;
int gr_def_gh = 0;
int gr_def_numcolor = 0;

/* Direct INT 10h function calls with AX >= this value to the 'graphics_assist' function */
/* One of the 'graphics_assist' functions can be used to reset this to 0xff00 */
/* Older versions of GRX used INT 10h, AH=0FEh to get the driver mode parameters. */
/* GRX 1.03+ does not use this call any more. Desqview also seems to be using the */
/* INT 10h, AH=0FEh call. By allowing to reset this value to 0xff00, GO32 will support */
/* both. Later when GRX 1.03 and later versions will be more out for some time we can */
/* change the default... */
word16 gr_assist_func_start = 0xfe00;

/* two graphics page tables */
word32 far *graphics_pt1 = NULL;
word32 far *graphics_pt2 = NULL;
word32 graphics_pt1_lin;
word32 graphics_pt2_lin;

/* pointers necessary for moving the graphics page tables in the page directory */
/* they point to the start of the graphics region in the PD-s */
word32 far *graphics_pd;
word8  far *graphics_pd_seg;
word32 graphics_pd_lin;
word32 graphics_pd_seg_lin;

/* current location of the two page tables */
word16 graphics_pt1_loc;
word16 graphics_pt2_loc;

/* the protected mode paging function */
word32 gr_paging_func;

/* linear pointers to prepared page table segments */
word32 gr_rw_table_lin;
word32 gr_ro_table_lin;
word32 gr_wo_table_lin;

/* other parameters for protected mode paging routine */
word32 gr_sgl_page_size  = 16;		/* R/W page size in 4kByte units */
word32 gr_r_w_page_size  = 16;		/* split page sizes in 4kByte units */
word8  gr_sgl_page_shift = 4;		/* log2 of the R/W page size in 4kByte units */
word8  gr_r_w_page_shift = 4;		/* log2 of the split page sizes in 4kByte units */
word8  gr_rw_page_offset = 0;		/* diff between two windows in R/W mode (ATI!) */

/* prepared page table segments: */
/* paging code can use rep movsl-s instead of fiddling with bits */
/* allocate enough space for 128kByte graphics map */
/* also contains the real mode paging parameter transfer buffer */

/* DJ - tcc 2.0 can't do far arrays */
/* static word32 far  gr_prepared_tables[3*(128/4) + 4 + 1]; */
static word32 gr_prepared_tables[3*(128/4) + 4 + 1];
/* DJ - end */

static word32 far *gr_rw_table;
static word32 far *gr_ro_table;
static word32 far *gr_wo_table;

/* stuff for the real-mode paging function interface */
word32 real_paging_buffer_lin;		/* linear address of param passing buffer */
word32 real_paging_buffer_virt;		/* virtual address of param passing buffer */
word32 real_paging_func_virt;		/* virtual address of the arena paging function */

extern void far real_paging_routine(void);
extern void far arena_real_paging_func(void);

static void far dummy_paging_routine(void)
{
	return;
}

static void fbzero(void far *addr,int size)
{
	asm les  di,dword ptr addr;
	asm mov  cx,word  ptr size;
	asm shr  cx,1;
	asm je	 done;
	asm xor  ax,ax;
	asm rep  stosw;
      done:
	return;
}

static void setup_paging_routine(void)
{
	word16 gr_seg  = (drv_version <= UNK) ? FP_SEG(dummy_paging_routine) : FP_SEG(driver);
	word16 gr_off  = (drv_version <= UNK) ? FP_OFF(dummy_paging_routine) : driver->paging_routine;
	word32 rw_addr = 0x000a0000L;
	word32 ro_addr = 0x000a0000L;
	word32 wo_addr = 0x000a0000L;
	int i;

	if(drv_version == VDR) {
	    rw_addr = wo_addr = (word32)driver->wr_page_start << 4;
	    ro_addr = (driver->rd_page_start == 0xffff) ?
			rw_addr :
			(word32)driver->rd_page_start << 4;
	    gr_sgl_page_shift = gr_r_w_page_shift = driver->page_size_shift;
	    gr_rw_page_offset = 0;
	    if(ro_addr > wo_addr) {
		/* ATI style paging: two split READ/WRITE 32kByte pages */
		/* it is handled by mapping the two pages continguously in R/W mode to */
		/* form a single 64K page. In separate R and W mode we have two */
		/* 32 kByte pages. For this we need an offset of one between the two */
		/* page indices in R/W mode */
		gr_sgl_page_shift++;
		gr_rw_page_offset = 1;
	    }
	    gr_sgl_page_size = 1 << gr_sgl_page_shift;
	    gr_r_w_page_size = 1 << gr_r_w_page_shift;
	    if(driver->driver_options & GRD_PROTECTED_PAGING) {
		if(driver->VESA_paging_fnc != 0L) {
		    fillgdt(g_VESAfunc, 0xffff,
			(word32)FP_SEG(driver->VESA_paging_fnc) * 16L,
			0x9a, 0
		    );
		    driver->VESA_paging_fnc = MK_FP(
			(g_VESAfunc << 3),
			FP_OFF(driver->VESA_paging_fnc)
		    );
		}
	    }
	    else {
		gr_seg = FP_SEG(real_paging_routine);
		gr_off = FP_OFF(real_paging_routine);
	    }
	}
	fillgdt(g_grdr, 0xffff, (word32)gr_seg << 4, 0x9a, 0);
	gr_paging_func = (word32)MK_FP((g_grdr << 3),gr_off);
	fbzero(gr_prepared_tables,sizeof(gr_prepared_tables));
	if(graphics_pt1) {
	    fbzero(graphics_pt1,4096);
	    fbzero(graphics_pt2,4096);
	}
	for(i = 0; i < (int)gr_sgl_page_size; i++) {
	    gr_rw_table[i] = rw_addr | (PT_W | PT_U | PT_P);
	    rw_addr += 4096;
	}
	for(i = 0; i < (int)gr_r_w_page_size; i++) {
	    gr_wo_table[i] = wo_addr | (PT_W | PT_U | PT_P);
	    gr_ro_table[i] = ro_addr | (PT_U | PT_P);
	    wo_addr += 4096;
	    ro_addr += 4096;
	}
}

void setup_graphics_driver(char *name)
{
	word32 far *real_paging_buf;

	if(name != NULL) drv_name = strdup(name);
	gr_rw_table = MK_FP(FP_SEG(gr_prepared_tables),((FP_OFF(gr_prepared_tables) + 3) & ~3));
	gr_ro_table = gr_rw_table + 128/4;
	gr_wo_table = gr_ro_table + 128/4;
	gr_rw_table_lin = ptr2linear(gr_rw_table);
	gr_ro_table_lin = ptr2linear(gr_ro_table);
	gr_wo_table_lin = ptr2linear(gr_wo_table);
	real_paging_buf = gr_wo_table + 128/4;
	real_paging_buffer_lin  = ptr2linear(real_paging_buf);
	real_paging_buffer_virt = real_paging_buffer_lin + 0xe0000000L;
	real_paging_func_virt	= ptr2linear(arena_real_paging_func) + 0xe0000000L;
	setup_paging_routine();
}

static void load_graphics_driver(void)
{
	int  far (*init_func)(void);
	char *try,*opt = NULL;
	char far *p1,far *p2;
	FILE *drvfile;
	int  size,ch;

	if(drv_version != UNK) return;
	if(drv_name) {
	    for(try = drv_name; (try = strchr(try,':')) != NULL; try++) {
		if(try[1] == ':') {
		    opt = &try[2];
		    *try = '\0';
		    break;
		}
	    }
	    if((*drv_name != '\0') && ((drvfile = fopen(drv_name,"rb")) != NULL)) {
		try  = NULL;
		size = (int)filelength(fileno(drvfile));
		if((size >= 100) && ((size <= builtin_driver_size) || ((try = malloc(size + 16)) != NULL))) {
		    p1 = (size <= builtin_driver_size) ? builtin_driver_code : (char far *)try;
		    p1 = MK_FP((FP_SEG(p1) + ((FP_OFF(p1) + 15) >> 4)),0);
		    driver = (GrDriverHeader far *)p1;
		    while(--size >= 0) {
			if((ch = fgetc(drvfile)) == EOF) {
			    /* bad driver file, disk error, etc..? */
			    if(try || (p1 == (char *)driver)) {
				/* fortunately we still have the original */
				if(try) free(try);
				driver = NULL;
			    }
			    else {
				/* no help, even the built-in driver is screwed up now */
				drv_version = BAD;
			    }
			    break;
			}
			*p1++ = ch;
		    }
		}
		fclose(drvfile);
	    }
	}
	if(drv_version != BAD) {
	    drv_version = GRD;
	    if(!driver) {
		driver = MK_FP((FP_SEG(builtin_driver_code) + ((FP_OFF(builtin_driver_code) + 15) >> 4)),0);
		if(FP_OFF(builtin_driver_code) & 15) {
		    size = builtin_driver_size;
		    p1 = (char far *)driver + size;
		    p2 = builtin_driver_code + size;
		    while(--size >= 0) *(--p1) = *(--p2);
		}
	    }
	    if(driver->driver_flags & GRD_NEW_DRIVER) {
		p1 = (char far *)driver->vdr_magic;
		p2 = ".VDR driver";
		while(*p1 && (*p1 == *p2)) p1++,p2++;
		drv_version = (*p1 == *p2) ? VDR : GRN;
		if((drv_version == VDR) && opt) while(*opt != '\0') {
		    switch(*opt) {
		      case 'P':
		      case 'p':
			driver->driver_options |= GRD_PROTECTED_PAGING;
			break;
		      case 'F':
		      case 'f':
			driver->driver_options |= GRD_FAST_256_MODE;
			break;
		      case '5':
			driver->driver_options |= GRD_15_PLANE_MODE;
			break;
		    }
		    opt++;
		}
		init_func = MK_FP(FP_SEG(driver),driver->driver_init_routine);
		_AX = FP_SEG(driver);
		asm push ds;
		asm mov  ds,ax;
		asm call dword ptr ss:[init_func];
		asm pop  ds;
		if(_AX == 0) {
		    /* You may want to do something more appropriate here */
		    fputs("Graphics initialization error -- probably incorrect driver\n",stderr);
		    drv_version = BAD;
		}
	    }
	    switch(drv_version) {
	      case VDR:
	      case GRN:
		if(gr_def_numcolor) driver->def_numcolor = gr_def_numcolor;
	      case GRD:
		if(gr_def_tw > 0) driver->def_tw = gr_def_tw;
		if(gr_def_th > 0) driver->def_th = gr_def_th;
		if(gr_def_gw > 0) driver->def_gw = gr_def_gw;
		if(gr_def_gh > 0) driver->def_gh = gr_def_gh;
	    }
	}
	if(drv_name) free(drv_name);
	setup_paging_routine();
}

static word32 add_driver_version(word16 flags)
{
	switch(drv_version) {
	    case GRD: return(flags | GR_DRV_VER_GRD);
	    case GRN: return(flags | GR_DRV_VER_GRN);
	    case VDR: return(flags | GR_DRV_VER_VDR);
	    default:  return(-1L);
	}
}

void graphics_assist(void)
{
	void far (*driver_func)(void);
	word16 mode,cnum,cols,rows;

	switch((word16)tss_ptr->tss_eax & 0xff00) {
	  case 0xff00:					/* graphics assist function */
	    switch(mode = ((word16)tss_ptr->tss_eax & 0x00ff)) {
	      case 0x00ff:				/* SUB-FNC 0xFF: make GO32 Desqview compatible */
		gr_assist_func_start = 0xff00;
		break;
	      case 0x00fe:				/* SUB-FNC 0xFE: return driver header adr */
		if(drv_version == UNK) load_graphics_driver();
		/* don't add 0xe0000000 -- GRX will figure whether running under DPMI or VCPI */
		tss_ptr->tss_eax = (drv_version == BAD) ? 0L : (word32)ptr2linear(driver);
		break;
	      case 0x00fd:				/* SUB-FNC 0xFD: call pg fnc in real mode */
		if(drv_version < GRD) break;
		driver_func = MK_FP(FP_SEG(driver),driver->paging_routine);
		_AX = (word16)tss_ptr->tss_ebx;
		asm push si;
		asm push di;
		asm call dword ptr ss:[driver_func];
		asm pop  di;
		asm pop  si;
		break;
	      case 0x00fc:				/* SUB-FNC 0xFC: set virtual screen start */
		if(drv_version != VDR) break;
		cols = (word16)tss_ptr->tss_ecx;
		rows = (word16)tss_ptr->tss_edx;
		driver_func = MK_FP(FP_SEG(driver),driver->set_screen_start);
		_AX  = FP_SEG(driver);
		asm mov  cx,word ptr cols;
		asm mov  dx,word ptr rows;
		asm push ds;
		asm mov  ds,ax;
		asm call dword ptr ss:[driver_func];
		asm pop  ds;
		break;
	      default:					/* mode set */
		if(drv_version == UNK) load_graphics_driver();
		switch(drv_version) {
		  case GRD:
		    if(mode > 8) mode = 8;
		  case GRN:
		    if(mode > 9) mode = 9;
		  case VDR:
		    if((mode & 0x7f) > 10) mode = (mode & 0x80) + 10;
		    cnum = (word16)tss_ptr->tss_ebx;
		    cols = (word16)tss_ptr->tss_ecx;
		    rows = (word16)tss_ptr->tss_edx;
		    driver_func = MK_FP(FP_SEG(driver),driver->modeset_routine);
		    _AX  = FP_SEG(driver);
		    asm push ds;
		    asm push ax;
		    asm mov  ax,word ptr mode;
		    asm mov  bx,word ptr cnum;
		    asm mov  cx,word ptr cols;
		    asm mov  dx,word ptr rows;
		    asm pop  ds;
		    asm call dword ptr ss:[driver_func];
		    asm pop  ds;
		    asm mov  word ptr cnum,bx;
		    asm mov  word ptr cols,cx;
		    asm mov  word ptr rows,dx;
		    tss_ptr->tss_ebx = add_driver_version(cnum);
		    tss_ptr->tss_ecx = (word32)cols;
		    tss_ptr->tss_edx = (word32)rows;
		    setup_paging_routine();
		    break;
		  default:
		    /* BAD driver -- only perform text mode sets */
		    if(mode < 4) {
			_AX = 3;
			geninterrupt(0x10);
			tss_ptr->tss_ebx = 0;
			tss_ptr->tss_ecx = 80;
			tss_ptr->tss_edx = 25;
			break;
		    }
		    tss_ptr->tss_ebx = (-1);		/* signal error */
		    break;
		}
	    }
	    break;
	  case 0xfe00:					/* old style driver mode info */
	    if(drv_version == UNK) load_graphics_driver();
	    tss_ptr->tss_ebx = (drv_version < GRD) ? -1L : add_driver_version(driver->driver_flags);
	    tss_ptr->tss_ecx = (drv_version < GRN) ?  0L : 0xe0000000L + ptr2linear(MK_FP(FP_SEG(driver),driver->text_table));
	    tss_ptr->tss_edx = (drv_version < GRN) ?  0L : 0xe0000000L + ptr2linear(MK_FP(FP_SEG(driver),driver->graphics_table));
	    break;
	}
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.