home *** CD-ROM | disk | FTP | other *** search
- /* 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 > 0) 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;
- }
- }
-
-