1692f60a7Smrg/**********************************************************************
2692f60a7SmrgCopyright 1998, 1999 by Precision Insight, Inc., Cedar Park, Texas.
3692f60a7Smrg
4692f60a7Smrg                        All Rights Reserved
5692f60a7Smrg
6692f60a7SmrgPermission to use, copy, modify, distribute, and sell this software and
7692f60a7Smrgits documentation for any purpose is hereby granted without fee,
8692f60a7Smrgprovided that the above copyright notice appear in all copies and that
9692f60a7Smrgboth that copyright notice and this permission notice appear in
10692f60a7Smrgsupporting documentation, and that the name of Precision Insight not be
11692f60a7Smrgused in advertising or publicity pertaining to distribution of the
12692f60a7Smrgsoftware without specific, written prior permission.  Precision Insight
13692f60a7Smrgand its suppliers make no representations about the suitability of this
14692f60a7Smrgsoftware for any purpose.  It is provided "as is" without express or
15692f60a7Smrgimplied warranty.
16692f60a7Smrg
17692f60a7SmrgPRECISION INSIGHT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18692f60a7SmrgINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19692f60a7SmrgEVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
20692f60a7SmrgSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21692f60a7SmrgRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22692f60a7SmrgCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23692f60a7SmrgCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24692f60a7Smrg**********************************************************************/
25692f60a7Smrg
26692f60a7Smrg/*
27692f60a7Smrg * The original Precision Insight driver for
28692f60a7Smrg * XFree86 v.3.3 has been sponsored by Red Hat.
29692f60a7Smrg *
30692f60a7Smrg * Authors:
31692f60a7Smrg *   Jens Owen (jens@tungstengraphics.com)
32692f60a7Smrg *   Kevin E. Martin (kevin@precisioninsight.com)
33692f60a7Smrg *
34692f60a7Smrg * Port to Xfree86 v.4.0
35692f60a7Smrg *   1998, 1999 by Egbert Eich (Egbert.Eich@Physik.TU-Darmstadt.DE)
36692f60a7Smrg */
37692f60a7Smrg
38692f60a7Smrg#ifdef HAVE_CONFIG_H
39692f60a7Smrg#include "config.h"
40692f60a7Smrg#endif
41692f60a7Smrg
42692f60a7Smrg/* All drivers should typically include these */
43692f60a7Smrg#include "xf86.h"
44692f60a7Smrg#include "xf86_OSproc.h"
45692f60a7Smrg#include "vgaHW.h"
46692f60a7Smrg
47692f60a7Smrg#include "xf86Cursor.h"
48692f60a7Smrg#include "cursorstr.h"
49692f60a7Smrg/* Driver specific headers */
50692f60a7Smrg#include "neo.h"
51692f60a7Smrg
52692f60a7Smrgstatic void _neoLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src,
53692f60a7Smrg				int xoff, int yoff);
54692f60a7Smrg
55692f60a7Smrgvoid
56692f60a7SmrgNeoShowCursor(ScrnInfoPtr pScrn)
57692f60a7Smrg{
58692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
59692f60a7Smrg
60692f60a7Smrg    /* turn cursor on */
61692f60a7Smrg    OUTREG(NEOREG_CURSCNTL, NEO_CURS_ENABLE);
62692f60a7Smrg    nPtr->NeoHWCursorShown = TRUE;
63692f60a7Smrg}
64692f60a7Smrg
65692f60a7Smrgvoid
66692f60a7SmrgNeoHideCursor(ScrnInfoPtr pScrn)
67692f60a7Smrg{
68692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
69692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
70692f60a7Smrg
71692f60a7Smrg    /*
72692f60a7Smrg     * turn cursor off
73692f60a7Smrg     *
74692f60a7Smrg     * Sometimes we loose the I/O map, so directly use I/O here
75692f60a7Smrg     */
76692f60a7Smrg
77692f60a7Smrg    VGAwGR(0x82,0x00);
78692f60a7Smrg
79692f60a7Smrg    nPtr->NeoHWCursorShown = FALSE;
80692f60a7Smrg}
81692f60a7Smrg
82692f60a7Smrg#define MAX_CURS 64
83692f60a7Smrg
84692f60a7Smrg#define REVBITS_32(__b) { \
85692f60a7Smrg  ((unsigned char *)&__b)[0] = byte_reversed[((unsigned char *)&__b)[0]]; \
86692f60a7Smrg  ((unsigned char *)&__b)[1] = byte_reversed[((unsigned char *)&__b)[1]]; \
87692f60a7Smrg  ((unsigned char *)&__b)[2] = byte_reversed[((unsigned char *)&__b)[2]]; \
88692f60a7Smrg  ((unsigned char *)&__b)[3] = byte_reversed[((unsigned char *)&__b)[3]]; \
89692f60a7Smrg}
90692f60a7Smrg
91692f60a7Smrgstatic void
92692f60a7SmrgneoSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
93692f60a7Smrg{
94692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
95692f60a7Smrg    NEOACLPtr nAcl = NEOACLPTR(pScrn);
96692f60a7Smrg    int i;
97692f60a7Smrg    CARD32 bits, bits2;
98692f60a7Smrg    unsigned char *_dest = ((unsigned char *)nPtr->NeoFbBase +
99692f60a7Smrg			    nAcl->CursorAddress);
100692f60a7Smrg    unsigned char *src = nPtr->NeoCursorImage;
101692f60a7Smrg    int xoff = 0, yoff = 0;
102692f60a7Smrg
103692f60a7Smrg    if ((y < 0) && (y > (-MAX_CURS))) {
104692f60a7Smrg	yoff = -y;
105692f60a7Smrg	y = 0;
106692f60a7Smrg    }
107692f60a7Smrg    if ((x < 0) && (x > (-MAX_CURS))) {
108692f60a7Smrg	xoff = -x;
109692f60a7Smrg	x = 0;
110692f60a7Smrg    }
111692f60a7Smrg    if (yoff != nPtr->NeoCursorPrevY || xoff !=nPtr->NeoCursorPrevX) {
112692f60a7Smrg	nPtr->NeoCursorPrevY = yoff;
113692f60a7Smrg	nPtr->NeoCursorPrevX = xoff;
114692f60a7Smrg
115692f60a7Smrg        /* This is for sprites that move off the top of the display.
116692f60a7Smrg	 * this code simply updates the pointer used for loading the sprite.
117692f60a7Smrg	 * Note, in our driver's RealizeCursor, the allocated buffer size
118692f60a7Smrg	 * is twice as large as needed, and we initialize the upper half to all
119692f60a7Smrg	 * zeros, so we can use this pointer trick here.
120692f60a7Smrg	 */
121692f60a7Smrg
122692f60a7Smrg         if (yoff) {
123692f60a7Smrg	    src += (yoff * 16);
124692f60a7Smrg	 }
125692f60a7Smrg
126692f60a7Smrg	 /* This is for sprites that move off the left edge of the display.
127692f60a7Smrg	  * this code has to do some ugly bit swizzling to generate new cursor
128692f60a7Smrg	  * masks that give the impression the cursor is moving off the screen.
129692f60a7Smrg	  * WARNING: PLATFORM SPECIFIC!  This is 32-bit little endian code!
130692f60a7Smrg	  */
131692f60a7Smrg          if (xoff)
132692f60a7Smrg	    {
133692f60a7Smrg	       if (xoff < 32) { /* offset 1-31 */
134692f60a7Smrg		  for (i=0; i<256; i+=2) {
135692f60a7Smrg		     bits = ((CARD32 *)src)[i];
136692f60a7Smrg		     bits2 = ((CARD32 *)src)[i+1];
137692f60a7Smrg
138692f60a7Smrg		     REVBITS_32(bits);
139692f60a7Smrg		     REVBITS_32(bits2);
140692f60a7Smrg
141692f60a7Smrg		     bits = ((bits >> xoff) | (bits2 << (32-xoff)));
142692f60a7Smrg		     bits2 >>= xoff;
143692f60a7Smrg
144692f60a7Smrg		     REVBITS_32(bits);
145692f60a7Smrg		     REVBITS_32(bits2);
146692f60a7Smrg
147692f60a7Smrg		     ((CARD32 *) nAcl->CursTemp)[i] = bits;
148692f60a7Smrg		     ((CARD32 *) nAcl->CursTemp)[i+1] = bits2;
149692f60a7Smrg		  }
150692f60a7Smrg	       }
151692f60a7Smrg	       else { /* offset 32-63 */
152692f60a7Smrg		  for (i=0; i<256; i+=2) {
153692f60a7Smrg		     bits = ((CARD32 *)src)[i];
154692f60a7Smrg		     bits2 = ((CARD32 *)src)[i+1];
155692f60a7Smrg
156692f60a7Smrg		     REVBITS_32(bits2);
157692f60a7Smrg
158692f60a7Smrg		     bits = (bits2 >> (xoff-32));
159692f60a7Smrg		     bits2 = 0;
160692f60a7Smrg
161692f60a7Smrg		     REVBITS_32(bits);
162692f60a7Smrg
163692f60a7Smrg		     ((CARD32 *)nAcl->CursTemp)[i] = bits;
164692f60a7Smrg		     ((CARD32 *)nAcl->CursTemp)[i+1] = bits2;
165692f60a7Smrg		  }
166692f60a7Smrg	       }
167692f60a7Smrg	       src = nAcl->CursTemp;
168692f60a7Smrg	    }
169692f60a7Smrg       memcpy(_dest, src, 1024);
170692f60a7Smrg       OUTREG(NEOREG_CURSMEMPOS, ((0x000f & (nAcl->CursorAddress >> 10)) << 8) |
171692f60a7Smrg	      ((0x0ff0 & (nAcl->CursorAddress >> 10)) >> 4));
172692f60a7Smrg
173692f60a7Smrg
174692f60a7Smrg    }
175692f60a7Smrg
176692f60a7Smrg    /* Move the cursor */
177692f60a7Smrg    OUTREG(NEOREG_CURSX, x);
178692f60a7Smrg    OUTREG(NEOREG_CURSY, y);
179692f60a7Smrg}
180692f60a7Smrg
181692f60a7Smrgstatic void
182692f60a7SmrgneoSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
183692f60a7Smrg{
184692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
185692f60a7Smrg
186692f60a7Smrg    /* swap blue and red */
187692f60a7Smrg    fg = ((fg & 0xff0000) >> 16) | ((fg & 0xff) << 16) | (fg & 0xff00);
188692f60a7Smrg    bg = ((bg & 0xff0000) >> 16) | ((bg & 0xff) << 16) | (bg & 0xff00);
189692f60a7Smrg
190692f60a7Smrg    /* load colors */
191692f60a7Smrg    OUTREG(NEOREG_CURSFGCOLOR, fg);
192692f60a7Smrg    OUTREG(NEOREG_CURSBGCOLOR, bg);
193692f60a7Smrg}
194692f60a7Smrg
195692f60a7Smrgstatic void
196692f60a7Smrg_neoLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src, int xoff, int yoff)
197692f60a7Smrg{
198692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
199692f60a7Smrg    NEOACLPtr nAcl = NEOACLPTR(pScrn);
200692f60a7Smrg    int i;
201692f60a7Smrg    unsigned char *_dest, *_src;
202692f60a7Smrg    int _width, _fill;
203692f60a7Smrg
204692f60a7Smrg    for (i = 0; i< nPtr->CursorInfo->MaxHeight - yoff; i++) {
205692f60a7Smrg      _dest = ((unsigned char *)nPtr->NeoFbBase
206692f60a7Smrg	       + nAcl->CursorAddress
207692f60a7Smrg	       + ((nPtr->CursorInfo->MaxWidth >> 2) * i));
208692f60a7Smrg      _width = (nPtr->CursorInfo->MaxWidth
209692f60a7Smrg		- (xoff & 0x38)) >> 3;
210692f60a7Smrg      _src = (src + ((nPtr->CursorInfo->MaxWidth >> 2) * i));
211692f60a7Smrg      _fill = (xoff & 0x38) >> 3;
212692f60a7Smrg
213692f60a7Smrg      memcpy(_dest,_src,_width);
214692f60a7Smrg      memset(_dest + _width, 0, _fill);
215692f60a7Smrg
216692f60a7Smrg      _dest += (nPtr->CursorInfo->MaxWidth >> 3);
217692f60a7Smrg      _src += (nPtr->CursorInfo->MaxWidth >> 3);
218692f60a7Smrg      memcpy(_dest,_src,_width);
219692f60a7Smrg      memset(_dest + _width, 0, _fill);
220692f60a7Smrg    }
221692f60a7Smrg    memset(nPtr->NeoFbBase + nAcl->CursorAddress
222692f60a7Smrg	   + ((nPtr->CursorInfo->MaxWidth >> 2) * i),
223692f60a7Smrg	   0, (nPtr->CursorInfo->MaxHeight - i)
224692f60a7Smrg	   * (nPtr->CursorInfo->MaxWidth >> 2));
225692f60a7Smrg    /* set cursor address here or we loose the cursor on video mode change */
226692f60a7Smrg    /* Load storage location.  */
227692f60a7Smrg    OUTREG(NEOREG_CURSMEMPOS, ((0x000f & (nAcl->CursorAddress >> 10)) << 8)  |
228692f60a7Smrg	   ((0x0ff0 & (nAcl->CursorAddress >> 10)) >> 4));
229692f60a7Smrg}
230692f60a7Smrg
231692f60a7Smrgstatic void
232692f60a7SmrgneoLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src)
233692f60a7Smrg{
234692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
235692f60a7Smrg    nPtr->NeoCursorImage = src;  /* store src address for later use */
236692f60a7Smrg
237692f60a7Smrg    /* Reset these because we have a new cursor image */
238692f60a7Smrg    nPtr->NeoCursorPrevY = nPtr->NeoCursorPrevX = 0;
239692f60a7Smrg
240692f60a7Smrg    _neoLoadCursorImage(pScrn,src,0,0);
241692f60a7Smrg}
242692f60a7Smrg
243692f60a7Smrgstatic Bool
244692f60a7SmrgneoUseHWCursor(ScreenPtr pScr, CursorPtr pCurs)
245692f60a7Smrg{
2463f6d0e1dSmrg    NEOACLPtr nAcl = NEOACLPTR(xf86ScreenToScrn(pScr));
247692f60a7Smrg
248692f60a7Smrg    return(nAcl->UseHWCursor && !nAcl->NoCursorMode);
249692f60a7Smrg}
250692f60a7Smrg
251692f60a7Smrgstatic unsigned char*
252692f60a7SmrgneoRealizeCursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
253692f60a7Smrg{
254692f60a7Smrg    CARD32 *SrcS, *SrcM, *DstS, *DstM;
255692f60a7Smrg    CARD32 *pSrc, *pMsk;
256692f60a7Smrg    unsigned char *mem;
257692f60a7Smrg    int SrcPitch, DstPitch, y, x, z;
258692f60a7Smrg
259692f60a7Smrg    mem = (unsigned char*)xnfcalloc(4096,1);
260692f60a7Smrg    SrcPitch = (pCurs->bits->width + 31) >> 5;
261692f60a7Smrg    DstPitch = infoPtr->MaxWidth >> 4;
262692f60a7Smrg    SrcS = (CARD32*)pCurs->bits->source;
263692f60a7Smrg    SrcM = (CARD32*)pCurs->bits->mask;
264692f60a7Smrg    DstS = (CARD32*)mem;
265692f60a7Smrg    DstM = DstS + (DstPitch >> 1);
266692f60a7Smrg
267692f60a7Smrg    for(y = pCurs->bits->height, pSrc = DstS, pMsk = DstM;
268692f60a7Smrg	y--;
269692f60a7Smrg	pSrc+=DstPitch, pMsk+=DstPitch, SrcS+=SrcPitch, SrcM+=SrcPitch) {
270692f60a7Smrg	for(x = 0; x < SrcPitch; x++) {
271692f60a7Smrg	    pSrc[x] = ~SrcS[x] & SrcM[x];
272692f60a7Smrg	    pMsk[x] = SrcM[x];
273692f60a7Smrg	    for (z = 0; z < 4; z++) {
274692f60a7Smrg		((char *)pSrc)[x*4+z] =
275692f60a7Smrg		    byte_reversed[((char *)pSrc)[x*4+z] & 0xFF];
276692f60a7Smrg		((char *)pMsk)[x*4+z] =
277692f60a7Smrg		    byte_reversed[((char *)pMsk)[x*4+z] & 0xFF];
278692f60a7Smrg	    }
279692f60a7Smrg	}
280692f60a7Smrg#if 0
281692f60a7Smrg	for (;x < DstPitch; x++) {
282692f60a7Smrg	    pSrc[x] = 0;
283692f60a7Smrg	    pMsk[x] = 0;
284692f60a7Smrg	}
285692f60a7Smrg#endif
286692f60a7Smrg    }
287692f60a7Smrg
288692f60a7Smrg    return (unsigned char *)mem;
289692f60a7Smrg}
290692f60a7Smrg
291692f60a7SmrgBool
292692f60a7SmrgNeoCursorInit(ScreenPtr pScreen)
293692f60a7Smrg{
2943f6d0e1dSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
295692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
296692f60a7Smrg    xf86CursorInfoPtr infoPtr;
297692f60a7Smrg    infoPtr = xf86CreateCursorInfoRec();
298692f60a7Smrg    if(!infoPtr) return FALSE;
299692f60a7Smrg
300692f60a7Smrg    nPtr->CursorInfo = infoPtr;
301692f60a7Smrg
302692f60a7Smrg    infoPtr->MaxHeight = 64;
303692f60a7Smrg    infoPtr->MaxWidth = 64;
304692f60a7Smrg    infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP;
305692f60a7Smrg
306692f60a7Smrg    infoPtr->SetCursorColors = neoSetCursorColors;
307692f60a7Smrg    infoPtr->SetCursorPosition = neoSetCursorPosition;
308692f60a7Smrg    infoPtr->LoadCursorImage = neoLoadCursorImage;
309692f60a7Smrg    infoPtr->HideCursor = NeoHideCursor;
310692f60a7Smrg    infoPtr->ShowCursor = NeoShowCursor;
311692f60a7Smrg    infoPtr->UseHWCursor = neoUseHWCursor;
312692f60a7Smrg    infoPtr->RealizeCursor = neoRealizeCursor;
313692f60a7Smrg
314692f60a7Smrg    return(xf86InitCursor(pScreen, infoPtr));
315692f60a7Smrg}
316692f60a7Smrg
317692f60a7Smrg
318692f60a7Smrg
319