/* * BDM2: Banked dumb monochrome driver * Pascal Haible 8/93, haible@izfm.uni-stuttgart.de * * bdm2/driver/hgc1280/hgc1280driv.c * * derived from: * hga2/* * Author: Davor Matic, dmatic@athena.mit.edu * and * vga256/* * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. * * see bdm2/COPYRIGHT for copyright and disclaimers. */ /* $XFree86: mit/server/ddx/x386/bdm2/drivers/hgc1280/hgc1280driv.c,v 2.3 1993/12/01 12:37:21 dawes Exp $ */ #include "X.h" #include "input.h" #include "screenint.h" #include "compiler.h" #include "x386.h" #include "x386Priv.h" #include "xf86_OSlib.h" #include "xf86_Config.h" #include "bdm.h" #include "hgc1280HW.h" int HGC_Current_mode = HGC_Textmode; Bool HGC_Primary = TRUE; /* #define HGC1280_DEBUG */ /* * Define the HGC I/O Ports * We take the ports for both primary and secondary */ unsigned HGC1280_IOPorts[] = { HGC_PRIM_PORT_INDEX, HGC_PRIM_PORT_DATA, HGC_PRIM_PORT_CONTROL, HGC_PRIM_PORT_CRT_STATUS, HGC_PRIM_PORT_CONFIG, HGC_SEC_PORT_INDEX, HGC_SEC_PORT_DATA, HGC_SEC_PORT_CONTROL, HGC_SEC_PORT_CRT_STATUS, HGC_SEC_PORT_CONFIG }; int Num_HGC1280_IOPorts = (sizeof(HGC1280_IOPorts)/sizeof(HGC1280_IOPorts[0])); char * HGC1280Ident(); Bool HGC1280Probe(); void HGC1280EnterLeave(); void * HGC1280Init(); void * HGC1280Save(); void HGC1280Restore(); void HGC1280Adjust(); Bool HGC1280SaveScreen(); void HGC1280GetMode(); /* Assembler functions in hgc1280bank.s * - to be called by assembler functions only! */ extern void HGC1280pSetRead(); extern void HGC1280pSetWrite(); extern void HGC1280pSetReadWrite(); extern void HGC1280sSetRead(); extern void HGC1280sSetWrite(); extern void HGC1280sSetReadWrite(); #if 0 /* From bdm.h -- see there, this here might not be up to date */ /* * structure for accessing the video chip`s functions * * We are doing a total encapsulation of the driver's functions. * Banking (bdmSetReadWrite(p) etc.) is done in bdmBank.c * using the chip's function pointed to by * bmpSetReadWriteFunc(bank) etc. */ typedef struct { char * (* ChipIdent)(); Bool (* ChipProbe)(); void (* ChipEnterLeave)(); void * (* ChipInit)(); void * (* ChipSave)(); void (* ChipRestore)(); void (* ChipAdjust)(); Bool (* ChipSaveScreen)(); void (* ChipGetMode)(); /* These are the chip's banking functions: */ /* they do the real switching to the desired bank */ /* they 'become' bdmSetReadFunc() etc. */ void (* ChipSetRead)(); void (* ChipSetWrite)(); void (* ChipSetReadWrite)(); /* Bottom and top of the banking window (rel. to ChipMapBase) */ /* Note: Top = highest accessable byte + 1 */ void *ChipReadBottom; void *ChipReadTop; void *ChipWriteBottom; void *ChipWriteTop; /* Memory to map */ int ChipMapBase; int ChipMapSize; /* replaces MEMTOMAP */ int ChipSegmentSize; int ChipSegmentShift; int ChipSegmentMask; Bool ChipUse2Banks; /* Display size is given by the driver */ int ChipHDisplay; int ChipVDisplay; /* In case Scan Line in mfb is longer than HDisplay */ int ChipScanLineWidth; OFlagSet ChipOptionFlags; } bdmVideoChipRec, *bdmVideoChipPtr; #endif /* 0 */ bdmVideoChipRec HGC1280 = { /* Functions */ HGC1280Ident, HGC1280Probe, HGC1280EnterLeave, HGC1280Init, HGC1280Save, HGC1280Restore, HGC1280Adjust, HGC1280SaveScreen, NoopDDA, /* HGC1280GetMode */ HGC1280pSetRead, HGC1280pSetWrite, HGC1280pSetReadWrite, (void *)HGC_BANK1_BOTTOM, /* ReadBottom */ (void *)HGC_BANK1_TOP, /* ReadTop */ (void *)HGC_BANK2_BOTTOM, /* WriteBottom */ (void *)HGC_BANK2_TOP, /* WriteTop */ HGC_PRIM_MAP_BASE, /* MapBase */ HGC_MAP_SIZE, /* MapSize */ HGC_SEGMENT_SIZE, /* SegmentSize */ HGC_SEGMENT_SHIFT, /* SegmentShift */ HGC_SEGMENT_MASK, /* SegmentMask */ TRUE, /* Use2Banks */ HGC_HDISPLAY, /* HDisplay */ HGC_VDISPLAY, /* VDisplay */ HGC_SCAN_LINE_WIDTH, /* ScanLineWidth */ {0,}, }; /* * HGC1280Ident */ char * HGC1280Ident(n) int n; { static char *chipsets[] = {"hgc1280"}; if (n >= sizeof(chipsets) / sizeof(char *)) return(NULL); else return(chipsets[n]); } /* * HGC1280Probe -- * check whether an HGC1280 based board is installed */ Bool HGC1280Probe() { /* * Set up I/O ports to be used by this card */ xf86ClearIOPortList(bdm2InfoRec.scrnIndex); xf86AddIOPorts(bdm2InfoRec.scrnIndex, Num_HGC1280_IOPorts, HGC1280_IOPorts); if (bdm2InfoRec.chipset) { /* Chipset preset */ if (strcmp(bdm2InfoRec.chipset, HGC1280Ident(0))) /* desired chipset != this one */ return (FALSE); else { /* chipset "hgc1280" */ if (OFLG_ISSET(OPTION_SECONDARY, &bdm2InfoRec.options)) { /* option "secondary" */ HGC_Primary=FALSE; ErrorF("%s %s: %s: Using secondary address\n", XCONFIG_GIVEN, bdm2InfoRec.name, bdm2InfoRec.chipset); } else { /* assume primary */ HGC_Primary=TRUE; ErrorF("%s %s: %s: Assuming primary address\n", XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset); } HGC1280EnterLeave(ENTER); /* go on with videoram etc. below */ } } else { unsigned char dsp, dsp_old; int i; int cnt=0; short val=0; Bool found=FALSE; HGC1280EnterLeave(ENTER); /* * Checks if there is a HGC-1280 based board in the system. * * */ /************************************************************* * If anybody has any 'real' infos about the HGC-1280 Hardware * - Please please contact me! *************************************************************/ /* Check for Hercules-like HSYNC on BASE+0xA, Bit 1 */ #define HSYNC_MASK 0x01 #define MIN_COUNT 2000 /* First check the primary address */ #ifdef HGC1280_DEBUG ErrorF("Checking primary address: "); #endif dsp_old = inb(HGC_PRIM_PORT_CRT_STATUS) & HSYNC_MASK; for (i = 0; i < 5000; i++) { dsp = inb(HGC_PRIM_PORT_CRT_STATUS) & HSYNC_MASK; if (dsp != dsp_old) cnt++; dsp_old = dsp; } /* This cnt is about 3500 to 4500 with a 'virgin' hardware, * and might be exactly 5000 if the card had been switched * to 'my' graphics mode before */ #ifdef HGC1280_DEBUG ErrorF("count=%d\n",cnt); #endif if (cnt>MIN_COUNT) { bdm2InfoRec.chipset = HGC1280Ident(0); #ifdef HGC1280_DEBUG ErrorF("%s %s: %s: cnt=%d, ", XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset, cnt); #endif /* Test a r/w register */ HGC_PRIM_SET_REG(HGC_PROBE_REG_RW,HGC_PROBE_VAL_WRITE); HGC_PRIM_GET_REG(HGC_PROBE_REG_RW,&val); #ifdef HGC1280_DEBUG ErrorF("r/w-val=%d, ",val); #endif found = (val==HGC_PROBE_VAL_READ); /* this register can't be set, depends on other registers */ HGC_PRIM_GET_REG(HGC_PROBE_REG_FIX,&val); #ifdef HGC1280_DEBUG ErrorF("fix-val1=%d, ",val); #endif found = found && (val==HGC_PROBE_VAL_FIX1); HGC_PRIM_SET_REG(HGC_PROBE_REG_RW,HGC_PROBE_VAL_RESET); HGC_PRIM_GET_REG(HGC_PROBE_REG_FIX,&val); #ifdef HGC1280_DEBUG ErrorF("fix-val2=%d\n",val); #endif found = found && (val==HGC_PROBE_VAL_FIX2); if (found) { HGC_Primary=TRUE; ErrorF("%s %s: %s found on primary address\n", XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset); } else { #ifdef HGC1280_DEBUG ErrorF("==> not found\n"); #endif bdm2InfoRec.chipset = "\0"; } }; if ( !(cnt>MIN_COUNT) || !found ) { #ifdef HGC1280_DEBUG ErrorF("Checking secondary address: "); #endif /* Check the secondary address */ dsp_old = inb(HGC_SEC_PORT_CRT_STATUS) & HSYNC_MASK; for (i = 0; i < 5000; i++) { dsp = inb(HGC_SEC_PORT_CRT_STATUS) & HSYNC_MASK; if (dsp != dsp_old) cnt++; dsp_old = dsp; } #ifdef HGC1280_DEBUG ErrorF("count=%d\n",cnt); #endif if (cnt>MIN_COUNT) { bdm2InfoRec.chipset = HGC1280Ident(0); #ifdef HGC1280_DEBUG ErrorF("%s %s: %s: cnt=%d, ", XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset, cnt); #endif /* Test a r/w register */ HGC_SEC_SET_REG(HGC_PROBE_REG_RW,HGC_PROBE_VAL_WRITE); HGC_SEC_GET_REG(HGC_PROBE_REG_RW,&val); #ifdef HGC1280_DEBUG ErrorF("r/w-val=%d, ",val); #endif found = (val==HGC_PROBE_VAL_READ); /* this register can't be set, depends on other registers */ HGC_SEC_GET_REG(HGC_PROBE_REG_FIX,&val); #ifdef HGC1280_DEBUG ErrorF("fix-val1=%d, ",val); #endif found = found && (val==HGC_PROBE_VAL_FIX1); HGC_SEC_SET_REG(HGC_PROBE_REG_RW,HGC_PROBE_VAL_RESET); HGC_SEC_GET_REG(HGC_PROBE_REG_FIX,&val); #ifdef HGC1280_DEBUG ErrorF("fix-val2=%d\n",val); #endif found = found && (val==HGC_PROBE_VAL_FIX2); if (found) { HGC_Primary=FALSE; ErrorF("%s %s: %s found on secondary address\n", XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset); } else { #ifdef HGC1280_DEBUG ErrorF("==> not found\n"); #endif bdm2InfoRec.chipset = "\0"; } } } /* if ( !(cnt>MIN_COUNT) || !found ) */ if ( !(cnt>MIN_COUNT) || !found ) { /* there is no HGC-1280 card */ HGC1280EnterLeave(LEAVE); return(FALSE); } } /* else (bdm2InfoRec.chipset) -- bdm2InfoRec.chipset is already set */ /* The following is done for both probed and preset chipset */ if (!bdm2InfoRec.videoRam) { /* videoram not given in Xconfig */ bdm2InfoRec.videoRam=192; } if (!HGC_Primary) { /* Fill in consts and functions for secondary I/O / Mem Base */ HGC1280.ChipMapBase=HGC_SEC_MAP_BASE; HGC1280.ChipSetRead=HGC1280sSetRead; HGC1280.ChipSetWrite=HGC1280sSetWrite; HGC1280.ChipSetReadWrite=HGC1280sSetReadWrite; } /* We do 'virtual' handling here as it is highly chipset specific */ /* Screen size (pixels) is fixed, virtual size can be larger up to * ChipMaxVirtualX and ChipMaxVirtualY */ /* Real display size is given by HGC_HDISPLAY and HGC_VDISPLAY, * desired virtual size is bdm2InfoRec.virtualX and bdm2InfoRec.virtualY. * Think they can be -1 at this point. * Maximum virtual size as done by the driver is * HGC_MAX_VIRTUAL_X and ..._Y */ if (bdm2InfoRec.virtualX < 0) { /* No virtual set in Xconfig */ /* Set virtual to real size */ bdm2InfoRec.virtualX = HGC_HDISPLAY; bdm2InfoRec.virtualY = HGC_VDISPLAY; } else { int Xrounding = 16; if (bdm2InfoRec.virtualX > HGC_MAX_VIRTUAL_X) { ErrorF("%s %s: %s: Virtual width too large, reset to %d\n", XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset, HGC_MAX_VIRTUAL_X); bdm2InfoRec.virtualX = HGC_MAX_VIRTUAL_X; } else if (bdm2InfoRec.virtualY > HGC_MAX_VIRTUAL_Y) { ErrorF("%s %s: %s: Virtual height too large, reset to %d\n", XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset, HGC_MAX_VIRTUAL_Y); bdm2InfoRec.virtualY = HGC_MAX_VIRTUAL_Y; } else if (bdm2InfoRec.virtualX < HGC_HDISPLAY) { ErrorF("%s %s: %s: Virtual width too small, reset to %d\n", XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset, HGC_HDISPLAY); bdm2InfoRec.virtualX = HGC_HDISPLAY; } else if (bdm2InfoRec.virtualY < HGC_VDISPLAY) { ErrorF("%s %s: %s: Virtual height too small, reset to %d\n", XCONFIG_PROBED, bdm2InfoRec.name, bdm2InfoRec.chipset, HGC_VDISPLAY); bdm2InfoRec.virtualY = HGC_VDISPLAY; }; if (bdm2InfoRec.virtualX % Xrounding) { bdm2InfoRec.virtualX -= bdm2InfoRec.virtualX % Xrounding; ErrorF("%s: %s: Virtual width rounded down to %d\n", bdm2InfoRec.name, bdm2InfoRec.chipset, bdm2InfoRec.virtualX); } } /* Initialize option flags allowed for this driver */ OFLG_SET(OPTION_SECONDARY, &HGC1280.ChipOptionFlags); /* Must return real display size */ /* hardcoded in HGC1280 */ return(TRUE); } /* * HGC1280EnterLeave -- * enable/disable io permissions */ void HGC1280EnterLeave(enter) Bool enter; { if (enter) xf86EnableIOPorts(bdm2InfoRec.scrnIndex); else xf86DisableIOPorts(bdm2InfoRec.scrnIndex); } /* * HGC1280Init -- * Handle the initialization of the HGCs registers */ void * HGC1280Init(mode) DisplayModePtr mode; { return((void *)HGC_Graphmode); } /* * HGC1280Save -- * save the current video mode */ void * HGC1280Save(save) int save; { return((void *)HGC_Current_mode); } /* * HGC1280Restore -- * restore a video mode */ void HGC1280Restore(restore) int restore; { unsigned char i; if (HGC_Primary) { if (restore==HGC_Textmode) { for (i = 0; i < HGC_NUM_REGS; i++) { HGC_PRIM_SET_REG(i,hgcRegsText[i]); } HGC_Current_mode = HGC_Textmode; } else if (restore==HGC_Graphmode) { for (i = 0; i < HGC_NUM_REGS; i++) { HGC_PRIM_SET_REG(i,hgcRegsGraf1280x1024[i]); } HGC_Current_mode = HGC_Graphmode; } else ErrorF("Warning: HGC1280Restore called with invalid arg.\n"); } else { /* secondary */ if (restore==HGC_Textmode) { for (i = 0; i < HGC_NUM_REGS; i++) { HGC_SEC_SET_REG(i,hgcRegsText[i]); } HGC_Current_mode = HGC_Textmode; } else if (restore==HGC_Graphmode) { for (i = 0; i < HGC_NUM_REGS; i++) { HGC_SEC_SET_REG(i,hgcRegsGraf1280x1024[i]); } HGC_Current_mode = HGC_Graphmode; } else ErrorF("Warning: HGC1280Restore called with invalid arg.\n"); } } /* * HGC1280SaveScreen(); * Disable the video on the frame buffer (screensaver) */ Bool HGC1280SaveScreen(pScreen,on) ScreenPtr pScreen; Bool on; { if (on == SCREEN_SAVER_FORCER) SetTimeSinceLastInputEvent(); if (x386VTSema) { /* Kind of hack: to get the screen dark, I set the * "begin [end] of display within scanline" to middle of the screen */ if (on) { /* Grrr! SaveScreen(on=TRUE) means turn ScreenSaver off */ if (HGC_Primary) { HGC_PRIM_SET_REG(HGC_REG_LEFT_BORDER,138); HGC_PRIM_SET_REG(HGC_REG_RIGHT_BORDER,90); } else { HGC_SEC_SET_REG(HGC_REG_LEFT_BORDER,138); HGC_SEC_SET_REG(HGC_REG_RIGHT_BORDER,90); } } else { if (HGC_Primary) { HGC_PRIM_SET_REG(HGC_REG_LEFT_BORDER,170); HGC_PRIM_SET_REG(HGC_REG_RIGHT_BORDER,50); } else { HGC_SEC_SET_REG(HGC_REG_LEFT_BORDER,170); HGC_SEC_SET_REG(HGC_REG_RIGHT_BORDER,50); } } } /* if we are not on the active VT, don't do anything - the screen * will be visible as soon as we switch back anyway (?) */ return(TRUE); } /* HGC1280Adjust -- * adjust the current video frame to display the mousecursor * (x,y) is the upper left corner to be displayed. * This needs some special handling with hgc1280: the card can only pan * in steps of 16 pixels. */ void HGC1280Adjust(x,y) int x, y; { static int oldx=0; int val; #if 0 ErrorF("(%d,%d)",x,y); if (x>=192) ErrorF("hgc1280: HGC1280Adjust(%d,%d) ",x,y); #endif /* make shure the pointer is always on the screen */ if (x>oldx) /* right side */ val=16-((x+15)>>4); else /* left side */ val=16-(x>>4); oldx=x; if (HGC_Primary) { HGC_PRIM_SET_REG(HGC_REG_SHIFT_DISPLAY,val); } else { HGC_SEC_SET_REG(HGC_REG_SHIFT_DISPLAY,val); } }