s3_dga.c revision b27e1915
1/*
2 *      Copyright 2001  Ani Joshi <ajoshi@unixbox.com>
3 *
4 *      XFree86 4.x driver for S3 chipsets
5 *
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that copyright
10 * notice and this permission notice appear in supporting documentation and
11 * that the name of Ani Joshi not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission.  Ani Joshi makes no representations
14 * about the suitability of this software for any purpose.  It is provided
15 * "as-is" without express or implied warranty.
16 *
17 * ANI JOSHI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL ANI JOSHI BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 *
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "xf86.h"
33#include "xf86_OSproc.h"
34
35#include "dgaproc.h"
36
37#include "s3.h"
38#include "s3_reg.h"
39
40
41static Bool S3_SetMode(ScrnInfoPtr pScrn, DGAModePtr pMode);
42static int S3_GetViewport(ScrnInfoPtr pScrn);
43static void S3_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags);
44#ifdef HAVE_XAA_H
45static void S3_FillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h,
46		        unsigned long color);
47static void S3_BltRect(ScrnInfoPtr pScrn, int srcx, int srcy, int w, int h,
48		       int dstx, int dsty);
49static void S3_Sync(ScrnInfoPtr pScrn);
50#endif
51static Bool S3_OpenFramebuffer(ScrnInfoPtr pScrn, char **name,
52			       unsigned char **mem, int *size, int *offset,
53			       int *flags);
54
55
56static DGAFunctionRec S3_DGAFuncs = {
57	S3_OpenFramebuffer,
58	NULL,
59	S3_SetMode,
60	S3_SetViewport,
61	S3_GetViewport,
62#ifdef HAVE_XAA_H
63	S3_Sync,
64	S3_FillRect,
65	S3_BltRect,
66#else
67	NULL, NULL, NULL,
68#endif
69	NULL
70};
71
72
73static DGAModePtr S3SetupDGAMode(ScrnInfoPtr pScrn, DGAModePtr modes,
74				 int *num, int bitsPerPixel, int depth,
75				 Bool pixmap, int secondPitch,
76				 unsigned long red, unsigned long green,
77				 unsigned long blue, short visualClass)
78{
79	S3Ptr pS3 = S3PTR(pScrn);
80	DGAModePtr newmodes = NULL, currentMode;
81	DisplayModePtr pMode, firstMode;
82	int otherPitch, Bpp = bitsPerPixel >> 3;
83	Bool oneMore;
84
85	pMode = firstMode = pScrn->modes;
86
87	while (pMode) {
88		otherPitch = secondPitch ? secondPitch : pMode->HDisplay;
89
90		if (pMode->HDisplay != otherPitch) {
91			newmodes = realloc(modes, (*num + 2) * sizeof(DGAModeRec));
92			oneMore = TRUE;
93		} else {
94			newmodes = realloc(modes, (*num + 1) * sizeof(DGAModeRec));
95			oneMore = FALSE;
96		}
97
98		if (!newmodes) {
99			free(modes);
100			return NULL;
101		}
102
103		modes = newmodes;
104
105SECOND_PASS:
106
107		currentMode = modes + *num;
108		(*num)++;
109
110		currentMode->mode = pMode;
111		currentMode->flags = DGA_CONCURRENT_ACCESS;
112		if (pixmap)
113			currentMode->flags |= DGA_PIXMAP_AVAILABLE;
114#ifdef HAVE_XAA_H
115		if (pS3->pXAA)
116			currentMode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT;
117#endif
118		if (pMode->Flags & V_DBLSCAN)
119			currentMode->flags |= DGA_DOUBLESCAN;
120		if (pMode->Flags & V_INTERLACE)
121			currentMode->flags |= DGA_INTERLACED;
122		currentMode->byteOrder = pScrn->imageByteOrder;
123		currentMode->depth = depth;
124		currentMode->bitsPerPixel = bitsPerPixel;
125		currentMode->red_mask = red;
126		currentMode->green_mask = green;
127		currentMode->blue_mask = blue;
128		currentMode->visualClass = visualClass;
129		currentMode->viewportWidth = pMode->HDisplay;
130		currentMode->viewportHeight = pMode->VDisplay;
131		currentMode->xViewportStep = 8;
132		currentMode->yViewportStep = 1;
133		currentMode->viewportFlags = DGA_FLIP_RETRACE;
134		currentMode->offset = 0;
135		currentMode->address = (unsigned char*)pS3->FBAddress;
136
137		if (oneMore) {
138			currentMode->bytesPerScanline = (((pMode->HDisplay * Bpp) + 3) & ~3L);
139
140			currentMode->imageWidth = pMode->HDisplay;
141			currentMode->imageHeight = pMode->VDisplay;
142			currentMode->pixmapWidth = currentMode->imageWidth;
143			currentMode->pixmapHeight = currentMode->imageHeight;
144			currentMode->maxViewportX = currentMode->imageWidth -
145						    currentMode->viewportWidth;
146			currentMode->maxViewportY = currentMode->imageHeight -
147						    currentMode->viewportHeight;
148
149			oneMore = FALSE;
150			goto SECOND_PASS;
151		} else {
152			currentMode->bytesPerScanline = (((otherPitch * Bpp) + 3) & ~3L);
153
154			currentMode->imageWidth = otherPitch;
155			currentMode->imageHeight = pMode->VDisplay;
156			currentMode->pixmapWidth = currentMode->imageWidth;
157			currentMode->pixmapHeight = currentMode->imageHeight;
158			currentMode->maxViewportX = currentMode->imageWidth -
159						    currentMode->viewportWidth;
160			currentMode->maxViewportY = currentMode->imageHeight -
161						    currentMode->viewportHeight;
162
163		}
164
165		pMode = pMode->next;
166
167		if (pMode == firstMode)
168			break;
169
170	}
171
172	return modes;
173}
174
175
176
177Bool S3DGAInit(ScreenPtr pScreen)
178{
179	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
180	S3Ptr pS3 = S3PTR(pScrn);
181	DGAModePtr modes = NULL;
182	int num = 0;
183
184	modes = S3SetupDGAMode(pScrn, modes, &num, 8, 8,
185			       (pScrn->bitsPerPixel == 8),
186			       ((pScrn->bitsPerPixel != 8) ? 0 : pScrn->displayWidth),
187			       0, 0, 0, PseudoColor);
188
189	modes = S3SetupDGAMode(pScrn, modes, &num, 16, 15,
190			       (pScrn->bitsPerPixel == 16),
191			       ((pScrn->depth != 15)
192			       ? 0 : pScrn->displayWidth),
193			       0x7c00, 0x03e0, 0x001f, TrueColor);
194
195	modes = S3SetupDGAMode(pScrn, modes, &num, 16, 15,
196			       (pScrn->bitsPerPixel == 16),
197			       ((pScrn->depth != 15)
198			       ? 0 : pScrn->displayWidth),
199			       0x7c00, 0x03e0, 0x001f, DirectColor);
200
201	modes = S3SetupDGAMode(pScrn, modes, &num, 16, 16,
202			       (pScrn->bitsPerPixel == 16),
203			       ((pScrn->depth != 16)
204			       ? 0 : pScrn->displayWidth),
205			       0xf800, 0x07e0, 0x001f, TrueColor);
206
207	modes = S3SetupDGAMode(pScrn, modes, &num, 16, 16,
208			       (pScrn->bitsPerPixel == 16),
209			       ((pScrn->depth != 16)
210			       ? 0 : pScrn->displayWidth),
211			       0xf800, 0x07e0, 0x001f, DirectColor);
212
213	modes = S3SetupDGAMode(pScrn, modes, &num, 32, 24,
214			       (pScrn->bitsPerPixel == 32),
215			       ((pScrn->bitsPerPixel != 32)
216			       ? 0 : pScrn->displayWidth),
217			       0xff0000, 0x00ff00, 0x0000ff, TrueColor);
218
219	modes = S3SetupDGAMode(pScrn, modes, &num, 32, 24,
220			       (pScrn->bitsPerPixel == 32),
221			       ((pScrn->bitsPerPixel != 32)
222			       ? 0 : pScrn->displayWidth),
223			       0xff0000, 0x00ff00, 0x0000ff, DirectColor);
224
225	pS3->numDGAModes = num;
226	pS3->DGAModes = modes;
227
228	return DGAInit(pScreen, &S3_DGAFuncs, modes, num);
229}
230
231
232static Bool S3_SetMode(ScrnInfoPtr pScrn, DGAModePtr pMode)
233{
234	S3Ptr pS3 = S3PTR(pScrn);
235	static S3FBLayout SavedLayouts[MAXSCREENS];
236	int indx = pScrn->pScreen->myNum;
237
238	if (!pMode) {
239		if (pS3->DGAactive) {
240			memcpy(&pS3->CurrentLayout, &SavedLayouts[indx],
241			       sizeof(S3FBLayout));
242			pS3->DGAactive = TRUE;
243		}
244
245		pS3->CurrentLayout.bitsPerPixel = pMode->bitsPerPixel;
246		pS3->CurrentLayout.depth = pMode->depth;
247		pS3->CurrentLayout.displayWidth = (pMode->bytesPerScanline /
248						   (pMode->bitsPerPixel >> 3));
249		pS3->CurrentLayout.pixel_bytes = pMode->bitsPerPixel / 8;
250		pS3->CurrentLayout.pixel_code = (pMode->bitsPerPixel != 16 ?
251						 pMode->bitsPerPixel :
252						 pMode->depth);
253
254		S3SwitchMode(SWITCH_MODE_ARGS(pScrn, pMode->mode));
255	}
256
257	return TRUE;
258}
259
260
261static int S3_GetViewport(ScrnInfoPtr pScrn)
262{
263	S3Ptr pS3 = S3PTR(pScrn);
264
265	return pS3->DGAViewportStatus;
266}
267
268
269static void S3_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags)
270{
271	S3Ptr pS3 = S3PTR(pScrn);
272
273	pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, x, y));
274	pS3->DGAViewportStatus = 0;
275}
276
277
278#ifdef HAVE_XAA_H
279static void S3_FillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h,
280		        unsigned long color)
281{
282	S3Ptr pS3 = S3PTR(pScrn);
283
284	if (pS3->pXAA) {
285		(*pS3->pXAA->SetupForSolidFill)(pScrn, color, GXcopy, (CARD32)(~0));
286		(*pS3->pXAA->SubsequentSolidFillRect)(pScrn, x, y, w, h);
287		SET_SYNC_FLAG(pS3->pXAA);
288	}
289}
290
291
292static void S3_BltRect(ScrnInfoPtr pScrn, int srcx, int srcy, int w, int h,
293		       int dstx, int dsty)
294{
295	S3Ptr pS3 = S3PTR(pScrn);
296
297	if (pS3->pXAA) {
298		int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
299		int ydir = (srcy < dsty) ? -1 : 1;
300
301		(*pS3->pXAA->SetupForScreenToScreenCopy)(pScrn, xdir, ydir,
302							 GXcopy, (CARD32)(~0), -1);
303		(*pS3->pXAA->SubsequentScreenToScreenCopy)(pScrn, srcx, srcy,
304							   dstx, dsty, w, h);
305		SET_SYNC_FLAG(pS3->pXAA);
306	}
307}
308#endif
309
310static Bool S3_OpenFramebuffer(ScrnInfoPtr pScrn, char **name,
311			       unsigned char **mem, int *size, int *offset,
312			       int *flags)
313{
314	S3Ptr pS3 = S3PTR(pScrn);
315
316	*name = NULL;
317	*mem = (unsigned char*)pS3->FBAddress;
318	*size = (pScrn->videoRam * 1024);
319	*offset = 0;
320	*flags = 0;
321
322	return TRUE;
323}
324
325#ifdef HAVE_XAA_H
326static void S3_Sync(ScrnInfoPtr pScrn)
327{
328	WaitIdle();
329}
330#endif
331