ct_cursor.c revision 9f4658d1
1
2/*
3 * Copyright 1994  The XFree86 Project
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * DAVID WEXELBLAT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Hardware Cursor for Trident utilizing XAA Cursor code.
24 * Written by Alan Hourihane <alanh@fairlite.demon.co.uk>
25 * Modified for Chips and Technologies by David Bateman <dbateman@eng.uts.edu.au>
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32/* All drivers should typically include these */
33#include "xf86.h"
34#include "xf86_OSproc.h"
35
36/* Everything using inb/outb, etc needs "compiler.h" */
37#include "compiler.h"
38
39/* Drivers for PCI hardware need this */
40#include "xf86PciInfo.h"
41
42/* Drivers that need to access the PCI config space directly need this */
43#include "xf86Pci.h"
44
45#include "xf86Cursor.h"
46
47/* Driver specific headers */
48#include "ct_driver.h"
49
50/* Sync function, maybe this should check infoRec->NeedToSync before syncing */
51#define CURSOR_SYNC(pScrn) \
52    if (IS_HiQV(cPtr)) { \
53	CHIPSHiQVSync(pScrn); \
54    } else { \
55	if(!cPtr->UseMMIO) { \
56	    CHIPSSync(pScrn); \
57	} else { \
58	    CHIPSMMIOSync(pScrn); \
59	} \
60    }
61
62/* Swing your cursor bytes round and round... yeehaw! */
63#if X_BYTE_ORDER == X_BIG_ENDIAN
64#define P_SWAP32( a , b )                \
65       ((char *)a)[0] = ((char *)b)[3];  \
66       ((char *)a)[1] = ((char *)b)[2];  \
67       ((char *)a)[2] = ((char *)b)[1];  \
68       ((char *)a)[3] = ((char *)b)[0]
69
70#define P_SWAP16( a , b )                \
71       ((char *)a)[0] = ((char *)b)[1];  \
72       ((char *)a)[1] = ((char *)b)[0];  \
73       ((char *)a)[2] = ((char *)b)[3];  \
74       ((char *)a)[3] = ((char *)b)[2]
75#endif
76
77static void
78CHIPSShowCursor(ScrnInfoPtr pScrn)
79{
80    CHIPSPtr cPtr = CHIPSPTR(pScrn);
81    unsigned char tmp;
82
83    CURSOR_SYNC(pScrn);
84
85    /* turn the cursor on */
86    if (IS_HiQV(cPtr)) {
87	tmp = cPtr->readXR(cPtr, 0xA0);
88	cPtr->writeXR(cPtr, 0xA0, (tmp & 0xF8) | 5);
89	if (cPtr->UseDualChannel &&
90	    (! xf86IsEntityShared(pScrn->entityList[0]))) {
91	    unsigned int IOSS, MSS;
92	    IOSS = cPtr->readIOSS(cPtr);
93	    MSS = cPtr->readMSS(cPtr);
94	    cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
95				   IOSS_PIPE_B));
96	    cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), ((cPtr->storeMSS &
97				  MSS_MASK) | MSS_PIPE_B));
98	    tmp = cPtr->readXR(cPtr, 0xA0);
99	    cPtr->writeXR(cPtr, 0xA0, (tmp & 0xF8) | 5);
100	    cPtr->writeIOSS(cPtr, IOSS);
101	    cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), MSS);
102	}
103    } else {
104	if(!cPtr->UseMMIO) {
105	    HW_DEBUG(0x8);
106	    outw(cPtr->PIOBase+DR(0x8), 0x21);
107	} else {
108	    HW_DEBUG(DR(8));
109	    /*  Used to be: MMIOmemw(MR(8)) = 0x21; */
110	    MMIOmeml(MR(8)) = 0x21;
111	}
112    }
113    cPtr->HWCursorShown = TRUE;
114}
115
116static void
117CHIPSHideCursor(ScrnInfoPtr pScrn)
118{
119    CHIPSPtr cPtr = CHIPSPTR(pScrn);
120    unsigned char tmp;
121
122    CURSOR_SYNC(pScrn);
123
124    /* turn the cursor off */
125    if (IS_HiQV(cPtr)) {
126	tmp = cPtr->readXR(cPtr, 0xA0);
127	cPtr->writeXR(cPtr, 0xA0, tmp & 0xF8);
128	if (cPtr->UseDualChannel &&
129	    (! xf86IsEntityShared(pScrn->entityList[0]))) {
130	    unsigned int IOSS, MSS;
131	    IOSS = cPtr->readIOSS(cPtr);
132	    MSS = cPtr->readMSS(cPtr);
133	    cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
134				   IOSS_PIPE_B));
135	    cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), ((cPtr->storeMSS &
136				  MSS_MASK) | MSS_PIPE_B));
137	    tmp = cPtr->readXR(cPtr, 0xA0);
138	    cPtr->writeXR(cPtr, 0xA0, tmp & 0xF8);
139	    cPtr->writeIOSS(cPtr, IOSS);
140	    cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), MSS);
141	}
142    } else {
143	if(!cPtr->UseMMIO) {
144	    HW_DEBUG(0x8);
145	    outw(cPtr->PIOBase+DR(0x8), 0x20);
146	} else {
147	    HW_DEBUG(DR(0x8));
148	    /* Used to be: MMIOmemw(DR(0x8)) = 0x20; */
149	    MMIOmeml(DR(0x8)) = 0x20;
150	}
151    }
152    cPtr->HWCursorShown = FALSE;
153}
154
155static void
156CHIPSSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
157{
158    CHIPSPtr cPtr = CHIPSPTR(pScrn);
159
160    CURSOR_SYNC(pScrn);
161
162    if (x < 0)
163	x = ~(x-1) | 0x8000;
164    if (y < 0)
165	y = ~(y-1) | 0x8000;
166
167    /* Program the cursor origin (offset into the cursor bitmap). */
168    if (IS_HiQV(cPtr)) {
169	cPtr->writeXR(cPtr, 0xA4, x & 0xFF);
170	cPtr->writeXR(cPtr, 0xA5, (x >> 8) & 0x87);
171	cPtr->writeXR(cPtr, 0xA6, y & 0xFF);
172	cPtr->writeXR(cPtr, 0xA7, (y >> 8) & 0x87);
173	if (cPtr->UseDualChannel &&
174	    (! xf86IsEntityShared(pScrn->entityList[0]))) {
175	    unsigned int IOSS, MSS;
176	    IOSS = cPtr->readIOSS(cPtr);
177	    MSS = cPtr->readMSS(cPtr);
178	    cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
179				   IOSS_PIPE_B));
180	    cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), ((cPtr->storeMSS &
181				  MSS_MASK) | MSS_PIPE_B));
182	    cPtr->writeXR(cPtr, 0xA4, x & 0xFF);
183	    cPtr->writeXR(cPtr, 0xA5, (x >> 8) & 0x87);
184	    cPtr->writeXR(cPtr, 0xA6, y & 0xFF);
185	    cPtr->writeXR(cPtr, 0xA7, (y >> 8) & 0x87);
186	    cPtr->writeIOSS(cPtr, IOSS);
187	    cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), MSS);
188	}
189    } else {
190	CARD32 xy;
191
192	xy = y;
193	xy = (xy << 16) | x;
194	if(!cPtr->UseMMIO) {
195	    HW_DEBUG(0xB);
196	    outl(cPtr->PIOBase+DR(0xB), xy);
197	} else {
198	    HW_DEBUG(MR(0xB));
199	    MMIOmeml(MR(0xB)) = xy;
200	}
201    }
202}
203
204static void
205CHIPSSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
206{
207    CHIPSPtr cPtr = CHIPSPTR(pScrn);
208    vgaHWPtr hwp = VGAHWPTR(pScrn);
209    CARD32 packedcolfg, packedcolbg;
210
211    CURSOR_SYNC(pScrn);
212
213    if (IS_HiQV(cPtr)) {
214	unsigned char xr80;
215
216	/* Enable extended palette addressing */
217	xr80 = cPtr->readXR(cPtr, 0x80);
218	cPtr->writeXR(cPtr, 0x80, xr80 | 0x1);
219
220	/* Write the new colours to the extended VGA palette. Palette
221	 * index is incremented after each write, so only write index
222	 * once
223	 */
224	hwp->writeDacWriteAddr(hwp, 0x04);
225	if (xr80 & 0x80) {
226	    /* 8bit DAC */
227	    hwp->writeDacData(hwp, (bg >> 16) & 0xFF);
228	    hwp->writeDacData(hwp, (bg >> 8) & 0xFF);
229	    hwp->writeDacData(hwp, bg & 0xFF);
230	    hwp->writeDacData(hwp, (fg >> 16) & 0xFF);
231	    hwp->writeDacData(hwp, (fg >> 8) & 0xFF);
232	    hwp->writeDacData(hwp, fg & 0xFF);
233	} else {
234	    /* 6bit DAC */
235	    hwp->writeDacData(hwp, (bg >> 18) & 0xFF);
236	    hwp->writeDacData(hwp, (bg >> 10) & 0xFF);
237	    hwp->writeDacData(hwp, (bg >> 2) & 0xFF);
238	    hwp->writeDacData(hwp, (fg >> 18) & 0xFF);
239	    hwp->writeDacData(hwp, (fg >> 10) & 0xFF);
240	    hwp->writeDacData(hwp, (fg >> 2) & 0xFF);
241	}
242	/* Enable normal palette addressing */
243	cPtr->writeXR(cPtr, 0x80, xr80);
244
245	if (cPtr->UseDualChannel &&
246	    (! xf86IsEntityShared(pScrn->entityList[0]))) {
247	    unsigned int IOSS, MSS;
248	    IOSS = cPtr->readIOSS(cPtr);
249	    MSS = cPtr->readMSS(cPtr);
250	    cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
251				   IOSS_PIPE_B));
252	    cPtr->writeMSS(cPtr, hwp, ((cPtr->storeMSS & MSS_MASK) |
253				   MSS_PIPE_B));
254	    /* Enable extended palette addressing */
255	    xr80 = cPtr->readXR(cPtr, 0x80);
256	    cPtr->writeXR(cPtr, 0x80, xr80 | 0x1);
257
258	    /* Write the new colours to the extended VGA palette. Palette
259	     * index is incremented after each write, so only write index
260	     * once
261	     */
262	    hwp->writeDacWriteAddr(hwp, 0x04);
263	    if (xr80 & 0x80) {
264		/* 8bit DAC */
265		hwp->writeDacData(hwp, (bg >> 16) & 0xFF);
266		hwp->writeDacData(hwp, (bg >> 8) & 0xFF);
267		hwp->writeDacData(hwp, bg & 0xFF);
268		hwp->writeDacData(hwp, (fg >> 16) & 0xFF);
269		hwp->writeDacData(hwp, (fg >> 8) & 0xFF);
270		hwp->writeDacData(hwp, fg & 0xFF);
271	    } else {
272		/* 6bit DAC */
273		hwp->writeDacData(hwp, (bg >> 18) & 0xFF);
274		hwp->writeDacData(hwp, (bg >> 10) & 0xFF);
275		hwp->writeDacData(hwp, (bg >> 2) & 0xFF);
276		hwp->writeDacData(hwp, (fg >> 18) & 0xFF);
277		hwp->writeDacData(hwp, (fg >> 10) & 0xFF);
278		hwp->writeDacData(hwp, (fg >> 2) & 0xFF);
279	    }
280	    /* Enable normal palette addressing */
281	    cPtr->writeXR(cPtr, 0x80, xr80);
282	    cPtr->writeIOSS(cPtr, IOSS);
283	    cPtr->writeMSS(cPtr, hwp, MSS);
284	}
285    } else if (IS_Wingine(cPtr)) {
286	outl(cPtr->PIOBase+DR(0xA), (bg & 0xFFFFFF));
287	outl(cPtr->PIOBase+DR(0x9), (fg & 0xFFFFFF));
288    } else {
289	packedcolfg =  ((fg & 0xF80000) >> 8) | ((fg & 0xFC00) >> 5)
290	    | ((fg & 0xF8) >> 3);
291	packedcolbg =  ((bg & 0xF80000) >> 8) | ((bg & 0xFC00) >> 5)
292	    | ((bg & 0xF8) >> 3);
293	packedcolfg = (packedcolfg << 16) | packedcolbg;
294	if(!cPtr->UseMMIO) {
295	    HW_DEBUG(0x9);
296	    outl(cPtr->PIOBase+DR(0x9), packedcolfg);
297	} else {
298	    MMIOmeml(MR(0x9)) = packedcolfg;
299	    HW_DEBUG(MR(0x9));
300	}
301    }
302}
303
304static void
305CHIPSLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src)
306{
307    CHIPSPtr cPtr = CHIPSPTR(pScrn);
308    CHIPSACLPtr cAcl = CHIPSACLPTR(pScrn);
309#if X_BYTE_ORDER == X_BIG_ENDIAN
310    CARD32 *s = (pointer)src;
311    CARD32 *d = (pointer)(cPtr->FbBase + cAcl->CursorAddress);
312    int y;
313#endif
314
315    CURSOR_SYNC(pScrn);
316
317    if (cPtr->cursorDelay) {
318	usleep(200000);
319	cPtr->cursorDelay = FALSE;
320    }
321
322    if (IS_Wingine(cPtr)) {
323	int i;
324	CARD32 *tmp = (CARD32 *)src;
325
326	outl(cPtr->PIOBase+DR(0x8),0x20);
327	for (i=0; i<64; i++) {
328	    outl(cPtr->PIOBase+DR(0xC),*(CARD32 *)tmp);
329	    tmp++;
330	}
331    } else {
332	if (cPtr->Flags & ChipsLinearSupport) {
333#if X_BYTE_ORDER == X_BIG_ENDIAN
334	    /* On big endian machines we must flip our cursor image around. */
335    	    switch(pScrn->bitsPerPixel >> 3) {
336    	        case 4:
337    	        case 3:
338#if 1
339		    memcpy((unsigned char *)cPtr->FbBase + cAcl->CursorAddress,
340			   src, cPtr->CursorInfoRec->MaxWidth *
341			   cPtr->CursorInfoRec->MaxHeight / 4);
342#else
343        	    for (y = 0; y < 64; y++) {
344            	        P_SWAP32(d,s);
345            	        d++; s++;
346            	        P_SWAP32(d,s);
347            	        d++; s++;
348            	        P_SWAP32(d,s);
349            	        d++; s++;
350            	        P_SWAP32(d,s);
351            	        d++; s++;
352        	    }
353#endif
354        	    break;
355    	        case 2:
356           	    for (y = 0; y < 64; y++) {
357            	        P_SWAP16(d,s);
358            	        d++; s++;
359                        P_SWAP16(d,s);
360                        d++; s++;
361                        P_SWAP16(d,s);
362                        d++; s++;
363                        P_SWAP16(d,s);
364                        d++; s++;
365                    }
366                    break;
367                default:
368                    for (y = 0; y < 64; y++) {
369                        *d++ = *s++;
370                        *d++ = *s++;
371                        *d++ = *s++;
372                        *d++ = *s++;
373                    }
374            }
375#else
376	    memcpy((unsigned char *)cPtr->FbBase + cAcl->CursorAddress,
377			src, cPtr->CursorInfoRec->MaxWidth *
378			cPtr->CursorInfoRec->MaxHeight / 4);
379#endif
380	} else {
381	    /*
382	     * The cursor can only be in the last 16K of video memory,
383	     * which fits in the last banking window.
384	     */
385	    if (IS_HiQV(cPtr))
386		if (pScrn->bitsPerPixel < 8)
387		    CHIPSHiQVSetReadWritePlanar(pScrn->pScreen,
388					    (int)(cAcl->CursorAddress >> 16));
389		else
390		    CHIPSHiQVSetReadWrite(pScrn->pScreen,
391					    (int)(cAcl->CursorAddress >> 16));
392	    else
393		if (pScrn->bitsPerPixel < 8)
394		    CHIPSSetWritePlanar(pScrn->pScreen,
395					    (int)(cAcl->CursorAddress >> 16));
396		else
397		    CHIPSSetWrite(pScrn->pScreen,
398					    (int)(cAcl->CursorAddress >> 16));
399	    memcpy((unsigned char *)cPtr->FbBase + (cAcl->CursorAddress &
400			0xFFFF), src,  cPtr->CursorInfoRec->MaxWidth *
401			cPtr->CursorInfoRec->MaxHeight / 4);
402	}
403    }
404
405    /* set cursor address here or we loose the cursor on video mode change */
406    if (IS_HiQV(cPtr)) {
407	cPtr->writeXR(cPtr, 0xA2, (cAcl->CursorAddress >> 8) & 0xFF);
408	cPtr->writeXR(cPtr, 0xA3, (cAcl->CursorAddress >> 16) & 0x3F);
409	if (cPtr->UseDualChannel &&
410	    (! xf86IsEntityShared(pScrn->entityList[0]))) {
411	    unsigned int IOSS, MSS;
412	    IOSS = cPtr->readIOSS(cPtr);
413	    MSS = cPtr->readMSS(cPtr);
414	    cPtr->writeIOSS(cPtr, ((cPtr->storeIOSS & IOSS_MASK) |
415				   IOSS_PIPE_B));
416	    cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), ((cPtr->storeMSS &
417				  MSS_MASK) | MSS_PIPE_B));
418	    cPtr->writeXR(cPtr, 0xA2, (cAcl->CursorAddress >> 8) & 0xFF);
419	    cPtr->writeXR(cPtr, 0xA3, (cAcl->CursorAddress >> 16) & 0x3F);
420	    cPtr->writeIOSS(cPtr, IOSS);
421	    cPtr->writeMSS(cPtr, VGAHWPTR(pScrn), MSS);
422	}
423    } else if (!IS_Wingine(cPtr)) {
424	if (!cPtr->UseMMIO) {
425	    HW_DEBUG(0xC);
426	    outl(cPtr->PIOBase+DR(0xC), cAcl->CursorAddress);
427	} else {
428	    HW_DEBUG(MR(0xC));
429	    MMIOmeml(MR(0xC)) = cAcl->CursorAddress;
430	}
431    }
432}
433
434static Bool
435CHIPSUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
436{
437    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
438    CHIPSPtr cPtr = CHIPSPTR(pScrn);
439
440    return (((cPtr->Flags & ChipsHWCursor) != 0)
441	    && !(pScrn->currentMode->Flags & V_DBLSCAN));
442}
443
444Bool
445CHIPSCursorInit(ScreenPtr pScreen)
446{
447    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
448    CHIPSPtr cPtr = CHIPSPTR(pScrn);
449    xf86CursorInfoPtr infoPtr;
450
451    infoPtr = xf86CreateCursorInfoRec();
452    if(!infoPtr) return FALSE;
453
454    cPtr->CursorInfoRec = infoPtr;
455
456    infoPtr->Flags =
457#if X_BYTE_ORDER == X_LITTLE_ENDIAN
458	HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
459#endif
460	HARDWARE_CURSOR_INVERT_MASK |
461	HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
462	HARDWARE_CURSOR_TRUECOLOR_AT_8BPP;
463
464    if (IS_HiQV(cPtr)) {
465	infoPtr->Flags |= HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64;
466	infoPtr->MaxHeight = 64;
467	infoPtr->MaxWidth = 64;
468    } else if (IS_Wingine(cPtr)) {
469	infoPtr->Flags |= HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED;
470	infoPtr->MaxHeight = 32;
471	infoPtr->MaxWidth = 32;
472    } else {
473	infoPtr->Flags |= HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8;
474	infoPtr->MaxHeight = 32;
475	infoPtr->MaxWidth = 32;
476    }
477
478    infoPtr->SetCursorColors = CHIPSSetCursorColors;
479    infoPtr->SetCursorPosition = CHIPSSetCursorPosition;
480    infoPtr->LoadCursorImage = CHIPSLoadCursorImage;
481    infoPtr->HideCursor = CHIPSHideCursor;
482    infoPtr->ShowCursor = CHIPSShowCursor;
483    infoPtr->UseHWCursor = CHIPSUseHWCursor;
484
485    return(xf86InitCursor(pScreen, infoPtr));
486}
487
488