s3v_hwcurs.c revision 1d54945d
11d54945dSmrg/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/s3virge/s3v_hwcurs.c,v 1.7 2003/02/04 02:20:50 dawes Exp $ */
21d54945dSmrg
31d54945dSmrg/*
41d54945dSmrgCopyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
51d54945dSmrg
61d54945dSmrgPermission is hereby granted, free of charge, to any person obtaining a copy of
71d54945dSmrgthis software and associated documentation files (the "Software"), to deal in
81d54945dSmrgthe Software without restriction, including without limitation the rights to
91d54945dSmrguse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
101d54945dSmrgof the Software, and to permit persons to whom the Software is furnished to do
111d54945dSmrgso, subject to the following conditions:
121d54945dSmrg
131d54945dSmrgThe above copyright notice and this permission notice shall be included in all
141d54945dSmrgcopies or substantial portions of the Software.
151d54945dSmrg
161d54945dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171d54945dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
181d54945dSmrgNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
191d54945dSmrgXFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
201d54945dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
211d54945dSmrgWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
221d54945dSmrg
231d54945dSmrgExcept as contained in this notice, the name of the XFree86 Project shall not
241d54945dSmrgbe used in advertising or otherwise to promote the sale, use or other dealings
251d54945dSmrgin this Software without prior written authorization from the XFree86 Project.
261d54945dSmrg*/
271d54945dSmrg
281d54945dSmrg#ifdef HAVE_CONFIG_H
291d54945dSmrg#include "config.h"
301d54945dSmrg#endif
311d54945dSmrg
321d54945dSmrg/*
331d54945dSmrg * s3v_hwcurs.c
341d54945dSmrg * HW Cursor support for 4.0 design level
351d54945dSmrg *
361d54945dSmrg * S3 ViRGE driver
371d54945dSmrg *
381d54945dSmrg *
391d54945dSmrg */
401d54945dSmrg
411d54945dSmrg
421d54945dSmrg#include "s3v.h"
431d54945dSmrg
441d54945dSmrg/* protos */
451d54945dSmrg
461d54945dSmrgstatic void S3VLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src);
471d54945dSmrgstatic void S3VShowCursor(ScrnInfoPtr pScrn);
481d54945dSmrgstatic void S3VHideCursor(ScrnInfoPtr pScrn);
491d54945dSmrgstatic void S3VSetCursorPosition(ScrnInfoPtr pScrn, int x, int y);
501d54945dSmrgstatic void S3VSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg);
511d54945dSmrg
521d54945dSmrg
531d54945dSmrg/*
541d54945dSmrg * Read/write to the DAC via MMIO
551d54945dSmrg */
561d54945dSmrg
571d54945dSmrg#define inCRReg(reg) (VGAHWPTR(pScrn))->readCrtc( VGAHWPTR(pScrn), reg )
581d54945dSmrg#define outCRReg(reg, val) (VGAHWPTR(pScrn))->writeCrtc( VGAHWPTR(pScrn), reg, val )
591d54945dSmrg
601d54945dSmrg
611d54945dSmrg
621d54945dSmrg/****
631d54945dSmrg ***  HW Cursor
641d54945dSmrg */
651d54945dSmrgstatic void
661d54945dSmrgS3VLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src)
671d54945dSmrg{
681d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
691d54945dSmrg
701d54945dSmrg    /*PVERB5("	S3VLoadCursorImage\n");*/
711d54945dSmrg
721d54945dSmrg    /* Load storage location.  */
731d54945dSmrg    outCRReg( HWCURSOR_ADDR_LOW_CR4D, 0xff & (ps3v->FBCursorOffset/1024));
741d54945dSmrg    outCRReg( HWCURSOR_ADDR_HIGH_CR4C, (0x0f00 & (ps3v->FBCursorOffset/1024)) >> 8);
751d54945dSmrg
761d54945dSmrg	/* Copy cursor image to framebuffer storage */
771d54945dSmrg	memcpy( (ps3v->FBBase + ps3v->FBCursorOffset), src, 1024);
781d54945dSmrg
791d54945dSmrg}
801d54945dSmrg
811d54945dSmrg
821d54945dSmrgstatic void
831d54945dSmrgS3VShowCursor(ScrnInfoPtr pScrn)
841d54945dSmrg{
851d54945dSmrg  char tmp;
861d54945dSmrg
871d54945dSmrg  tmp = inCRReg(HWCURSOR_MODE_CR45);
881d54945dSmrg    /* Enable cursor */
891d54945dSmrg  outCRReg(HWCURSOR_MODE_CR45, tmp | 1 );
901d54945dSmrg}
911d54945dSmrg
921d54945dSmrg
931d54945dSmrgstatic void
941d54945dSmrgS3VHideCursor(ScrnInfoPtr pScrn)
951d54945dSmrg{
961d54945dSmrg  char tmp;
971d54945dSmrg
981d54945dSmrg  tmp = inCRReg(HWCURSOR_MODE_CR45);
991d54945dSmrg   /* Disable cursor */
1001d54945dSmrg  outCRReg(HWCURSOR_MODE_CR45, tmp & ~1 );
1011d54945dSmrg}
1021d54945dSmrg
1031d54945dSmrg
1041d54945dSmrgstatic void
1051d54945dSmrgS3VSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
1061d54945dSmrg{
1071d54945dSmrg   unsigned char xoff = 0, yoff = 0;
1081d54945dSmrg
1091d54945dSmrg   /*
1101d54945dSmrg   if (!xf86VTSema)
1111d54945dSmrg      return;
1121d54945dSmrg    */
1131d54945dSmrg
1141d54945dSmrg   /*
1151d54945dSmrg   x -= s3vHotX;
1161d54945dSmrg   y -= s3vHotY;
1171d54945dSmrg    */
1181d54945dSmrg
1191d54945dSmrg   /*
1201d54945dSmrg    * Make these even when used.  There is a bug/feature on at least
1211d54945dSmrg    * some chipsets that causes a "shadow" of the cursor in interlaced
1221d54945dSmrg    * mode.  Making this even seems to have no visible effect, so just
1231d54945dSmrg    * do it for the generic case.
1241d54945dSmrg    * note - xoff & yoff are used for displaying partial cursors on screen
1251d54945dSmrg    * edges.
1261d54945dSmrg    */
1271d54945dSmrg
1281d54945dSmrg   if (x < 0) {
1291d54945dSmrg     xoff = ((-x) & 0xFE);
1301d54945dSmrg     x = 0;
1311d54945dSmrg   }
1321d54945dSmrg
1331d54945dSmrg   if (y < 0) {
1341d54945dSmrg      yoff = ((-y) & 0xFE);
1351d54945dSmrg      y = 0;
1361d54945dSmrg   }
1371d54945dSmrg
1381d54945dSmrg   /* Double y position for a doublescan mode */
1391d54945dSmrg   if(pScrn->currentMode->Flags & V_DBLSCAN) y <<= 1;
1401d54945dSmrg
1411d54945dSmrg   /* This is the recommended order to move the cursor */
1421d54945dSmrg
1431d54945dSmrg   outCRReg( 0x46, (x & 0xff00)>>8 );
1441d54945dSmrg   outCRReg( 0x47, (x & 0xff) );
1451d54945dSmrg   outCRReg( 0x49, (y & 0xff) );
1461d54945dSmrg   outCRReg( 0x4e, xoff );
1471d54945dSmrg   outCRReg( 0x4f, yoff );
1481d54945dSmrg   outCRReg( 0x48, (y & 0xff00)>>8 );
1491d54945dSmrg}
1501d54945dSmrg
1511d54945dSmrg
1521d54945dSmrgstatic void
1531d54945dSmrgS3VSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
1541d54945dSmrg{
1551d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
1561d54945dSmrg
1571d54945dSmrg    /*PVERB5("	S3VSetCursorColors\n");*/
1581d54945dSmrg
1591d54945dSmrg	switch( pScrn->bitsPerPixel) {
1601d54945dSmrg	case 8:
1611d54945dSmrg	  if (!(S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset))) {
1621d54945dSmrg	    /* Reset the cursor color stack pointer */
1631d54945dSmrg	    inCRReg(0x45);
1641d54945dSmrg	    /* Write foreground */
1651d54945dSmrg	    outCRReg(0x4a, fg);
1661d54945dSmrg	    outCRReg(0x4a, fg);
1671d54945dSmrg	    /* Reset the cursor color stack pointer */
1681d54945dSmrg	    inCRReg(0x45);
1691d54945dSmrg	    /* Write background */
1701d54945dSmrg	    outCRReg(0x4b, bg);
1711d54945dSmrg	    outCRReg(0x4b, bg);
1721d54945dSmrg	    break;
1731d54945dSmrg	  }  /* else fall through for ViRGE/MX... */
1741d54945dSmrg	case 16:
1751d54945dSmrg	  if (!(S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset))) {
1761d54945dSmrg	    /* adjust colors to 16 bits */
1771d54945dSmrg	    if (pScrn->weight.green == 5 && ps3v->Chipset != S3_ViRGE_VX) {
1781d54945dSmrg	      fg = ((fg & 0xf80000) >> 9) |
1791d54945dSmrg		((fg & 0xf800) >> 6) |
1801d54945dSmrg		((fg & 0xf8) >> 3);
1811d54945dSmrg	      bg = ((bg & 0xf80000) >> 9) |
1821d54945dSmrg		((bg & 0xf800) >> 6) |
1831d54945dSmrg		((bg & 0xf8) >> 3);
1841d54945dSmrg	    } else {
1851d54945dSmrg	      fg = ((fg & 0xf80000) >> 8) |
1861d54945dSmrg		((fg & 0xfc00) >> 5) |
1871d54945dSmrg		((fg & 0xf8) >> 3);
1881d54945dSmrg	      bg = ((bg & 0xf80000) >> 8) |
1891d54945dSmrg		((bg & 0xfc00) >> 5) |
1901d54945dSmrg		((bg & 0xf8) >> 3);
1911d54945dSmrg	    }
1921d54945dSmrg
1931d54945dSmrg	    inCRReg(0x45);
1941d54945dSmrg	    /* Write foreground */
1951d54945dSmrg	    outCRReg(0x4a, fg);
1961d54945dSmrg	    outCRReg(0x4a, fg >> 8);
1971d54945dSmrg	    /* needed for 2nd pixel in double-clock modes */
1981d54945dSmrg	    outCRReg(0x4a, fg);
1991d54945dSmrg	    outCRReg(0x4a, fg >> 8);
2001d54945dSmrg	    /* Reset the cursor color stack pointer */
2011d54945dSmrg	    inCRReg(0x45);
2021d54945dSmrg	    /* Write background */
2031d54945dSmrg	    outCRReg(0x4b, bg);
2041d54945dSmrg	    outCRReg(0x4b, bg >> 8);
2051d54945dSmrg	    /* needed for 2nd pixel in double-clock modes */
2061d54945dSmrg	    outCRReg(0x4b, bg);
2071d54945dSmrg	    outCRReg(0x4b, bg >> 8);
2081d54945dSmrg	    break;
2091d54945dSmrg	  }  /* else fall through for ViRGE/MX... */
2101d54945dSmrg
2111d54945dSmrg	case 24:
2121d54945dSmrg	case 32:
2131d54945dSmrg	  /* Do it straight, full 24 bit color. */
2141d54945dSmrg
2151d54945dSmrg	  /* Reset the cursor color stack pointer */
2161d54945dSmrg	  inCRReg(0x45);
2171d54945dSmrg	  /* Write low, mid, high bytes - foreground */
2181d54945dSmrg	  outCRReg(0x4a, fg);
2191d54945dSmrg	  outCRReg(0x4a, fg >> 8);
2201d54945dSmrg	  outCRReg(0x4a, fg >> 16);
2211d54945dSmrg	  /* Reset the cursor color stack pointer */
2221d54945dSmrg	  inCRReg(0x45);
2231d54945dSmrg	  /* Write low, mid, high bytes - background */
2241d54945dSmrg	  outCRReg(0x4b, bg);
2251d54945dSmrg	  outCRReg(0x4b, bg >> 8);
2261d54945dSmrg	  outCRReg(0x4b, bg >> 16);
2271d54945dSmrg	  break;
2281d54945dSmrg	}
2291d54945dSmrg}
2301d54945dSmrg
2311d54945dSmrg
2321d54945dSmrgBool
2331d54945dSmrgS3VHWCursorInit(ScreenPtr pScreen)
2341d54945dSmrg{
2351d54945dSmrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2361d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
2371d54945dSmrg    xf86CursorInfoPtr infoPtr;
2381d54945dSmrg
2391d54945dSmrg    PVERB5("	S3VHWCursorInit\n");
2401d54945dSmrg
2411d54945dSmrg    infoPtr = xf86CreateCursorInfoRec();
2421d54945dSmrg    if(!infoPtr) return FALSE;
2431d54945dSmrg
2441d54945dSmrg    ps3v->CursorInfoRec = infoPtr;
2451d54945dSmrg
2461d54945dSmrg    infoPtr->MaxWidth = 64;
2471d54945dSmrg    infoPtr->MaxHeight = 64;
2481d54945dSmrg    infoPtr->Flags = HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 |
2491d54945dSmrg    				 HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
2501d54945dSmrg				 HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
2511d54945dSmrg        			 HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
2521d54945dSmrg    if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset))
2531d54945dSmrg       infoPtr->Flags |= HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
2541d54945dSmrg	                 HARDWARE_CURSOR_INVERT_MASK;
2551d54945dSmrg
2561d54945dSmrg    infoPtr->SetCursorColors = S3VSetCursorColors;
2571d54945dSmrg    infoPtr->SetCursorPosition = S3VSetCursorPosition;
2581d54945dSmrg    infoPtr->LoadCursorImage = S3VLoadCursorImage;
2591d54945dSmrg    infoPtr->HideCursor = S3VHideCursor;
2601d54945dSmrg    infoPtr->ShowCursor = S3VShowCursor;
2611d54945dSmrg    infoPtr->UseHWCursor = NULL;
2621d54945dSmrg
2631d54945dSmrg    return(xf86InitCursor(pScreen, infoPtr));
2641d54945dSmrg}
2651d54945dSmrg
2661d54945dSmrg/*EOF*/
267