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