1/*
2 * Copyright 2000 by Alan Hourihane, Sychdyn, North Wales, UK.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Alan Hourihane not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Alan Hourihane makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as is" without express or implied warranty.
13 *
14 * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Authors:  Alan Hourihane, <alanh@fairlite.demon.co.uk>
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include "xf86.h"
30#include "xf86_OSproc.h"
31#include "xf86Pci.h"
32#include "neo.h"
33#include "neo_reg.h"
34#include "dgaproc.h"
35#include "vgaHW.h"
36
37static Bool NEO_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **,
38					int *, int *, int *);
39static Bool NEO_SetMode(ScrnInfoPtr, DGAModePtr);
40static int  NEO_GetViewport(ScrnInfoPtr);
41static void NEO_SetViewport(ScrnInfoPtr, int, int, int);
42#ifdef HAVE_XAA_H
43static void NEO_Sync(ScrnInfoPtr);
44static void NEO_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
45static void NEO_BlitRect(ScrnInfoPtr, int, int, int, int, int, int);
46#if 0
47static void NEO_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int,
48					unsigned long);
49#endif
50#endif
51
52static
53DGAFunctionRec NEODGAFuncs = {
54   NEO_OpenFramebuffer,
55   NULL,
56   NEO_SetMode,
57   NEO_SetViewport,
58   NEO_GetViewport,
59#ifdef HAVE_XAA_H
60   NEO_Sync,
61   NEO_FillRect,
62   NEO_BlitRect,
63#if 0
64   NEO_BlitTransRect
65#else
66   NULL
67#endif
68#else
69   NULL, NULL, NULL
70#endif
71};
72
73Bool
74NEODGAInit(ScreenPtr pScreen)
75{
76   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
77   NEOPtr pNEO = NEOPTR(pScrn);
78   DGAModePtr modes = NULL, newmodes = NULL, currentMode;
79   DisplayModePtr pMode, firstMode;
80   int Bpp = pScrn->bitsPerPixel >> 3;
81   int num = 0, imlines, pixlines;
82
83   imlines =  (pScrn->videoRam * 1024) /
84      (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
85
86   pixlines =  (imlines > 1024 && !pNEO->noAccel)  ? 1024 : imlines;
87
88   pMode = firstMode = pScrn->modes;
89
90   while(pMode) {
91
92	newmodes = realloc(modes, (num + 1) * sizeof(DGAModeRec));
93
94	if(!newmodes) {
95	   free(modes);
96	   return FALSE;
97	}
98	modes = newmodes;
99
100	currentMode = modes + num;
101	num++;
102
103	currentMode->mode = pMode;
104	currentMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE;
105#ifdef HAVE_XAA_H
106	if (!pNEO->noAccel)
107	    currentMode->flags |= (DGA_FILL_RECT | DGA_BLIT_RECT);
108#endif
109	if(pMode->Flags & V_DBLSCAN)
110	   currentMode->flags |= DGA_DOUBLESCAN;
111	if(pMode->Flags & V_INTERLACE)
112	   currentMode->flags |= DGA_INTERLACED;
113	currentMode->byteOrder = pScrn->imageByteOrder;
114	currentMode->depth = pScrn->depth;
115	currentMode->bitsPerPixel = pScrn->bitsPerPixel;
116	currentMode->red_mask = pScrn->mask.red;
117	currentMode->green_mask = pScrn->mask.green;
118	currentMode->blue_mask = pScrn->mask.blue;
119	currentMode->visualClass = (Bpp == 1) ? PseudoColor : TrueColor;
120	currentMode->viewportWidth = pMode->HDisplay;
121	currentMode->viewportHeight = pMode->VDisplay;
122	currentMode->xViewportStep = 1;
123	currentMode->yViewportStep = 1;
124	currentMode->viewportFlags = DGA_FLIP_RETRACE;
125	currentMode->offset = 0;
126	currentMode->address = pNEO->NeoFbBase;
127
128	currentMode->bytesPerScanline =
129			((pScrn->displayWidth * Bpp) + 3) & ~3L;
130	currentMode->imageWidth = pScrn->displayWidth;
131	currentMode->imageHeight =  imlines;
132	currentMode->pixmapWidth = currentMode->imageWidth;
133	currentMode->pixmapHeight = pixlines;
134	currentMode->maxViewportX = currentMode->imageWidth -
135					currentMode->viewportWidth;
136	currentMode->maxViewportY = currentMode->imageHeight -
137					currentMode->viewportHeight;
138
139	pMode = pMode->next;
140	if(pMode == firstMode)
141	   break;
142   }
143
144   pNEO->numDGAModes = num;
145   pNEO->DGAModes = modes;
146
147   return DGAInit(pScreen, &NEODGAFuncs, modes, num);
148}
149
150static DisplayModePtr NEOSavedDGAModes[MAXSCREENS];
151
152static Bool
153NEO_SetMode(
154   ScrnInfoPtr pScrn,
155   DGAModePtr pMode
156){
157   int index = pScrn->pScreen->myNum;
158   NEOPtr pNEO = NEOPTR(pScrn);
159
160   if(!pMode) { /* restore the original mode */
161 	if(pNEO->DGAactive) {
162	    pScrn->currentMode = NEOSavedDGAModes[index];
163            NEOSwitchMode(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode));
164	    NEOAdjustFrame(ADJUST_FRAME_ARGS(pScrn, 0, 0));
165 	    pNEO->DGAactive = FALSE;
166	}
167   } else {
168	if(!pNEO->DGAactive) {  /* save the old parameters */
169	    NEOSavedDGAModes[index] = pScrn->currentMode;
170	    pNEO->DGAactive = TRUE;
171	}
172
173        NEOSwitchMode(SWITCH_MODE_ARGS(pScrn, pMode->mode));
174   }
175
176   return TRUE;
177}
178
179static int
180NEO_GetViewport(
181  ScrnInfoPtr pScrn
182){
183    NEOPtr pNEO = NEOPTR(pScrn);
184
185    return pNEO->DGAViewportStatus;
186}
187
188static void
189NEO_SetViewport(
190   ScrnInfoPtr pScrn,
191   int x, int y,
192   int flags
193){
194   NEOPtr pNEO = NEOPTR(pScrn);
195   vgaHWPtr hwp = VGAHWPTR(pScrn);
196
197   NEOAdjustFrame(ADJUST_FRAME_ARGS(pScrn, x, y));
198   /* wait for retrace */
199   while((hwp->readST01(hwp) & 0x08));
200   while(!(hwp->readST01(hwp) & 0x08));
201
202   pNEO->DGAViewportStatus = 0;
203}
204
205#ifdef HAVE_XAA_H
206static void
207NEO_FillRect (
208   ScrnInfoPtr pScrn,
209   int x, int y, int w, int h,
210   unsigned long color
211){
212    NEOPtr pNEO = NEOPTR(pScrn);
213
214    if(pNEO->AccelInfoRec) {
215	(*pNEO->AccelInfoRec->SetupForSolidFill)(pScrn, color, GXcopy, ~0);
216	(*pNEO->AccelInfoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h);
217	SET_SYNC_FLAG(pNEO->AccelInfoRec);
218    }
219}
220
221static void
222NEO_Sync(
223   ScrnInfoPtr pScrn
224){
225    NEOPtr pNEO = NEOPTR(pScrn);
226    if(pNEO->AccelInfoRec) {
227	(*pNEO->AccelInfoRec->Sync)(pScrn);
228    }
229}
230
231static void
232NEO_BlitRect(
233   ScrnInfoPtr pScrn,
234   int srcx, int srcy,
235   int w, int h,
236   int dstx, int dsty
237){
238    NEOPtr pNEO = NEOPTR(pScrn);
239
240    if(pNEO->AccelInfoRec) {
241	int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
242	int ydir = (srcy < dsty) ? -1 : 1;
243
244	(*pNEO->AccelInfoRec->SetupForScreenToScreenCopy)(
245		pScrn, xdir, ydir, GXcopy, ~0, -1);
246	(*pNEO->AccelInfoRec->SubsequentScreenToScreenCopy)(
247		pScrn, srcx, srcy, dstx, dsty, w, h);
248	SET_SYNC_FLAG(pNEO->AccelInfoRec);
249    }
250}
251
252#if 0
253static void
254NEO_BlitTransRect(
255   ScrnInfoPtr pScrn,
256   int srcx, int srcy,
257   int w, int h,
258   int dstx, int dsty,
259   unsigned long color
260){
261  /* this one should be separate since the XAA function would
262     prohibit usage of ~0 as the key */
263}
264#endif
265#endif
266static Bool
267NEO_OpenFramebuffer(
268   ScrnInfoPtr pScrn,
269   char **name,
270   unsigned char **mem,
271   int *size,
272   int *offset,
273   int *flags
274){
275    NEOPtr pNEO = NEOPTR(pScrn);
276
277    *name = NULL; 		/* no special device */
278    *mem = (unsigned char*)pNEO->NeoLinearAddr;
279    *size = pNEO->NeoFbMapSize;
280    *offset = 0;
281    *flags = DGA_NEED_ROOT;
282
283    return TRUE;
284}
285
286