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