r128_dri.c revision 42a55b46
1/*
2 * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
3 *                      Precision Insight, Inc., Cedar Park, Texas, and
4 *                      VA Linux Systems Inc., Fremont, California.
5 *
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation on the rights to use, copy, modify, merge,
12 * publish, distribute, sublicense, and/or sell copies of the Software,
13 * and to permit persons to whom the Software is furnished to do so,
14 * subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial
18 * portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
24 * SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include <string.h>
35#include <stdio.h>
36
37/*
38 * Authors:
39 *   Kevin E. Martin <martin@valinux.com>
40 *   Rickard E. Faith <faith@valinux.com>
41 *   Daryll Strauss <daryll@valinux.com>
42 *   Gareth Hughes <gareth@valinux.com>
43 *
44 */
45
46				/* Driver data structures */
47#include "r128.h"
48#include "r128_dri.h"
49#include "r128_common.h"
50#include "r128_reg.h"
51#include "r128_sarea.h"
52#include "r128_version.h"
53
54				/* X and server generic header files */
55#include "xf86.h"
56#include "xf86PciInfo.h"
57#include "windowstr.h"
58
59#include "shadowfb.h"
60				/* GLX/DRI/DRM definitions */
61#define _XF86DRI_SERVER_
62#include "GL/glxtokens.h"
63#include "sarea.h"
64
65static size_t r128_drm_page_size;
66
67static void R128DRITransitionTo2d(ScreenPtr pScreen);
68static void R128DRITransitionTo3d(ScreenPtr pScreen);
69static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen);
70static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen);
71
72static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
73
74/* Initialize the visual configs that are supported by the hardware.
75   These are combined with the visual configs that the indirect
76   rendering core supports, and the intersection is exported to the
77   client. */
78static Bool R128InitVisualConfigs(ScreenPtr pScreen)
79{
80    ScrnInfoPtr       pScrn            = xf86ScreenToScrn(pScreen);
81    R128InfoPtr       info             = R128PTR(pScrn);
82    int               numConfigs       = 0;
83    __GLXvisualConfig *pConfigs        = NULL;
84    R128ConfigPrivPtr pR128Configs     = NULL;
85    R128ConfigPrivPtr *pR128ConfigPtrs = NULL;
86    int               i, accum, stencil, db;
87
88    switch (info->CurrentLayout.pixel_code) {
89    case 8:  /* 8bpp mode is not support */
90    case 15: /* FIXME */
91    case 24: /* FIXME */
92	xf86DrvMsg(pScreen->myNum, X_ERROR,
93		   "[dri] R128DRIScreenInit failed (depth %d not supported).  "
94		   "Disabling DRI.\n", info->CurrentLayout.pixel_code);
95	return FALSE;
96
97#define R128_USE_ACCUM   1
98#define R128_USE_STENCIL 1
99#define R128_USE_DB      1
100
101    case 16:
102	numConfigs = 1;
103	if (R128_USE_ACCUM)   numConfigs *= 2;
104	if (R128_USE_STENCIL) numConfigs *= 2;
105	if (R128_USE_DB)      numConfigs *= 2;
106
107	if (!(pConfigs
108	      = (__GLXvisualConfig*)calloc(sizeof(__GLXvisualConfig),
109					      numConfigs))) {
110	    return FALSE;
111	}
112	if (!(pR128Configs
113	      = (R128ConfigPrivPtr)calloc(sizeof(R128ConfigPrivRec),
114					     numConfigs))) {
115	    free(pConfigs);
116	    return FALSE;
117	}
118	if (!(pR128ConfigPtrs
119	      = (R128ConfigPrivPtr*)calloc(sizeof(R128ConfigPrivPtr),
120					      numConfigs))) {
121	    free(pConfigs);
122	    free(pR128Configs);
123	    return FALSE;
124	}
125
126	i = 0;
127	for (db = 0; db <= R128_USE_DB; db++) {
128	  for (accum = 0; accum <= R128_USE_ACCUM; accum++) {
129	    for (stencil = 0; stencil <= R128_USE_STENCIL; stencil++) {
130		pR128ConfigPtrs[i] = &pR128Configs[i];
131
132		pConfigs[i].vid                = (VisualID)(-1);
133		pConfigs[i].class              = -1;
134		pConfigs[i].rgba               = TRUE;
135		pConfigs[i].redSize            = 5;
136		pConfigs[i].greenSize          = 6;
137		pConfigs[i].blueSize           = 5;
138		pConfigs[i].alphaSize          = 0;
139		pConfigs[i].redMask            = 0x0000F800;
140		pConfigs[i].greenMask          = 0x000007E0;
141		pConfigs[i].blueMask           = 0x0000001F;
142		pConfigs[i].alphaMask          = 0x00000000;
143		if (accum) { /* Simulated in software */
144		    pConfigs[i].accumRedSize   = 16;
145		    pConfigs[i].accumGreenSize = 16;
146		    pConfigs[i].accumBlueSize  = 16;
147		    pConfigs[i].accumAlphaSize = 0;
148		} else {
149		    pConfigs[i].accumRedSize   = 0;
150		    pConfigs[i].accumGreenSize = 0;
151		    pConfigs[i].accumBlueSize  = 0;
152		    pConfigs[i].accumAlphaSize = 0;
153		}
154		if (db)
155		    pConfigs[i].doubleBuffer       = TRUE;
156		else
157		    pConfigs[i].doubleBuffer       = FALSE;
158		pConfigs[i].stereo             = FALSE;
159		pConfigs[i].bufferSize         = 16;
160		pConfigs[i].depthSize          = 16;
161		if (stencil)
162		    pConfigs[i].stencilSize    = 8; /* Simulated in software */
163		else
164		    pConfigs[i].stencilSize    = 0;
165		pConfigs[i].auxBuffers         = 0;
166		pConfigs[i].level              = 0;
167		if (accum || stencil) {
168		   pConfigs[i].visualRating    = GLX_SLOW_CONFIG;
169		} else {
170		   pConfigs[i].visualRating    = GLX_NONE;
171		}
172		pConfigs[i].transparentPixel   = GLX_NONE;
173		pConfigs[i].transparentRed     = 0;
174		pConfigs[i].transparentGreen   = 0;
175		pConfigs[i].transparentBlue    = 0;
176		pConfigs[i].transparentAlpha   = 0;
177		pConfigs[i].transparentIndex   = 0;
178		i++;
179	    }
180	  }
181	}
182	break;
183
184    case 32:
185	numConfigs = 1;
186	if (R128_USE_ACCUM)   numConfigs *= 2;
187	if (R128_USE_STENCIL) numConfigs *= 2;
188	if (R128_USE_DB)      numConfigs *= 2;
189
190	if (!(pConfigs
191	      = (__GLXvisualConfig*)calloc(sizeof(__GLXvisualConfig),
192					      numConfigs))) {
193	    return FALSE;
194	}
195	if (!(pR128Configs
196	      = (R128ConfigPrivPtr)calloc(sizeof(R128ConfigPrivRec),
197					     numConfigs))) {
198	    free(pConfigs);
199	    return FALSE;
200	}
201	if (!(pR128ConfigPtrs
202	      = (R128ConfigPrivPtr*)calloc(sizeof(R128ConfigPrivPtr),
203					      numConfigs))) {
204	    free(pConfigs);
205	    free(pR128Configs);
206	    return FALSE;
207	}
208
209	i = 0;
210	for (db = 0; db <= R128_USE_DB; db++) {
211	  for (accum = 0; accum <= R128_USE_ACCUM; accum++) {
212	    for (stencil = 0; stencil <= R128_USE_STENCIL; stencil++) {
213		pR128ConfigPtrs[i] = &pR128Configs[i];
214
215		pConfigs[i].vid                = (VisualID)(-1);
216		pConfigs[i].class              = -1;
217		pConfigs[i].rgba               = TRUE;
218		pConfigs[i].redSize            = 8;
219		pConfigs[i].greenSize          = 8;
220		pConfigs[i].blueSize           = 8;
221		pConfigs[i].alphaSize          = 0;
222		pConfigs[i].redMask            = 0x00FF0000;
223		pConfigs[i].greenMask          = 0x0000FF00;
224		pConfigs[i].blueMask           = 0x000000FF;
225		pConfigs[i].alphaMask          = 0x00000000;
226		if (accum) { /* Simulated in software */
227		    pConfigs[i].accumRedSize   = 16;
228		    pConfigs[i].accumGreenSize = 16;
229		    pConfigs[i].accumBlueSize  = 16;
230		    pConfigs[i].accumAlphaSize = 0;
231		} else {
232		    pConfigs[i].accumRedSize   = 0;
233		    pConfigs[i].accumGreenSize = 0;
234		    pConfigs[i].accumBlueSize  = 0;
235		    pConfigs[i].accumAlphaSize = 0;
236		}
237		if (db)
238		    pConfigs[i].doubleBuffer       = TRUE;
239		else
240		    pConfigs[i].doubleBuffer       = FALSE;
241		pConfigs[i].stereo             = FALSE;
242		pConfigs[i].bufferSize         = 24;
243		if (stencil) {
244		    pConfigs[i].depthSize      = 24;
245		    pConfigs[i].stencilSize    = 8;
246		} else {
247		    pConfigs[i].depthSize      = 24;
248		    pConfigs[i].stencilSize    = 0;
249		}
250		pConfigs[i].auxBuffers         = 0;
251		pConfigs[i].level              = 0;
252		if (accum) {
253		   pConfigs[i].visualRating    = GLX_SLOW_CONFIG;
254		} else {
255		   pConfigs[i].visualRating    = GLX_NONE;
256		}
257		pConfigs[i].transparentPixel   = GLX_NONE;
258		pConfigs[i].transparentRed     = 0;
259		pConfigs[i].transparentGreen   = 0;
260		pConfigs[i].transparentBlue    = 0;
261		pConfigs[i].transparentAlpha   = 0;
262		pConfigs[i].transparentIndex   = 0;
263		i++;
264	    }
265	  }
266	}
267	break;
268    }
269
270    info->numVisualConfigs   = numConfigs;
271    info->pVisualConfigs     = pConfigs;
272    info->pVisualConfigsPriv = pR128Configs;
273    GlxSetVisualConfigs(numConfigs, pConfigs, (void**)pR128ConfigPtrs);
274    return TRUE;
275}
276
277/* Create the Rage 128-specific context information */
278static Bool R128CreateContext(ScreenPtr pScreen, VisualPtr visual,
279			      drm_context_t hwContext, void *pVisualConfigPriv,
280			      DRIContextType contextStore)
281{
282    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
283    R128InfoPtr info = R128PTR(pScrn);
284
285    info->drmCtx = hwContext;
286    return TRUE;
287}
288
289/* Destroy the Rage 128-specific context information */
290static void R128DestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
291			       DRIContextType contextStore)
292{
293    /* Nothing yet */
294}
295
296/* Called when the X server is woken up to allow the last client's
297   context to be saved and the X server's context to be loaded.  This is
298   not necessary for the Rage 128 since the client detects when it's
299   context is not currently loaded and then load's it itself.  Since the
300   registers to start and stop the CCE are privileged, only the X server
301   can start/stop the engine. */
302static void R128EnterServer(ScreenPtr pScreen)
303{
304    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
305    R128InfoPtr info = R128PTR(pScrn);
306
307#ifdef HAVE_XAA_H
308    if (info->accel) info->accel->NeedToSync = TRUE;
309#endif
310#ifdef USE_EXA
311    if (info->ExaDriver) exaMarkSync(pScreen);
312    info->state_2d.composite_setup = FALSE;
313#endif
314}
315
316/* Called when the X server goes to sleep to allow the X server's
317   context to be saved and the last client's context to be loaded.  This
318   is not necessary for the Rage 128 since the client detects when it's
319   context is not currently loaded and then load's it itself.  Since the
320   registers to start and stop the CCE are privileged, only the X server
321   can start/stop the engine. */
322static void R128LeaveServer(ScreenPtr pScreen)
323{
324    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
325    R128InfoPtr   info      = R128PTR(pScrn);
326    unsigned char *R128MMIO = info->MMIO;
327
328    if (!info->directRenderingEnabled) {
329	/* Save all hardware scissors */
330	info->sc_left     = INREG(R128_SC_LEFT);
331	info->sc_right    = INREG(R128_SC_RIGHT);
332	info->sc_top      = INREG(R128_SC_TOP);
333	info->sc_bottom   = INREG(R128_SC_BOTTOM);
334	info->aux_sc_cntl = INREG(R128_SC_BOTTOM);
335    } else if (info->CCEInUse) {
336	R128CCEReleaseIndirect(pScrn);
337
338	info->CCEInUse = FALSE;
339    }
340}
341
342/* Contexts can be swapped by the X server if necessary.  This callback
343   is currently only used to perform any functions necessary when
344   entering or leaving the X server, and in the future might not be
345   necessary. */
346static void R128DRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
347			       DRIContextType oldContextType, void *oldContext,
348			       DRIContextType newContextType, void *newContext)
349{
350    if ((syncType==DRI_3D_SYNC) && (oldContextType==DRI_2D_CONTEXT) &&
351	(newContextType==DRI_2D_CONTEXT)) { /* Entering from Wakeup */
352	R128EnterServer(pScreen);
353    }
354    if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) &&
355	(newContextType==DRI_2D_CONTEXT)) { /* Exiting from Block Handler */
356	R128LeaveServer(pScreen);
357    }
358}
359
360/* Initialize the state of the back and depth buffers. */
361static void R128DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 indx)
362{
363    /* FIXME: This routine needs to have acceleration turned on */
364    ScreenPtr   pScreen = pWin->drawable.pScreen;
365    ScrnInfoPtr pScrn   = xf86ScreenToScrn(pScreen);
366    R128InfoPtr info    = R128PTR(pScrn);
367#ifdef HAVE_XAA_H
368    BoxPtr      pbox, pboxSave;
369    int         nbox, nboxSave;
370    int         depth;
371#endif
372
373    /* FIXME: Use accel when CCE 2D code is written
374     * EA: What is this code kept for? Radeon doesn't have it and
375     * has a comment: "There's no need for the 2d driver to be clearing
376     * buffers for the 3d client.  It knows how to do that on its own."
377     */
378    if (info->directRenderingEnabled)
379	return;
380#ifdef HAVE_XAA_H
381    /* FIXME: This should be based on the __GLXvisualConfig info */
382    switch (pScrn->bitsPerPixel) {
383    case  8: depth = 0x000000ff; break;
384    case 16: depth = 0x0000ffff; break;
385    case 24: depth = 0x00ffffff; break;
386    case 32: depth = 0xffffffff; break;
387    default: depth = 0x00000000; break;
388    }
389
390    /* FIXME: Copy XAAPaintWindow() and use REGION_TRANSLATE() */
391    /* FIXME: Only initialize the back and depth buffers for contexts
392       that request them */
393
394    pboxSave = pbox = REGION_RECTS(prgn);
395    nboxSave = nbox = REGION_NUM_RECTS(prgn);
396
397    (*info->accel->SetupForSolidFill)(pScrn, 0, GXcopy, (CARD32)(-1));
398    for (; nbox; nbox--, pbox++) {
399	(*info->accel->SubsequentSolidFillRect)(pScrn,
400						pbox->x1 + info->fbX,
401						pbox->y1 + info->fbY,
402						pbox->x2 - pbox->x1,
403						pbox->y2 - pbox->y1);
404	(*info->accel->SubsequentSolidFillRect)(pScrn,
405						pbox->x1 + info->backX,
406						pbox->y1 + info->backY,
407						pbox->x2 - pbox->x1,
408						pbox->y2 - pbox->y1);
409    }
410
411    pbox = pboxSave;
412    nbox = nboxSave;
413
414    /* FIXME: this needs to consider depth tiling. */
415    (*info->accel->SetupForSolidFill)(pScrn, depth, GXcopy, (CARD32)(-1));
416    for (; nbox; nbox--, pbox++)
417	(*info->accel->SubsequentSolidFillRect)(pScrn,
418						pbox->x1 + info->depthX,
419						pbox->y1 + info->depthY,
420						pbox->x2 - pbox->x1,
421						pbox->y2 - pbox->y1);
422
423    info->accel->NeedToSync = TRUE;
424#endif
425}
426
427/* Copy the back and depth buffers when the X server moves a window. */
428static void R128DRIMoveBuffers(WindowPtr pWin, DDXPointRec ptOldOrg,
429			       RegionPtr prgnSrc, CARD32 indx)
430{
431    ScreenPtr   pScreen = pWin->drawable.pScreen;
432    ScrnInfoPtr pScrn   = xf86ScreenToScrn(pScreen);
433    R128InfoPtr info   = R128PTR(pScrn);
434
435    /* FIXME: This routine needs to have acceleration turned on */
436    /* FIXME: Copy XAACopyWindow() and use REGION_TRANSLATE() */
437    /* FIXME: Only initialize the back and depth buffers for contexts
438       that request them */
439
440    /* FIXME: Use accel when CCE 2D code is written */
441    if (info->directRenderingEnabled)
442	return;
443}
444
445/* Initialize the AGP state.  Request memory for use in AGP space, and
446   initialize the Rage 128 registers to point to that memory. */
447static Bool R128DRIAgpInit(R128InfoPtr info, ScreenPtr pScreen)
448{
449    unsigned char *R128MMIO = info->MMIO;
450    unsigned long mode;
451    unsigned int  vendor, device;
452    int           ret;
453    unsigned long cntl, chunk;
454    int           s, l;
455    int           flags;
456    unsigned long agpBase;
457
458    if (drmAgpAcquire(info->drmFD) < 0) {
459	xf86DrvMsg(pScreen->myNum, X_WARNING, "[agp] AGP not available\n");
460	return FALSE;
461    }
462
463				/* Modify the mode if the default mode is
464				   not appropriate for this particular
465				   combination of graphics card and AGP
466				   chipset. */
467
468    mode   = drmAgpGetMode(info->drmFD);        /* Default mode */
469    vendor = drmAgpVendorId(info->drmFD);
470    device = drmAgpDeviceId(info->drmFD);
471
472    mode &= ~R128_AGP_MODE_MASK;
473    switch (info->agpMode) {
474    case 4:          mode |= R128_AGP_4X_MODE;
475    case 2:          mode |= R128_AGP_2X_MODE;
476    case 1: default: mode |= R128_AGP_1X_MODE;
477    }
478
479    xf86DrvMsg(pScreen->myNum, X_INFO,
480	       "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n",
481	       mode, vendor, device,
482	       PCI_DEV_VENDOR_ID(info->PciInfo),
483	       PCI_DEV_DEVICE_ID(info->PciInfo));
484
485    if (drmAgpEnable(info->drmFD, mode) < 0) {
486	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n");
487	drmAgpRelease(info->drmFD);
488	return FALSE;
489    }
490
491    info->agpOffset = 0;
492
493    if ((ret = drmAgpAlloc(info->drmFD, info->agpSize*1024*1024, 0, NULL,
494			   &info->agpMemHandle)) < 0) {
495	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret);
496	drmAgpRelease(info->drmFD);
497	return FALSE;
498    }
499    xf86DrvMsg(pScreen->myNum, X_INFO,
500	       "[agp] %d kB allocated with handle 0x%08x\n",
501	       info->agpSize*1024, info->agpMemHandle);
502
503    if (drmAgpBind(info->drmFD, info->agpMemHandle, info->agpOffset) < 0) {
504	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not bind\n");
505	drmAgpFree(info->drmFD, info->agpMemHandle);
506	drmAgpRelease(info->drmFD);
507	return FALSE;
508    }
509
510				/* Initialize the CCE ring buffer data */
511    info->ringStart       = info->agpOffset;
512    info->ringMapSize     = info->ringSize*1024*1024 + r128_drm_page_size;
513    info->ringSizeLog2QW  = R128MinBits(info->ringSize*1024*1024/8) - 1;
514
515    info->ringReadOffset  = info->ringStart + info->ringMapSize;
516    info->ringReadMapSize = r128_drm_page_size;
517
518				/* Reserve space for vertex/indirect buffers */
519    info->bufStart        = info->ringReadOffset + info->ringReadMapSize;
520    info->bufMapSize      = info->bufSize*1024*1024;
521
522				/* Reserve the rest for AGP textures */
523    info->agpTexStart     = info->bufStart + info->bufMapSize;
524    s = (info->agpSize*1024*1024 - info->agpTexStart);
525    l = R128MinBits((s-1) / R128_NR_TEX_REGIONS);
526    if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY;
527    info->agpTexMapSize   = (s >> l) << l;
528    info->log2AGPTexGran  = l;
529
530    if (info->CCESecure) flags = DRM_READ_ONLY;
531    else                  flags = 0;
532
533    if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize,
534		  DRM_AGP, flags, &info->ringHandle) < 0) {
535	xf86DrvMsg(pScreen->myNum, X_ERROR,
536		   "[agp] Could not add ring mapping\n");
537	return FALSE;
538    }
539    xf86DrvMsg(pScreen->myNum, X_INFO,
540	       "[agp] ring handle = 0x%08x\n", info->ringHandle);
541
542    if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize,
543	       &info->ring) < 0) {
544	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not map ring\n");
545	return FALSE;
546    }
547    xf86DrvMsg(pScreen->myNum, X_INFO,
548	       "[agp] Ring mapped at 0x%08lx\n",
549	       (unsigned long)info->ring);
550
551    if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize,
552		  DRM_AGP, flags, &info->ringReadPtrHandle) < 0) {
553	xf86DrvMsg(pScreen->myNum, X_ERROR,
554		   "[agp] Could not add ring read ptr mapping\n");
555	return FALSE;
556    }
557    xf86DrvMsg(pScreen->myNum, X_INFO,
558 	       "[agp] ring read ptr handle = 0x%08x\n",
559	       info->ringReadPtrHandle);
560
561    if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize,
562	       &info->ringReadPtr) < 0) {
563	xf86DrvMsg(pScreen->myNum, X_ERROR,
564		   "[agp] Could not map ring read ptr\n");
565	return FALSE;
566    }
567    xf86DrvMsg(pScreen->myNum, X_INFO,
568	       "[agp] Ring read ptr mapped at 0x%08lx\n",
569	       (unsigned long)info->ringReadPtr);
570
571    if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize,
572		  DRM_AGP, 0, &info->bufHandle) < 0) {
573	xf86DrvMsg(pScreen->myNum, X_ERROR,
574		   "[agp] Could not add vertex/indirect buffers mapping\n");
575	return FALSE;
576    }
577    xf86DrvMsg(pScreen->myNum, X_INFO,
578	       "[agp] vertex/indirect buffers handle = 0x%08x\n",
579	       info->bufHandle);
580
581    if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize,
582	       &info->buf) < 0) {
583	xf86DrvMsg(pScreen->myNum, X_ERROR,
584		   "[agp] Could not map vertex/indirect buffers\n");
585	return FALSE;
586    }
587    xf86DrvMsg(pScreen->myNum, X_INFO,
588	       "[agp] Vertex/indirect buffers mapped at 0x%08lx\n",
589	       (unsigned long)info->buf);
590
591    if (drmAddMap(info->drmFD, info->agpTexStart, info->agpTexMapSize,
592		  DRM_AGP, 0, &info->agpTexHandle) < 0) {
593	xf86DrvMsg(pScreen->myNum, X_ERROR,
594		   "[agp] Could not add AGP texture map mapping\n");
595	return FALSE;
596    }
597    xf86DrvMsg(pScreen->myNum, X_INFO,
598	       "[agp] AGP texture map handle = 0x%08x\n",
599	       info->agpTexHandle);
600
601    if (drmMap(info->drmFD, info->agpTexHandle, info->agpTexMapSize,
602	       &info->agpTex) < 0) {
603	xf86DrvMsg(pScreen->myNum, X_ERROR,
604		   "[agp] Could not map AGP texture map\n");
605	return FALSE;
606    }
607    xf86DrvMsg(pScreen->myNum, X_INFO,
608	       "[agp] AGP Texture map mapped at 0x%08lx\n",
609	       (unsigned long)info->agpTex);
610
611				/* Initialize Rage 128's AGP registers */
612    cntl  = INREG(R128_AGP_CNTL);
613    cntl &= ~R128_AGP_APER_SIZE_MASK;
614    switch (info->agpSize) {
615    case 256: cntl |= R128_AGP_APER_SIZE_256MB; break;
616    case 128: cntl |= R128_AGP_APER_SIZE_128MB; break;
617    case  64: cntl |= R128_AGP_APER_SIZE_64MB;  break;
618    case  32: cntl |= R128_AGP_APER_SIZE_32MB;  break;
619    case  16: cntl |= R128_AGP_APER_SIZE_16MB;  break;
620    case   8: cntl |= R128_AGP_APER_SIZE_8MB;   break;
621    case   4: cntl |= R128_AGP_APER_SIZE_4MB;   break;
622    default:
623	xf86DrvMsg(pScreen->myNum, X_ERROR,
624		   "[agp] Illegal aperture size %d kB\n",
625		   info->agpSize*1024);
626	return FALSE;
627    }
628    agpBase = drmAgpBase(info->drmFD);
629    OUTREG(R128_AGP_BASE, agpBase);
630    OUTREG(R128_AGP_CNTL, cntl);
631
632				/* Disable Rage 128's PCIGART registers */
633    chunk = INREG(R128_BM_CHUNK_0_VAL);
634    chunk &= ~(R128_BM_PTR_FORCE_TO_PCI |
635	       R128_BM_PM4_RD_FORCE_TO_PCI |
636	       R128_BM_GLOBAL_FORCE_TO_PCI);
637    OUTREG(R128_BM_CHUNK_0_VAL, chunk);
638
639    OUTREG(R128_PCI_GART_PAGE, 1); /* Ensure AGP GART is used (for now) */
640
641    return TRUE;
642}
643
644static Bool R128DRIPciInit(R128InfoPtr info, ScreenPtr pScreen)
645{
646    unsigned char *R128MMIO = info->MMIO;
647    CARD32 chunk;
648    int ret;
649    int flags;
650
651    info->agpOffset = 0;
652
653    ret = drmScatterGatherAlloc(info->drmFD, info->agpSize*1024*1024,
654				&info->pciMemHandle);
655    if (ret < 0) {
656	xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Out of memory (%d)\n", ret);
657	return FALSE;
658    }
659    xf86DrvMsg(pScreen->myNum, X_INFO,
660	       "[pci] %d kB allocated with handle 0x%08x\n",
661	       info->agpSize*1024, info->pciMemHandle);
662
663				/* Initialize the CCE ring buffer data */
664    info->ringStart       = info->agpOffset;
665    info->ringMapSize     = info->ringSize*1024*1024 + r128_drm_page_size;
666    info->ringSizeLog2QW  = R128MinBits(info->ringSize*1024*1024/8) - 1;
667
668    info->ringReadOffset  = info->ringStart + info->ringMapSize;
669    info->ringReadMapSize = r128_drm_page_size;
670
671				/* Reserve space for vertex/indirect buffers */
672    info->bufStart        = info->ringReadOffset + info->ringReadMapSize;
673    info->bufMapSize      = info->bufSize*1024*1024;
674
675    flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL;
676
677    if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize,
678		  DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) {
679	xf86DrvMsg(pScreen->myNum, X_ERROR,
680		   "[pci] Could not add ring mapping\n");
681	return FALSE;
682    }
683    xf86DrvMsg(pScreen->myNum, X_INFO,
684	       "[pci] ring handle = 0x%08x\n", info->ringHandle);
685
686    if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize,
687	       &info->ring) < 0) {
688	xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Could not map ring\n");
689	return FALSE;
690    }
691    xf86DrvMsg(pScreen->myNum, X_INFO,
692	       "[pci] Ring mapped at 0x%08lx\n",
693	       (unsigned long)info->ring);
694    xf86DrvMsg(pScreen->myNum, X_INFO,
695	       "[pci] Ring contents 0x%08lx\n",
696	       *(unsigned long *)(pointer)info->ring);
697
698    if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize,
699		  DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) {
700	xf86DrvMsg(pScreen->myNum, X_ERROR,
701		   "[pci] Could not add ring read ptr mapping\n");
702	return FALSE;
703    }
704    xf86DrvMsg(pScreen->myNum, X_INFO,
705	       "[pci] ring read ptr handle = 0x%08x\n",
706	       info->ringReadPtrHandle);
707
708    if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize,
709	       &info->ringReadPtr) < 0) {
710	xf86DrvMsg(pScreen->myNum, X_ERROR,
711		   "[pci] Could not map ring read ptr\n");
712	return FALSE;
713    }
714    xf86DrvMsg(pScreen->myNum, X_INFO,
715	       "[pci] Ring read ptr mapped at 0x%08lx\n",
716	       (unsigned long)info->ringReadPtr);
717    xf86DrvMsg(pScreen->myNum, X_INFO,
718	       "[pci] Ring read ptr contents 0x%08lx\n",
719	       *(unsigned long *)(pointer)info->ringReadPtr);
720
721    if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize,
722		  DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) {
723	xf86DrvMsg(pScreen->myNum, X_ERROR,
724		   "[pci] Could not add vertex/indirect buffers mapping\n");
725	return FALSE;
726    }
727    xf86DrvMsg(pScreen->myNum, X_INFO,
728	       "[pci] vertex/indirect buffers handle = 0x%08x\n",
729	       info->bufHandle);
730
731    if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize,
732	       &info->buf) < 0) {
733	xf86DrvMsg(pScreen->myNum, X_ERROR,
734		   "[pci] Could not map vertex/indirect buffers\n");
735	return FALSE;
736    }
737    xf86DrvMsg(pScreen->myNum, X_INFO,
738	       "[pci] Vertex/indirect buffers mapped at 0x%08lx\n",
739	       (unsigned long)info->buf);
740    xf86DrvMsg(pScreen->myNum, X_INFO,
741	       "[pci] Vertex/indirect buffers contents 0x%08lx\n",
742	       *(unsigned long *)(pointer)info->buf);
743
744    switch (info->Chipset) {
745    case PCI_CHIP_RAGE128LE:
746    case PCI_CHIP_RAGE128RE:
747    case PCI_CHIP_RAGE128RK:
748    case PCI_CHIP_RAGE128PD:
749    case PCI_CHIP_RAGE128PP:
750    case PCI_CHIP_RAGE128PR:
751	/* This is a PCI card, do nothing */
752	break;
753
754    case PCI_CHIP_RAGE128LF:
755    case PCI_CHIP_RAGE128MF:
756    case PCI_CHIP_RAGE128ML:
757    case PCI_CHIP_RAGE128RF:
758    case PCI_CHIP_RAGE128RG:
759    case PCI_CHIP_RAGE128RL:
760    case PCI_CHIP_RAGE128SM:
761    case PCI_CHIP_RAGE128PF:
762    case PCI_CHIP_RAGE128TF:
763    case PCI_CHIP_RAGE128TL:
764    case PCI_CHIP_RAGE128TR:
765    /* FIXME: ATI documentation does not specify if the following chips are
766     * AGP or PCI, it just mentions their PCI IDs.  I'm assuming they're AGP
767     * until I get more correct information. <mharris@redhat.com>
768     */
769    case PCI_CHIP_RAGE128PA:
770    case PCI_CHIP_RAGE128PB:
771    case PCI_CHIP_RAGE128PC:
772    case PCI_CHIP_RAGE128PE:
773    case PCI_CHIP_RAGE128PG:
774    case PCI_CHIP_RAGE128PH:
775    case PCI_CHIP_RAGE128PI:
776    case PCI_CHIP_RAGE128PJ:
777    case PCI_CHIP_RAGE128PK:
778    case PCI_CHIP_RAGE128PL:
779    case PCI_CHIP_RAGE128PM:
780    case PCI_CHIP_RAGE128PN:
781    case PCI_CHIP_RAGE128PO:
782    case PCI_CHIP_RAGE128PQ:
783    case PCI_CHIP_RAGE128PS:
784    case PCI_CHIP_RAGE128PT:
785    case PCI_CHIP_RAGE128PU:
786    case PCI_CHIP_RAGE128PV:
787    case PCI_CHIP_RAGE128PW:
788    case PCI_CHIP_RAGE128PX:
789    case PCI_CHIP_RAGE128SE:
790    case PCI_CHIP_RAGE128SF:
791    case PCI_CHIP_RAGE128SG:
792    case PCI_CHIP_RAGE128SH:
793    case PCI_CHIP_RAGE128SK:
794    case PCI_CHIP_RAGE128SL:
795    case PCI_CHIP_RAGE128SN:
796    case PCI_CHIP_RAGE128TS:
797    case PCI_CHIP_RAGE128TT:
798    case PCI_CHIP_RAGE128TU:
799    default:
800	/* This is really an AGP card, force PCI GART mode */
801        chunk = INREG(R128_BM_CHUNK_0_VAL);
802        chunk |= (R128_BM_PTR_FORCE_TO_PCI |
803		  R128_BM_PM4_RD_FORCE_TO_PCI |
804		  R128_BM_GLOBAL_FORCE_TO_PCI);
805        OUTREG(R128_BM_CHUNK_0_VAL, chunk);
806        OUTREG(R128_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */
807        break;
808    }
809
810    return TRUE;
811}
812
813/* Add a map for the MMIO registers that will be accessed by any
814   DRI-based clients. */
815static Bool R128DRIMapInit(R128InfoPtr info, ScreenPtr pScreen)
816{
817    int flags;
818
819    if (info->CCESecure) flags = DRM_READ_ONLY;
820    else                 flags = 0;
821
822				/* Map registers */
823    info->registerSize = R128_MMIOSIZE;
824    if (drmAddMap(info->drmFD, info->MMIOAddr, info->registerSize,
825		  DRM_REGISTERS, flags, &info->registerHandle) < 0) {
826	return FALSE;
827    }
828    xf86DrvMsg(pScreen->myNum, X_INFO,
829	       "[drm] register handle = 0x%08x\n", info->registerHandle);
830
831    return TRUE;
832}
833
834/* Initialize the kernel data structures. */
835static int R128DRIKernelInit(R128InfoPtr info, ScreenPtr pScreen)
836{
837    drmR128Init drmInfo;
838
839    memset( &drmInfo, 0, sizeof(drmR128Init) );
840
841    drmInfo.func                = DRM_R128_INIT_CCE;
842    drmInfo.sarea_priv_offset   = sizeof(XF86DRISAREARec);
843    drmInfo.is_pci              = info->IsPCI;
844    drmInfo.cce_mode            = info->CCEMode;
845    drmInfo.cce_secure          = info->CCESecure;
846    drmInfo.ring_size           = info->ringSize*1024*1024;
847    drmInfo.usec_timeout        = info->CCEusecTimeout;
848
849    drmInfo.fb_bpp              = info->CurrentLayout.pixel_code;
850    drmInfo.depth_bpp           = info->CurrentLayout.pixel_code;
851
852    drmInfo.front_offset        = info->frontOffset;
853    drmInfo.front_pitch         = info->frontPitch;
854
855    drmInfo.back_offset         = info->backOffset;
856    drmInfo.back_pitch          = info->backPitch;
857
858    drmInfo.depth_offset        = info->depthOffset;
859    drmInfo.depth_pitch         = info->depthPitch;
860    drmInfo.span_offset         = info->spanOffset;
861
862    drmInfo.fb_offset           = info->fbHandle;
863    drmInfo.mmio_offset         = info->registerHandle;
864    drmInfo.ring_offset         = info->ringHandle;
865    drmInfo.ring_rptr_offset    = info->ringReadPtrHandle;
866    drmInfo.buffers_offset      = info->bufHandle;
867    drmInfo.agp_textures_offset = info->agpTexHandle;
868
869    if (drmCommandWrite(info->drmFD, DRM_R128_INIT,
870                        &drmInfo, sizeof(drmR128Init)) < 0)
871        return FALSE;
872
873    return TRUE;
874}
875
876/* Add a map for the vertex buffers that will be accessed by any
877   DRI-based clients. */
878static Bool R128DRIBufInit(R128InfoPtr info, ScreenPtr pScreen)
879{
880				/* Initialize vertex buffers */
881    if (info->IsPCI) {
882	info->bufNumBufs = drmAddBufs(info->drmFD,
883				      info->bufMapSize / R128_BUFFER_SIZE,
884				      R128_BUFFER_SIZE,
885				      DRM_SG_BUFFER,
886				      info->bufStart);
887    } else {
888	info->bufNumBufs = drmAddBufs(info->drmFD,
889				      info->bufMapSize / R128_BUFFER_SIZE,
890				      R128_BUFFER_SIZE,
891				      DRM_AGP_BUFFER,
892				      info->bufStart);
893    }
894    if (info->bufNumBufs <= 0) {
895	xf86DrvMsg(pScreen->myNum, X_ERROR,
896		   "[drm] Could not create vertex/indirect buffers list\n");
897	return FALSE;
898    }
899    xf86DrvMsg(pScreen->myNum, X_INFO,
900	       "[drm] Added %d %d byte vertex/indirect buffers\n",
901	       info->bufNumBufs, R128_BUFFER_SIZE);
902
903    if (!(info->buffers = drmMapBufs(info->drmFD))) {
904	xf86DrvMsg(pScreen->myNum, X_ERROR,
905		   "[drm] Failed to map vertex/indirect buffers list\n");
906	return FALSE;
907    }
908    xf86DrvMsg(pScreen->myNum, X_INFO,
909	       "[drm] Mapped %d vertex/indirect buffers\n",
910	       info->buffers->count);
911
912    return TRUE;
913}
914
915static void R128DRIIrqInit(R128InfoPtr info, ScreenPtr pScreen)
916{
917   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
918
919   if (!info->irq) {
920      info->irq = drmGetInterruptFromBusID(
921	 info->drmFD,
922	 PCI_CFG_BUS(info->PciInfo),
923	 PCI_CFG_DEV(info->PciInfo),
924	 PCI_CFG_FUNC(info->PciInfo));
925
926      if((drmCtlInstHandler(info->drmFD, info->irq)) != 0) {
927	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
928		    "[drm] failure adding irq handler, "
929		    "there is a device already using that irq\n"
930		    "[drm] falling back to irq-free operation\n");
931	 info->irq = 0;
932      } else {
933          unsigned char *R128MMIO = info->MMIO;
934          info->gen_int_cntl = INREG( R128_GEN_INT_CNTL );
935      }
936   }
937
938   if (info->irq)
939      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
940		 "[drm] dma control initialized, using IRQ %d\n",
941		 info->irq);
942}
943
944/* Initialize the CCE state, and start the CCE (if used by the X server) */
945static void R128DRICCEInit(ScrnInfoPtr pScrn)
946{
947    R128InfoPtr   info      = R128PTR(pScrn);
948
949				/* Turn on bus mastering */
950    info->BusCntl &= ~R128_BUS_MASTER_DIS;
951
952				/* CCEMode is initialized in r128_driver.c */
953    switch (info->CCEMode) {
954    case R128_PM4_NONPM4:                 info->CCEFifoSize = 0;   break;
955    case R128_PM4_192PIO:                 info->CCEFifoSize = 192; break;
956    case R128_PM4_192BM:                  info->CCEFifoSize = 192; break;
957    case R128_PM4_128PIO_64INDBM:         info->CCEFifoSize = 128; break;
958    case R128_PM4_128BM_64INDBM:          info->CCEFifoSize = 128; break;
959    case R128_PM4_64PIO_128INDBM:         info->CCEFifoSize = 64;  break;
960    case R128_PM4_64BM_128INDBM:          info->CCEFifoSize = 64;  break;
961    case R128_PM4_64PIO_64VCBM_64INDBM:   info->CCEFifoSize = 64;  break;
962    case R128_PM4_64BM_64VCBM_64INDBM:    info->CCEFifoSize = 64;  break;
963    case R128_PM4_64PIO_64VCPIO_64INDPIO: info->CCEFifoSize = 64;  break;
964    }
965
966    if (info->directRenderingEnabled) {
967				/* Make sure the CCE is on for the X server */
968	R128CCE_START(pScrn, info);
969    } else {
970				/* Make sure the CCE is off for the X server */
971	R128CCE_STOP(pScrn, info);
972    }
973}
974
975/* Initialize the screen-specific data structures for the DRI and the
976   Rage 128.  This is the main entry point to the device-specific
977   initialization code.  It calls device-independent DRI functions to
978   create the DRI data structures and initialize the DRI state. */
979Bool R128DRIScreenInit(ScreenPtr pScreen)
980{
981    ScrnInfoPtr   pScrn = xf86ScreenToScrn(pScreen);
982    R128InfoPtr   info = R128PTR(pScrn);
983    DRIInfoPtr    pDRIInfo;
984    R128DRIPtr    pR128DRI;
985    int           major, minor, patch;
986    drmVersionPtr version;
987
988    /* Check that the GLX, DRI, and DRM modules have been loaded by testing
989     * for known symbols in each module. */
990    if (!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) return FALSE;
991    if (!xf86LoaderCheckSymbol("drmAvailable"))        return FALSE;
992    if (!xf86LoaderCheckSymbol("DRIQueryVersion")) {
993      xf86DrvMsg(pScreen->myNum, X_ERROR,
994		 "[dri] R128DRIScreenInit failed (libdri.a too old)\n");
995      return FALSE;
996    }
997
998    /* Check the DRI version */
999    DRIQueryVersion(&major, &minor, &patch);
1000    if (major != DRIINFO_MAJOR_VERSION || minor < 0) {
1001	xf86DrvMsg(pScreen->myNum, X_ERROR,
1002		"[dri] R128DRIScreenInit failed because of a version mismatch.\n"
1003		"[dri] libdri version is %d.%d.%d but version %d.%d.x is needed.\n"
1004		"[dri] Disabling the DRI.\n",
1005		major, minor, patch,
1006                DRIINFO_MAJOR_VERSION, 0);
1007	return FALSE;
1008    }
1009
1010    switch (info->CurrentLayout.pixel_code) {
1011    case 8:
1012	/* These modes are not supported (yet). */
1013    case 15:
1014    case 24:
1015	xf86DrvMsg(pScreen->myNum, X_ERROR,
1016		   "[dri] R128DRIScreenInit failed (depth %d not supported).  "
1017		   "[dri] Disabling DRI.\n", info->CurrentLayout.pixel_code);
1018	return FALSE;
1019
1020	/* Only 16 and 32 color depths are supports currently. */
1021    case 16:
1022    case 32:
1023	break;
1024    }
1025
1026    r128_drm_page_size = getpagesize();
1027
1028    /* Create the DRI data structure, and fill it in before calling the
1029       DRIScreenInit(). */
1030    if (!(pDRIInfo = DRICreateInfoRec())) return FALSE;
1031
1032    info->pDRIInfo                       = pDRIInfo;
1033    pDRIInfo->drmDriverName              = R128_DRIVER_NAME;
1034    pDRIInfo->clientDriverName           = R128_DRIVER_NAME;
1035    if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) {
1036	pDRIInfo->busIdString = DRICreatePCIBusID(info->PciInfo);
1037    } else {
1038	pDRIInfo->busIdString            = malloc(64);
1039	sprintf(pDRIInfo->busIdString,
1040		"PCI:%d:%d:%d",
1041		PCI_DEV_BUS(info->PciInfo),
1042		PCI_DEV_DEV(info->PciInfo),
1043		PCI_DEV_FUNC(info->PciInfo));
1044    }
1045    pDRIInfo->ddxDriverMajorVersion      = R128_VERSION_MAJOR;
1046    pDRIInfo->ddxDriverMinorVersion      = R128_VERSION_MINOR;
1047    pDRIInfo->ddxDriverPatchVersion      = R128_VERSION_PATCH;
1048    pDRIInfo->frameBufferPhysicalAddress = (void *)info->LinearAddr;
1049    pDRIInfo->frameBufferSize            = info->FbMapSize;
1050    pDRIInfo->frameBufferStride          = (pScrn->displayWidth *
1051					    info->CurrentLayout.pixel_bytes);
1052    pDRIInfo->ddxDrawableTableEntry      = R128_MAX_DRAWABLES;
1053    pDRIInfo->maxDrawableTableEntry      = (SAREA_MAX_DRAWABLES
1054					    < R128_MAX_DRAWABLES
1055					    ? SAREA_MAX_DRAWABLES
1056					    : R128_MAX_DRAWABLES);
1057
1058#ifdef NOT_DONE
1059    /* FIXME: Need to extend DRI protocol to pass this size back to
1060     * client for SAREA mapping that includes a device private record
1061     */
1062    pDRIInfo->SAREASize =
1063	((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */
1064    /* + shared memory device private rec */
1065#else
1066    /* For now the mapping works by using a fixed size defined
1067     * in the SAREA header
1068     */
1069    if (sizeof(XF86DRISAREARec)+sizeof(R128SAREAPriv)>SAREA_MAX) {
1070        xf86DrvMsg(pScreen->myNum, X_ERROR,
1071                   "[dri] Data does not fit in SAREA.  Disabling DRI.\n");
1072	return FALSE;
1073    }
1074    pDRIInfo->SAREASize = SAREA_MAX;
1075#endif
1076
1077    if (!(pR128DRI = (R128DRIPtr)calloc(sizeof(R128DRIRec),1))) {
1078	DRIDestroyInfoRec(info->pDRIInfo);
1079	info->pDRIInfo = NULL;
1080	return FALSE;
1081    }
1082    pDRIInfo->devPrivate     = pR128DRI;
1083    pDRIInfo->devPrivateSize = sizeof(R128DRIRec);
1084    pDRIInfo->contextSize    = sizeof(R128DRIContextRec);
1085
1086    pDRIInfo->CreateContext  = R128CreateContext;
1087    pDRIInfo->DestroyContext = R128DestroyContext;
1088    pDRIInfo->SwapContext    = R128DRISwapContext;
1089    pDRIInfo->InitBuffers    = R128DRIInitBuffers;
1090    pDRIInfo->MoveBuffers    = R128DRIMoveBuffers;
1091    pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
1092    pDRIInfo->TransitionTo2d = R128DRITransitionTo2d;
1093    pDRIInfo->TransitionTo3d = R128DRITransitionTo3d;
1094    pDRIInfo->TransitionSingleToMulti3D = R128DRITransitionSingleToMulti3d;
1095    pDRIInfo->TransitionMultiToSingle3D = R128DRITransitionMultiToSingle3d;
1096
1097    pDRIInfo->createDummyCtx     = TRUE;
1098    pDRIInfo->createDummyCtxPriv = FALSE;
1099
1100    if (!DRIScreenInit(pScreen, pDRIInfo, &info->drmFD)) {
1101	xf86DrvMsg(pScreen->myNum, X_ERROR,
1102                   "[dri] DRIScreenInit failed.  Disabling DRI.\n");
1103	free(pDRIInfo->devPrivate);
1104	pDRIInfo->devPrivate = NULL;
1105	DRIDestroyInfoRec(pDRIInfo);
1106	pDRIInfo = NULL;
1107	return FALSE;
1108    }
1109
1110    /* Check the DRM lib version.
1111       drmGetLibVersion was not supported in version 1.0, so check for
1112       symbol first to avoid possible crash or hang.
1113     */
1114    if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
1115        version = drmGetLibVersion(info->drmFD);
1116    }
1117    else {
1118        /* drmlib version 1.0.0 didn't have the drmGetLibVersion
1119           entry point.  Fake it by allocating a version record
1120           via drmGetVersion and changing it to version 1.0.0
1121         */
1122        version = drmGetVersion(info->drmFD);
1123        version->version_major      = 1;
1124        version->version_minor      = 0;
1125        version->version_patchlevel = 0;
1126    }
1127
1128    if (version) {
1129	if (version->version_major != 1 ||
1130	    version->version_minor < 1) {
1131            /* incompatible drm library version */
1132            xf86DrvMsg(pScreen->myNum, X_ERROR,
1133		"[dri] R128DRIScreenInit failed because of a version mismatch.\n"
1134		"[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n"
1135		"[dri] Disabling DRI.\n",
1136                version->version_major,
1137                version->version_minor,
1138                version->version_patchlevel);
1139            drmFreeVersion(version);
1140	    R128DRICloseScreen(pScreen);
1141            return FALSE;
1142	}
1143	drmFreeVersion(version);
1144    }
1145
1146    /* Check the r128 DRM version */
1147    version = drmGetVersion(info->drmFD);
1148    if (version) {
1149	if (version->version_major != 2 ||
1150	    version->version_minor < 2) {
1151	    /* incompatible drm version */
1152	    xf86DrvMsg(pScreen->myNum, X_ERROR,
1153		"[dri] R128DRIScreenInit failed because of a version mismatch.\n"
1154		"[dri] r128.o kernel module version is %d.%d.%d but version 2.2 or greater is needed.\n"
1155		"[dri] Disabling the DRI.\n",
1156		version->version_major,
1157		version->version_minor,
1158		version->version_patchlevel);
1159	    drmFreeVersion(version);
1160	    R128DRICloseScreen(pScreen);
1161	    return FALSE;
1162	}
1163	info->drmMinor = version->version_minor;
1164	drmFreeVersion(version);
1165    }
1166
1167				/* Initialize AGP */
1168    if (!info->IsPCI && !R128DRIAgpInit(info, pScreen)) {
1169	info->IsPCI = TRUE;
1170	xf86DrvMsg(pScreen->myNum, X_WARNING,
1171		   "[agp] AGP failed to initialize -- falling back to PCI mode.\n");
1172	xf86DrvMsg(pScreen->myNum, X_WARNING,
1173		   "[agp] Make sure you have the agpgart kernel module loaded.\n");
1174    }
1175
1176				/* Initialize PCIGART */
1177    if (info->IsPCI && !R128DRIPciInit(info, pScreen)) {
1178	R128DRICloseScreen(pScreen);
1179	return FALSE;
1180    }
1181
1182				/* DRIScreenInit doesn't add all the
1183				   common mappings.  Add additional
1184				   mappings here. */
1185    if (!R128DRIMapInit(info, pScreen)) {
1186	R128DRICloseScreen(pScreen);
1187	return FALSE;
1188    }
1189
1190				/* DRIScreenInit adds the frame buffer
1191				   map, but we need it as well */
1192    {
1193	void *scratch_ptr;
1194        int scratch_int;
1195
1196	DRIGetDeviceInfo(pScreen, &info->fbHandle,
1197                         &scratch_int, &scratch_int,
1198                         &scratch_int, &scratch_int,
1199                         &scratch_ptr);
1200    }
1201
1202				/* FIXME: When are these mappings unmapped? */
1203
1204    if (!R128InitVisualConfigs(pScreen)) {
1205	R128DRICloseScreen(pScreen);
1206	return FALSE;
1207    }
1208    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Visual configs initialized\n");
1209
1210    return TRUE;
1211}
1212
1213/* Finish initializing the device-dependent DRI state, and call
1214   DRIFinishScreenInit() to complete the device-independent DRI
1215   initialization. */
1216Bool R128DRIFinishScreenInit(ScreenPtr pScreen)
1217{
1218    ScrnInfoPtr      pScrn = xf86ScreenToScrn(pScreen);
1219    R128InfoPtr      info  = R128PTR(pScrn);
1220    R128SAREAPrivPtr pSAREAPriv;
1221    R128DRIPtr       pR128DRI;
1222
1223    info->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
1224    /* info->pDRIInfo->driverSwapMethod = DRI_SERVER_SWAP; */
1225
1226    /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit
1227       because *DRIKernelInit requires that the hardware lock is held by
1228       the X server, and the first time the hardware lock is grabbed is
1229       in DRIFinishScreenInit. */
1230    if (!DRIFinishScreenInit(pScreen)) {
1231	R128DRICloseScreen(pScreen);
1232	return FALSE;
1233    }
1234
1235    /* Initialize the kernel data structures */
1236    if (!R128DRIKernelInit(info, pScreen)) {
1237	R128DRICloseScreen(pScreen);
1238	return FALSE;
1239    }
1240
1241    /* Initialize the vertex buffers list */
1242    if (!R128DRIBufInit(info, pScreen)) {
1243	R128DRICloseScreen(pScreen);
1244	return FALSE;
1245    }
1246
1247    /* Initialize IRQ */
1248    R128DRIIrqInit(info, pScreen);
1249
1250    /* Initialize and start the CCE if required */
1251    R128DRICCEInit(pScrn);
1252
1253    pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
1254    memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
1255
1256    pR128DRI                    = (R128DRIPtr)info->pDRIInfo->devPrivate;
1257
1258    pR128DRI->deviceID          = info->Chipset;
1259    pR128DRI->width             = pScrn->virtualX;
1260    pR128DRI->height            = pScrn->virtualY;
1261    pR128DRI->depth             = pScrn->depth;
1262    pR128DRI->bpp               = pScrn->bitsPerPixel;
1263
1264    pR128DRI->IsPCI             = info->IsPCI;
1265    pR128DRI->AGPMode           = info->agpMode;
1266
1267    pR128DRI->frontOffset       = info->frontOffset;
1268    pR128DRI->frontPitch        = info->frontPitch;
1269    pR128DRI->backOffset        = info->backOffset;
1270    pR128DRI->backPitch         = info->backPitch;
1271    pR128DRI->depthOffset       = info->depthOffset;
1272    pR128DRI->depthPitch        = info->depthPitch;
1273    pR128DRI->spanOffset        = info->spanOffset;
1274    pR128DRI->textureOffset     = info->textureOffset;
1275    pR128DRI->textureSize       = info->textureSize;
1276    pR128DRI->log2TexGran       = info->log2TexGran;
1277
1278    pR128DRI->registerHandle    = info->registerHandle;
1279    pR128DRI->registerSize      = info->registerSize;
1280
1281    pR128DRI->agpTexHandle      = info->agpTexHandle;
1282    pR128DRI->agpTexMapSize     = info->agpTexMapSize;
1283    pR128DRI->log2AGPTexGran    = info->log2AGPTexGran;
1284    pR128DRI->agpTexOffset      = info->agpTexStart;
1285    pR128DRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
1286
1287    /* Have shadowfb run only while there is 3d active. */
1288    if (info->allowPageFlip && info->drmMinor >= 5 ) {
1289	ShadowFBInit( pScreen, R128DRIRefreshArea );
1290    } else if (info->allowPageFlip) {
1291	xf86DrvMsg(pScreen->myNum, X_WARNING,
1292		   "[dri] Kernel module version 2.5.0 or newer is required for pageflipping.\n");
1293       info->allowPageFlip = 0;
1294    }
1295
1296    return TRUE;
1297}
1298
1299/* The screen is being closed, so clean up any state and free any
1300   resources used by the DRI. */
1301void R128DRICloseScreen(ScreenPtr pScreen)
1302{
1303    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1304    R128InfoPtr info = R128PTR(pScrn);
1305    drmR128Init drmInfo;
1306
1307				/* Stop the CCE if it is still in use */
1308    if (info->directRenderingEnabled) {
1309	R128CCE_STOP(pScrn, info);
1310    }
1311
1312    if (info->irq) {
1313	drmCtlUninstHandler(info->drmFD);
1314	info->irq = 0;
1315	info->gen_int_cntl = 0;
1316    }
1317
1318				/* De-allocate vertex buffers */
1319    if (info->buffers) {
1320	drmUnmapBufs(info->buffers);
1321	info->buffers = NULL;
1322    }
1323
1324				/* De-allocate all kernel resources */
1325    memset(&drmInfo, 0, sizeof(drmR128Init));
1326    drmInfo.func = DRM_R128_CLEANUP_CCE;
1327    drmCommandWrite(info->drmFD, DRM_R128_INIT,
1328                    &drmInfo, sizeof(drmR128Init));
1329
1330				/* De-allocate all AGP resources */
1331    if (info->agpTex) {
1332	drmUnmap(info->agpTex, info->agpTexMapSize);
1333	info->agpTex = NULL;
1334    }
1335    if (info->buf) {
1336	drmUnmap(info->buf, info->bufMapSize);
1337	info->buf = NULL;
1338    }
1339    if (info->ringReadPtr) {
1340	drmUnmap(info->ringReadPtr, info->ringReadMapSize);
1341	info->ringReadPtr = NULL;
1342    }
1343    if (info->ring) {
1344	drmUnmap(info->ring, info->ringMapSize);
1345	info->ring = NULL;
1346    }
1347    if (info->agpMemHandle != DRM_AGP_NO_HANDLE) {
1348	drmAgpUnbind(info->drmFD, info->agpMemHandle);
1349	drmAgpFree(info->drmFD, info->agpMemHandle);
1350	info->agpMemHandle = DRM_AGP_NO_HANDLE;
1351	drmAgpRelease(info->drmFD);
1352    }
1353    if (info->pciMemHandle) {
1354	drmScatterGatherFree(info->drmFD, info->pciMemHandle);
1355	info->pciMemHandle = 0;
1356    }
1357
1358				/* De-allocate all DRI resources */
1359    DRICloseScreen(pScreen);
1360
1361				/* De-allocate all DRI data structures */
1362    if (info->pDRIInfo) {
1363	if (info->pDRIInfo->devPrivate) {
1364	    free(info->pDRIInfo->devPrivate);
1365	    info->pDRIInfo->devPrivate = NULL;
1366	}
1367	DRIDestroyInfoRec(info->pDRIInfo);
1368	info->pDRIInfo = NULL;
1369    }
1370    if (info->pVisualConfigs) {
1371	free(info->pVisualConfigs);
1372	info->pVisualConfigs = NULL;
1373    }
1374    if (info->pVisualConfigsPriv) {
1375	free(info->pVisualConfigsPriv);
1376	info->pVisualConfigsPriv = NULL;
1377    }
1378}
1379
1380/* Use callbacks from dri.c to support pageflipping mode for a single
1381 * 3d context without need for any specific full-screen extension.
1382 */
1383
1384/* Use the shadowfb module to maintain a list of dirty rectangles.
1385 * These are blitted to the back buffer to keep both buffers clean
1386 * during page-flipping when the 3d application isn't fullscreen.
1387 *
1388 * Unlike most use of the shadowfb code, both buffers are in video memory.
1389 *
1390 * An alternative to this would be to organize for all on-screen drawing
1391 * operations to be duplicated for the two buffers.  That might be
1392 * faster, but seems like a lot more work...
1393 */
1394
1395
1396static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
1397{
1398    R128InfoPtr         info       = R128PTR(pScrn);
1399    int                 i;
1400    R128SAREAPrivPtr    pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen);
1401    PixmapPtr		pPix	   = pScrn->pScreen->GetScreenPixmap(pScrn->pScreen);
1402
1403    /* Don't want to do this when no 3d is active and pages are
1404     * right-way-round
1405     */
1406    if (!pSAREAPriv->pfAllowPageFlip && pSAREAPriv->pfCurrentPage == 0)
1407	return;
1408
1409#ifdef HAVE_XAA_H
1410    if (!info->useEXA) {
1411	(*info->accel->SetupForScreenToScreenCopy)(pScrn,
1412					       1, 1, GXcopy,
1413					       (CARD32)(-1), -1);
1414    }
1415#endif
1416#ifdef USE_EXA
1417    if (info->useEXA) {
1418        CARD32 src_pitch_offset, dst_pitch_offset, datatype;
1419
1420	R128GetPixmapOffsetPitch(pPix, &src_pitch_offset);
1421	dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5);
1422	R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype);
1423	info->xdir = info->ydir = 1;
1424
1425	R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0);
1426    }
1427#endif
1428
1429    for (i = 0 ; i < num ; i++, pbox++) {
1430	int xa = max(pbox->x1, 0), xb = min(pbox->x2, pScrn->virtualX-1);
1431	int ya = max(pbox->y1, 0), yb = min(pbox->y2, pScrn->virtualY-1);
1432
1433	if (xa <= xb && ya <= yb) {
1434#ifdef HAVE_XAA_H
1435	    if (!info->useEXA) {
1436	        (*info->accel->SubsequentScreenToScreenCopy)(pScrn, xa, ya,
1437							 xa + info->backX,
1438							 ya + info->backY,
1439							 xb - xa + 1,
1440							 yb - ya + 1);
1441	    }
1442#endif
1443#ifdef USE_EXA
1444	    if (info->useEXA) {
1445		(*info->ExaDriver->Copy)(pPix, xa, ya, xa, ya, xb - xa + 1, yb - ya + 1);
1446	    }
1447#endif
1448	}
1449    }
1450}
1451
1452static void R128EnablePageFlip(ScreenPtr pScreen)
1453{
1454    ScrnInfoPtr         pScrn      = xf86ScreenToScrn(pScreen);
1455    R128InfoPtr         info       = R128PTR(pScrn);
1456    R128SAREAPrivPtr    pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1457    PixmapPtr		pPix	   = pScreen->GetScreenPixmap(pScreen);
1458
1459    if (info->allowPageFlip) {
1460	/* Duplicate the frontbuffer to the backbuffer */
1461#ifdef HAVE_XAA_H
1462	if (!info->useEXA) {
1463	    (*info->accel->SetupForScreenToScreenCopy)(pScrn,
1464						   1, 1, GXcopy,
1465						   (CARD32)(-1), -1);
1466
1467	    (*info->accel->SubsequentScreenToScreenCopy)(pScrn,
1468						     0,
1469						     0,
1470						     info->backX,
1471						     info->backY,
1472						     pScrn->virtualX,
1473						     pScrn->virtualY);
1474	}
1475#endif
1476#ifdef USE_EXA
1477	if (info->useEXA) {
1478	    CARD32 src_pitch_offset, dst_pitch_offset, datatype;
1479
1480	    R128GetPixmapOffsetPitch(pPix, &src_pitch_offset);
1481	    dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5);
1482	    R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype);
1483	    info->xdir = info->ydir = 1;
1484
1485            R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0);
1486
1487	    (*info->ExaDriver->Copy)(pPix, 0, 0, 0, 0, pScrn->virtualX, pScrn->virtualY);
1488	}
1489#endif
1490
1491	pSAREAPriv->pfAllowPageFlip = 1;
1492    }
1493}
1494
1495static void R128DisablePageFlip(ScreenPtr pScreen)
1496{
1497    /* Tell the clients not to pageflip.  How?
1498     *   -- Field in sarea, plus bumping the window counters.
1499     *   -- DRM needs to cope with Front-to-Back swapbuffers.
1500     */
1501    R128SAREAPrivPtr  pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1502
1503    pSAREAPriv->pfAllowPageFlip = 0;
1504}
1505
1506static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen)
1507{
1508    R128DisablePageFlip(pScreen);
1509}
1510
1511static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen)
1512{
1513    /* Let the remaining 3d app start page flipping again */
1514    R128EnablePageFlip(pScreen);
1515}
1516
1517static void R128DRITransitionTo3d(ScreenPtr pScreen)
1518{
1519    ScrnInfoPtr    pScrn = xf86ScreenToScrn(pScreen);
1520    R128InfoPtr    info  = R128PTR(pScrn);
1521
1522    R128EnablePageFlip(pScreen);
1523
1524    info->have3DWindows = 1;
1525
1526    if (info->cursor_start)
1527        xf86ForceHWCursor(pScreen, TRUE);
1528}
1529
1530static void R128DRITransitionTo2d(ScreenPtr pScreen)
1531{
1532    ScrnInfoPtr         pScrn      = xf86ScreenToScrn(pScreen);
1533    R128InfoPtr         info       = R128PTR(pScrn);
1534    R128SAREAPrivPtr    pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1535
1536    /* Try flipping back to the front page if necessary */
1537    if (pSAREAPriv->pfCurrentPage == 1)
1538	drmCommandNone(info->drmFD, DRM_R128_FLIP);
1539
1540    /* Shut down shadowing if we've made it back to the front page */
1541    if (pSAREAPriv->pfCurrentPage == 0) {
1542	R128DisablePageFlip(pScreen);
1543    } else {
1544	xf86DrvMsg(pScreen->myNum, X_WARNING,
1545		   "[dri] R128DRITransitionTo2d: "
1546		   "kernel failed to unflip buffers.\n");
1547    }
1548
1549    info->have3DWindows = 0;
1550
1551    if (info->cursor_start)
1552        xf86ForceHWCursor(pScreen, FALSE);
1553}
1554