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