s3_dga.c revision 340e3fbd
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/* $XFree86: $ */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include "xf86.h"
34#include "xf86_OSproc.h"
35
36#include "dgaproc.h"
37
38#include "s3.h"
39#include "s3_reg.h"
40
41
42static Bool S3_SetMode(ScrnInfoPtr pScrn, DGAModePtr pMode);
43static int S3_GetViewport(ScrnInfoPtr pScrn);
44static void S3_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags);
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 Bool S3_OpenFramebuffer(ScrnInfoPtr pScrn, char **name,
50			       unsigned char **mem, int *size, int *offset,
51			       int *flags);
52static void S3_Sync(ScrnInfoPtr pScrn);
53
54
55static DGAFunctionRec S3_DGAFuncs = {
56	S3_OpenFramebuffer,
57	NULL,
58	S3_SetMode,
59	S3_SetViewport,
60	S3_GetViewport,
61	S3_Sync,
62	S3_FillRect,
63	S3_BltRect,
64	NULL
65};
66
67
68static DGAModePtr S3SetupDGAMode(ScrnInfoPtr pScrn, DGAModePtr modes,
69				 int *num, int bitsPerPixel, int depth,
70				 Bool pixmap, int secondPitch,
71				 unsigned long red, unsigned long green,
72				 unsigned long blue, short visualClass)
73{
74	S3Ptr pS3 = S3PTR(pScrn);
75	DGAModePtr newmodes = NULL, currentMode;
76	DisplayModePtr pMode, firstMode;
77	int otherPitch, Bpp = bitsPerPixel >> 3;
78	Bool oneMore;
79
80	pMode = firstMode = pScrn->modes;
81
82	while (pMode) {
83		otherPitch = secondPitch ? secondPitch : pMode->HDisplay;
84
85		if (pMode->HDisplay != otherPitch) {
86			newmodes = xrealloc(modes, (*num + 2) * sizeof(DGAModeRec));
87			oneMore = TRUE;
88		} else {
89			newmodes = xrealloc(modes, (*num + 1) * sizeof(DGAModeRec));
90			oneMore = FALSE;
91		}
92
93		if (!newmodes) {
94			xfree(modes);
95			return NULL;
96		}
97
98		modes = newmodes;
99
100SECOND_PASS:
101
102		currentMode = modes + *num;
103		(*num)++;
104
105		currentMode->mode = pMode;
106		currentMode->flags = DGA_CONCURRENT_ACCESS;
107		if (pixmap)
108			currentMode->flags |= DGA_PIXMAP_AVAILABLE;
109		if (pS3->pXAA)
110			currentMode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT;
111		if (pMode->Flags & V_DBLSCAN)
112			currentMode->flags |= DGA_DOUBLESCAN;
113		if (pMode->Flags & V_INTERLACE)
114			currentMode->flags |= DGA_INTERLACED;
115		currentMode->byteOrder = pScrn->imageByteOrder;
116		currentMode->depth = depth;
117		currentMode->bitsPerPixel = bitsPerPixel;
118		currentMode->red_mask = red;
119		currentMode->green_mask = green;
120		currentMode->blue_mask = blue;
121		currentMode->visualClass = visualClass;
122		currentMode->viewportWidth = pMode->HDisplay;
123		currentMode->viewportHeight = pMode->VDisplay;
124		currentMode->xViewportStep = 8;
125		currentMode->yViewportStep = 1;
126		currentMode->viewportFlags = DGA_FLIP_RETRACE;
127		currentMode->offset = 0;
128		currentMode->address = (unsigned char*)pS3->FBAddress;
129
130		if (oneMore) {
131			currentMode->bytesPerScanline = (((pMode->HDisplay * Bpp) + 3) & ~3L);
132
133			currentMode->imageWidth = pMode->HDisplay;
134			currentMode->imageHeight = pMode->VDisplay;
135			currentMode->pixmapWidth = currentMode->imageWidth;
136			currentMode->pixmapHeight = currentMode->imageHeight;
137			currentMode->maxViewportX = currentMode->imageWidth -
138						    currentMode->viewportWidth;
139			currentMode->maxViewportY = currentMode->imageHeight -
140						    currentMode->viewportHeight;
141
142			oneMore = FALSE;
143			goto SECOND_PASS;
144		} else {
145			currentMode->bytesPerScanline = (((otherPitch * Bpp) + 3) & ~3L);
146
147			currentMode->imageWidth = otherPitch;
148			currentMode->imageHeight = pMode->VDisplay;
149			currentMode->pixmapWidth = currentMode->imageWidth;
150			currentMode->pixmapHeight = currentMode->imageHeight;
151			currentMode->maxViewportX = currentMode->imageWidth -
152						    currentMode->viewportWidth;
153			currentMode->maxViewportY = currentMode->imageHeight -
154						    currentMode->viewportHeight;
155
156		}
157
158		pMode = pMode->next;
159
160		if (pMode == firstMode)
161			break;
162
163	}
164
165	return modes;
166}
167
168
169
170Bool S3DGAInit(ScreenPtr pScreen)
171{
172	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
173	S3Ptr pS3 = S3PTR(pScrn);
174	DGAModePtr modes = NULL;
175	int num = 0;
176
177	modes = S3SetupDGAMode(pScrn, modes, &num, 8, 8,
178			       (pScrn->bitsPerPixel == 8),
179			       ((pScrn->bitsPerPixel != 8) ? 0 : pScrn->displayWidth),
180			       0, 0, 0, PseudoColor);
181
182	modes = S3SetupDGAMode(pScrn, modes, &num, 16, 15,
183			       (pScrn->bitsPerPixel == 16),
184			       ((pScrn->depth != 15)
185			       ? 0 : pScrn->displayWidth),
186			       0x7c00, 0x03e0, 0x001f, TrueColor);
187
188	modes = S3SetupDGAMode(pScrn, modes, &num, 16, 15,
189			       (pScrn->bitsPerPixel == 16),
190			       ((pScrn->depth != 15)
191			       ? 0 : pScrn->displayWidth),
192			       0x7c00, 0x03e0, 0x001f, DirectColor);
193
194	modes = S3SetupDGAMode(pScrn, modes, &num, 16, 16,
195			       (pScrn->bitsPerPixel == 16),
196			       ((pScrn->depth != 16)
197			       ? 0 : pScrn->displayWidth),
198			       0xf800, 0x07e0, 0x001f, TrueColor);
199
200	modes = S3SetupDGAMode(pScrn, modes, &num, 16, 16,
201			       (pScrn->bitsPerPixel == 16),
202			       ((pScrn->depth != 16)
203			       ? 0 : pScrn->displayWidth),
204			       0xf800, 0x07e0, 0x001f, DirectColor);
205
206	modes = S3SetupDGAMode(pScrn, modes, &num, 32, 24,
207			       (pScrn->bitsPerPixel == 32),
208			       ((pScrn->bitsPerPixel != 32)
209			       ? 0 : pScrn->displayWidth),
210			       0xff0000, 0x00ff00, 0x0000ff, TrueColor);
211
212	modes = S3SetupDGAMode(pScrn, modes, &num, 32, 24,
213			       (pScrn->bitsPerPixel == 32),
214			       ((pScrn->bitsPerPixel != 32)
215			       ? 0 : pScrn->displayWidth),
216			       0xff0000, 0x00ff00, 0x0000ff, DirectColor);
217
218	pS3->numDGAModes = num;
219	pS3->DGAModes = modes;
220
221	return DGAInit(pScreen, &S3_DGAFuncs, modes, num);
222}
223
224
225static Bool S3_SetMode(ScrnInfoPtr pScrn, DGAModePtr pMode)
226{
227	S3Ptr pS3 = S3PTR(pScrn);
228	static S3FBLayout SavedLayouts[MAXSCREENS];
229	int indx = pScrn->pScreen->myNum;
230
231	if (!pMode) {
232		if (pS3->DGAactive) {
233			memcpy(&pS3->CurrentLayout, &SavedLayouts[indx],
234			       sizeof(S3FBLayout));
235			pS3->DGAactive = TRUE;
236		}
237
238		pS3->CurrentLayout.bitsPerPixel = pMode->bitsPerPixel;
239		pS3->CurrentLayout.depth = pMode->depth;
240		pS3->CurrentLayout.displayWidth = (pMode->bytesPerScanline /
241						   (pMode->bitsPerPixel >> 3));
242		pS3->CurrentLayout.pixel_bytes = pMode->bitsPerPixel / 8;
243		pS3->CurrentLayout.pixel_code = (pMode->bitsPerPixel != 16 ?
244						 pMode->bitsPerPixel :
245						 pMode->depth);
246
247		S3SwitchMode(indx, pMode->mode, 0);
248	}
249
250	return TRUE;
251}
252
253
254static int S3_GetViewport(ScrnInfoPtr pScrn)
255{
256	S3Ptr pS3 = S3PTR(pScrn);
257
258	return pS3->DGAViewportStatus;
259}
260
261
262static void S3_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags)
263{
264	S3Ptr pS3 = S3PTR(pScrn);
265
266	pScrn->AdjustFrame(pScrn->pScreen->myNum, x, y, flags);
267	pS3->DGAViewportStatus = 0;
268}
269
270
271static void S3_FillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h,
272		        unsigned long color)
273{
274	S3Ptr pS3 = S3PTR(pScrn);
275
276	if (pS3->pXAA) {
277		(*pS3->pXAA->SetupForSolidFill)(pScrn, color, GXcopy, (CARD32)(~0));
278		(*pS3->pXAA->SubsequentSolidFillRect)(pScrn, x, y, w, h);
279		SET_SYNC_FLAG(pS3->pXAA);
280	}
281}
282
283
284static void S3_BltRect(ScrnInfoPtr pScrn, int srcx, int srcy, int w, int h,
285		       int dstx, int dsty)
286{
287	S3Ptr pS3 = S3PTR(pScrn);
288
289	if (pS3->pXAA) {
290		int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
291		int ydir = (srcy < dsty) ? -1 : 1;
292
293		(*pS3->pXAA->SetupForScreenToScreenCopy)(pScrn, xdir, ydir,
294							 GXcopy, (CARD32)(~0), -1);
295		(*pS3->pXAA->SubsequentScreenToScreenCopy)(pScrn, srcx, srcy,
296							   dstx, dsty, w, h);
297		SET_SYNC_FLAG(pS3->pXAA);
298	}
299}
300
301
302static Bool S3_OpenFramebuffer(ScrnInfoPtr pScrn, char **name,
303			       unsigned char **mem, int *size, int *offset,
304			       int *flags)
305{
306	S3Ptr pS3 = S3PTR(pScrn);
307
308	*name = NULL;
309	*mem = (unsigned char*)pS3->FBAddress;
310	*size = (pScrn->videoRam * 1024);
311	*offset = 0;
312	*flags = 0;
313
314	return TRUE;
315}
316
317
318static void S3_Sync(ScrnInfoPtr pScrn)
319{
320	WaitIdle();
321}
322