1/**********************************************************************
2Copyright 1998, 1999 by Precision Insight, Inc., Cedar Park, Texas.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, distribute, and sell this software and
7its documentation for any purpose is hereby granted without fee,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Precision Insight not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.  Precision Insight
13and its suppliers make no representations about the suitability of this
14software for any purpose.  It is provided "as is" without express or
15implied warranty.
16
17PRECISION INSIGHT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
20SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24**********************************************************************/
25
26/*
27 * The original Precision Insight driver for
28 * XFree86 v.3.3 has been sponsored by Red Hat.
29 *
30 * Authors:
31 *   Jens Owen (jens@tungstengraphics.com)
32 *   Kevin E. Martin (kevin@precisioninsight.com)
33 *
34 * Port to Xfree86 v.4.0
35 *   1998, 1999 by Egbert Eich (Egbert.Eich@Physik.TU-Darmstadt.DE)
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42/* All drivers should typically include these */
43#include "xf86.h"
44#include "xf86_OSproc.h"
45#include "vgaHW.h"
46
47#include "xf86Cursor.h"
48#include "cursorstr.h"
49/* Driver specific headers */
50#include "neo.h"
51
52static void _neoLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src,
53				int xoff, int yoff);
54
55void
56NeoShowCursor(ScrnInfoPtr pScrn)
57{
58    NEOPtr nPtr = NEOPTR(pScrn);
59
60    /* turn cursor on */
61    OUTREG(NEOREG_CURSCNTL, NEO_CURS_ENABLE);
62    nPtr->NeoHWCursorShown = TRUE;
63}
64
65void
66NeoHideCursor(ScrnInfoPtr pScrn)
67{
68    NEOPtr nPtr = NEOPTR(pScrn);
69    vgaHWPtr hwp = VGAHWPTR(pScrn);
70
71    /*
72     * turn cursor off
73     *
74     * Sometimes we loose the I/O map, so directly use I/O here
75     */
76
77    VGAwGR(0x82,0x00);
78
79    nPtr->NeoHWCursorShown = FALSE;
80}
81
82#define MAX_CURS 64
83
84#define REVBITS_32(__b) { \
85  ((unsigned char *)&__b)[0] = byte_reversed[((unsigned char *)&__b)[0]]; \
86  ((unsigned char *)&__b)[1] = byte_reversed[((unsigned char *)&__b)[1]]; \
87  ((unsigned char *)&__b)[2] = byte_reversed[((unsigned char *)&__b)[2]]; \
88  ((unsigned char *)&__b)[3] = byte_reversed[((unsigned char *)&__b)[3]]; \
89}
90
91static void
92neoSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
93{
94    NEOPtr nPtr = NEOPTR(pScrn);
95    NEOACLPtr nAcl = NEOACLPTR(pScrn);
96    int i;
97    CARD32 bits, bits2;
98    unsigned char *_dest = ((unsigned char *)nPtr->NeoFbBase +
99			    nAcl->CursorAddress);
100    unsigned char *src = nPtr->NeoCursorImage;
101    int xoff = 0, yoff = 0;
102
103    if ((y < 0) && (y > (-MAX_CURS))) {
104	yoff = -y;
105	y = 0;
106    }
107    if ((x < 0) && (x > (-MAX_CURS))) {
108	xoff = -x;
109	x = 0;
110    }
111    if (yoff != nPtr->NeoCursorPrevY || xoff !=nPtr->NeoCursorPrevX) {
112	nPtr->NeoCursorPrevY = yoff;
113	nPtr->NeoCursorPrevX = xoff;
114
115        /* This is for sprites that move off the top of the display.
116	 * this code simply updates the pointer used for loading the sprite.
117	 * Note, in our driver's RealizeCursor, the allocated buffer size
118	 * is twice as large as needed, and we initialize the upper half to all
119	 * zeros, so we can use this pointer trick here.
120	 */
121
122         if (yoff) {
123	    src += (yoff * 16);
124	 }
125
126	 /* This is for sprites that move off the left edge of the display.
127	  * this code has to do some ugly bit swizzling to generate new cursor
128	  * masks that give the impression the cursor is moving off the screen.
129	  * WARNING: PLATFORM SPECIFIC!  This is 32-bit little endian code!
130	  */
131          if (xoff)
132	    {
133	       if (xoff < 32) { /* offset 1-31 */
134		  for (i=0; i<256; i+=2) {
135		     bits = ((CARD32 *)src)[i];
136		     bits2 = ((CARD32 *)src)[i+1];
137
138		     REVBITS_32(bits);
139		     REVBITS_32(bits2);
140
141		     bits = ((bits >> xoff) | (bits2 << (32-xoff)));
142		     bits2 >>= xoff;
143
144		     REVBITS_32(bits);
145		     REVBITS_32(bits2);
146
147		     ((CARD32 *) nAcl->CursTemp)[i] = bits;
148		     ((CARD32 *) nAcl->CursTemp)[i+1] = bits2;
149		  }
150	       }
151	       else { /* offset 32-63 */
152		  for (i=0; i<256; i+=2) {
153		     bits = ((CARD32 *)src)[i];
154		     bits2 = ((CARD32 *)src)[i+1];
155
156		     REVBITS_32(bits2);
157
158		     bits = (bits2 >> (xoff-32));
159		     bits2 = 0;
160
161		     REVBITS_32(bits);
162
163		     ((CARD32 *)nAcl->CursTemp)[i] = bits;
164		     ((CARD32 *)nAcl->CursTemp)[i+1] = bits2;
165		  }
166	       }
167	       src = nAcl->CursTemp;
168	    }
169       memcpy(_dest, src, 1024);
170       OUTREG(NEOREG_CURSMEMPOS, ((0x000f & (nAcl->CursorAddress >> 10)) << 8) |
171	      ((0x0ff0 & (nAcl->CursorAddress >> 10)) >> 4));
172
173
174    }
175
176    /* Move the cursor */
177    OUTREG(NEOREG_CURSX, x);
178    OUTREG(NEOREG_CURSY, y);
179}
180
181static void
182neoSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
183{
184    NEOPtr nPtr = NEOPTR(pScrn);
185
186    /* swap blue and red */
187    fg = ((fg & 0xff0000) >> 16) | ((fg & 0xff) << 16) | (fg & 0xff00);
188    bg = ((bg & 0xff0000) >> 16) | ((bg & 0xff) << 16) | (bg & 0xff00);
189
190    /* load colors */
191    OUTREG(NEOREG_CURSFGCOLOR, fg);
192    OUTREG(NEOREG_CURSBGCOLOR, bg);
193}
194
195static void
196_neoLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src, int xoff, int yoff)
197{
198    NEOPtr nPtr = NEOPTR(pScrn);
199    NEOACLPtr nAcl = NEOACLPTR(pScrn);
200    int i;
201    unsigned char *_dest, *_src;
202    int _width, _fill;
203
204    for (i = 0; i< nPtr->CursorInfo->MaxHeight - yoff; i++) {
205      _dest = ((unsigned char *)nPtr->NeoFbBase
206	       + nAcl->CursorAddress
207	       + ((nPtr->CursorInfo->MaxWidth >> 2) * i));
208      _width = (nPtr->CursorInfo->MaxWidth
209		- (xoff & 0x38)) >> 3;
210      _src = (src + ((nPtr->CursorInfo->MaxWidth >> 2) * i));
211      _fill = (xoff & 0x38) >> 3;
212
213      memcpy(_dest,_src,_width);
214      memset(_dest + _width, 0, _fill);
215
216      _dest += (nPtr->CursorInfo->MaxWidth >> 3);
217      _src += (nPtr->CursorInfo->MaxWidth >> 3);
218      memcpy(_dest,_src,_width);
219      memset(_dest + _width, 0, _fill);
220    }
221    memset(nPtr->NeoFbBase + nAcl->CursorAddress
222	   + ((nPtr->CursorInfo->MaxWidth >> 2) * i),
223	   0, (nPtr->CursorInfo->MaxHeight - i)
224	   * (nPtr->CursorInfo->MaxWidth >> 2));
225    /* set cursor address here or we loose the cursor on video mode change */
226    /* Load storage location.  */
227    OUTREG(NEOREG_CURSMEMPOS, ((0x000f & (nAcl->CursorAddress >> 10)) << 8)  |
228	   ((0x0ff0 & (nAcl->CursorAddress >> 10)) >> 4));
229}
230
231static void
232neoLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src)
233{
234    NEOPtr nPtr = NEOPTR(pScrn);
235    nPtr->NeoCursorImage = src;  /* store src address for later use */
236
237    /* Reset these because we have a new cursor image */
238    nPtr->NeoCursorPrevY = nPtr->NeoCursorPrevX = 0;
239
240    _neoLoadCursorImage(pScrn,src,0,0);
241}
242
243static Bool
244neoUseHWCursor(ScreenPtr pScr, CursorPtr pCurs)
245{
246    NEOACLPtr nAcl = NEOACLPTR(xf86ScreenToScrn(pScr));
247
248    return(nAcl->UseHWCursor && !nAcl->NoCursorMode);
249}
250
251static unsigned char*
252neoRealizeCursor(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
253{
254    CARD32 *SrcS, *SrcM, *DstS, *DstM;
255    CARD32 *pSrc, *pMsk;
256    unsigned char *mem;
257    int SrcPitch, DstPitch, y, x, z;
258
259    mem = (unsigned char*)xnfcalloc(4096,1);
260    SrcPitch = (pCurs->bits->width + 31) >> 5;
261    DstPitch = infoPtr->MaxWidth >> 4;
262    SrcS = (CARD32*)pCurs->bits->source;
263    SrcM = (CARD32*)pCurs->bits->mask;
264    DstS = (CARD32*)mem;
265    DstM = DstS + (DstPitch >> 1);
266
267    for(y = pCurs->bits->height, pSrc = DstS, pMsk = DstM;
268	y--;
269	pSrc+=DstPitch, pMsk+=DstPitch, SrcS+=SrcPitch, SrcM+=SrcPitch) {
270	for(x = 0; x < SrcPitch; x++) {
271	    pSrc[x] = ~SrcS[x] & SrcM[x];
272	    pMsk[x] = SrcM[x];
273	    for (z = 0; z < 4; z++) {
274		((char *)pSrc)[x*4+z] =
275		    byte_reversed[((char *)pSrc)[x*4+z] & 0xFF];
276		((char *)pMsk)[x*4+z] =
277		    byte_reversed[((char *)pMsk)[x*4+z] & 0xFF];
278	    }
279	}
280#if 0
281	for (;x < DstPitch; x++) {
282	    pSrc[x] = 0;
283	    pMsk[x] = 0;
284	}
285#endif
286    }
287
288    return (unsigned char *)mem;
289}
290
291Bool
292NeoCursorInit(ScreenPtr pScreen)
293{
294    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
295    NEOPtr nPtr = NEOPTR(pScrn);
296    xf86CursorInfoPtr infoPtr;
297    infoPtr = xf86CreateCursorInfoRec();
298    if(!infoPtr) return FALSE;
299
300    nPtr->CursorInfo = infoPtr;
301
302    infoPtr->MaxHeight = 64;
303    infoPtr->MaxWidth = 64;
304    infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP;
305
306    infoPtr->SetCursorColors = neoSetCursorColors;
307    infoPtr->SetCursorPosition = neoSetCursorPosition;
308    infoPtr->LoadCursorImage = neoLoadCursorImage;
309    infoPtr->HideCursor = NeoHideCursor;
310    infoPtr->ShowCursor = NeoShowCursor;
311    infoPtr->UseHWCursor = neoUseHWCursor;
312    infoPtr->RealizeCursor = neoRealizeCursor;
313
314    return(xf86InitCursor(pScreen, infoPtr));
315}
316
317
318
319