11d54945dSmrg
21d54945dSmrg/*
31d54945dSmrgCopyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
41d54945dSmrg
51d54945dSmrgPermission is hereby granted, free of charge, to any person obtaining a copy of
61d54945dSmrgthis software and associated documentation files (the "Software"), to deal in
71d54945dSmrgthe Software without restriction, including without limitation the rights to
81d54945dSmrguse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
91d54945dSmrgof the Software, and to permit persons to whom the Software is furnished to do
101d54945dSmrgso, subject to the following conditions:
111d54945dSmrg
121d54945dSmrgThe above copyright notice and this permission notice shall be included in all
131d54945dSmrgcopies or substantial portions of the Software.
141d54945dSmrg
151d54945dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161d54945dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
171d54945dSmrgNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
181d54945dSmrgXFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
191d54945dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
201d54945dSmrgWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
211d54945dSmrg
221d54945dSmrgExcept as contained in this notice, the name of the XFree86 Project shall not
231d54945dSmrgbe used in advertising or otherwise to promote the sale, use or other dealings
241d54945dSmrgin this Software without prior written authorization from the XFree86 Project.
251d54945dSmrg*/
261d54945dSmrg
271d54945dSmrg#ifdef HAVE_CONFIG_H
281d54945dSmrg#include "config.h"
291d54945dSmrg#endif
301d54945dSmrg
311d54945dSmrg/*
321d54945dSmrg * s3v_hwcurs.c
331d54945dSmrg * HW Cursor support for 4.0 design level
341d54945dSmrg *
351d54945dSmrg * S3 ViRGE driver
361d54945dSmrg *
371d54945dSmrg *
381d54945dSmrg */
391d54945dSmrg
401d54945dSmrg
411d54945dSmrg#include "s3v.h"
42d769e936Smrg#include "s3v_pciids.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... */
17422663e35Smrg	  /* FALLTHROUGH */
1751d54945dSmrg	case 16:
1761d54945dSmrg	  if (!(S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset))) {
1771d54945dSmrg	    /* adjust colors to 16 bits */
1781d54945dSmrg	    if (pScrn->weight.green == 5 && ps3v->Chipset != S3_ViRGE_VX) {
1791d54945dSmrg	      fg = ((fg & 0xf80000) >> 9) |
1801d54945dSmrg		((fg & 0xf800) >> 6) |
1811d54945dSmrg		((fg & 0xf8) >> 3);
1821d54945dSmrg	      bg = ((bg & 0xf80000) >> 9) |
1831d54945dSmrg		((bg & 0xf800) >> 6) |
1841d54945dSmrg		((bg & 0xf8) >> 3);
1851d54945dSmrg	    } else {
1861d54945dSmrg	      fg = ((fg & 0xf80000) >> 8) |
1871d54945dSmrg		((fg & 0xfc00) >> 5) |
1881d54945dSmrg		((fg & 0xf8) >> 3);
1891d54945dSmrg	      bg = ((bg & 0xf80000) >> 8) |
1901d54945dSmrg		((bg & 0xfc00) >> 5) |
1911d54945dSmrg		((bg & 0xf8) >> 3);
1921d54945dSmrg	    }
1931d54945dSmrg
1941d54945dSmrg	    inCRReg(0x45);
1951d54945dSmrg	    /* Write foreground */
1961d54945dSmrg	    outCRReg(0x4a, fg);
1971d54945dSmrg	    outCRReg(0x4a, fg >> 8);
1981d54945dSmrg	    /* needed for 2nd pixel in double-clock modes */
1991d54945dSmrg	    outCRReg(0x4a, fg);
2001d54945dSmrg	    outCRReg(0x4a, fg >> 8);
2011d54945dSmrg	    /* Reset the cursor color stack pointer */
2021d54945dSmrg	    inCRReg(0x45);
2031d54945dSmrg	    /* Write background */
2041d54945dSmrg	    outCRReg(0x4b, bg);
2051d54945dSmrg	    outCRReg(0x4b, bg >> 8);
2061d54945dSmrg	    /* needed for 2nd pixel in double-clock modes */
2071d54945dSmrg	    outCRReg(0x4b, bg);
2081d54945dSmrg	    outCRReg(0x4b, bg >> 8);
2091d54945dSmrg	    break;
2101d54945dSmrg	  }  /* else fall through for ViRGE/MX... */
21122663e35Smrg	  /* FALLTHROUGH */
2121d54945dSmrg	case 24:
2131d54945dSmrg	case 32:
2141d54945dSmrg	  /* Do it straight, full 24 bit color. */
2151d54945dSmrg
2161d54945dSmrg	  /* Reset the cursor color stack pointer */
2171d54945dSmrg	  inCRReg(0x45);
2181d54945dSmrg	  /* Write low, mid, high bytes - foreground */
2191d54945dSmrg	  outCRReg(0x4a, fg);
2201d54945dSmrg	  outCRReg(0x4a, fg >> 8);
2211d54945dSmrg	  outCRReg(0x4a, fg >> 16);
2221d54945dSmrg	  /* Reset the cursor color stack pointer */
2231d54945dSmrg	  inCRReg(0x45);
2241d54945dSmrg	  /* Write low, mid, high bytes - background */
2251d54945dSmrg	  outCRReg(0x4b, bg);
2261d54945dSmrg	  outCRReg(0x4b, bg >> 8);
2271d54945dSmrg	  outCRReg(0x4b, bg >> 16);
2281d54945dSmrg	  break;
2291d54945dSmrg	}
2301d54945dSmrg}
2311d54945dSmrg
2321d54945dSmrg
2331d54945dSmrgBool
2341d54945dSmrgS3VHWCursorInit(ScreenPtr pScreen)
2351d54945dSmrg{
236d769e936Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2371d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
2381d54945dSmrg    xf86CursorInfoPtr infoPtr;
2391d54945dSmrg
2401d54945dSmrg    PVERB5("	S3VHWCursorInit\n");
2411d54945dSmrg
2421d54945dSmrg    infoPtr = xf86CreateCursorInfoRec();
2431d54945dSmrg    if(!infoPtr) return FALSE;
2441d54945dSmrg
2451d54945dSmrg    ps3v->CursorInfoRec = infoPtr;
2461d54945dSmrg
2471d54945dSmrg    infoPtr->MaxWidth = 64;
2481d54945dSmrg    infoPtr->MaxHeight = 64;
2491d54945dSmrg    infoPtr->Flags = HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 |
2501d54945dSmrg    				 HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
2511d54945dSmrg				 HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
2521d54945dSmrg        			 HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
2531d54945dSmrg    if (S3_ViRGE_GX2_SERIES(ps3v->Chipset) || S3_ViRGE_MX_SERIES(ps3v->Chipset))
2541d54945dSmrg       infoPtr->Flags |= HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
2551d54945dSmrg	                 HARDWARE_CURSOR_INVERT_MASK;
2561d54945dSmrg
2571d54945dSmrg    infoPtr->SetCursorColors = S3VSetCursorColors;
2581d54945dSmrg    infoPtr->SetCursorPosition = S3VSetCursorPosition;
2591d54945dSmrg    infoPtr->LoadCursorImage = S3VLoadCursorImage;
2601d54945dSmrg    infoPtr->HideCursor = S3VHideCursor;
2611d54945dSmrg    infoPtr->ShowCursor = S3VShowCursor;
2621d54945dSmrg    infoPtr->UseHWCursor = NULL;
2631d54945dSmrg
2641d54945dSmrg    return(xf86InitCursor(pScreen, infoPtr));
2651d54945dSmrg}
2661d54945dSmrg
2671d54945dSmrg/*EOF*/
268