mga_dri.c revision 81f79626
1/*
2 * Copyright 2000 VA Linux Systems Inc., Fremont, California.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES
20 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Keith Whitwell <keith@tungstengraphics.com>
26 *    Gareth Hughes <gareth@valinux.com>
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include "xf86.h"
34#include "xf86_OSproc.h"
35
36#include "xf86Pci.h"
37
38#include "miline.h"
39
40#include <errno.h>
41
42#include <inttypes.h>
43#include "mga_reg.h"
44#include "mga.h"
45#include "mga_macros.h"
46#include "mga_dri.h"
47#include "mga_sarea.h"
48#include "mga_drm.h"
49
50#define _XF86DRI_SERVER_
51#include "sarea.h"
52
53#include "mga_reg.h"
54#include "mga.h"
55#include "mga_macros.h"
56#include "mga_dri.h"
57
58#define  DRM_MGA_IDLE_RETRY          2048
59
60static char MGAKernelDriverName[] = "mga";
61static char MGAClientDriverName[] = "mga";
62
63static Bool MGACreateContext( ScreenPtr pScreen, VisualPtr visual,
64			      drm_context_t hwContext, void *pVisualConfigPriv,
65			      DRIContextType contextStore )
66{
67   /* Nothing yet */
68   return TRUE;
69}
70
71static void MGADestroyContext( ScreenPtr pScreen, drm_context_t hwContext,
72			       DRIContextType contextStore )
73{
74   /* Nothing yet */
75}
76
77
78/* Quiescence, locking
79 */
80#define MGA_TIMEOUT		2048
81
82static void MGAWaitForIdleDMA( ScrnInfoPtr pScrn )
83{
84   MGAPtr pMga = MGAPTR(pScrn);
85   drm_lock_t lock;
86   int ret;
87   int i = 0;
88
89   memset( &lock, 0, sizeof(drm_lock_t) );
90
91   for (;;) {
92      do {
93         /* first ask for quiescent and flush */
94         lock.flags = DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH;
95         do {
96	    ret = drmCommandWrite( pMga->drmFD, DRM_MGA_FLUSH,
97                                   &lock, sizeof( drm_lock_t ) );
98         } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY );
99
100         /* if it's still busy just try quiescent */
101         if ( ret == -EBUSY ) {
102            lock.flags = DRM_LOCK_QUIESCENT;
103            do {
104	       ret = drmCommandWrite( pMga->drmFD, DRM_MGA_FLUSH,
105                                      &lock, sizeof( drm_lock_t ) );
106            } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY );
107         }
108      } while ( ( ret == -EBUSY ) && ( i++ < MGA_TIMEOUT ) );
109
110      if ( ret == 0 )
111	 return;
112
113      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
114		  "[dri] Idle timed out, resetting engine...\n" );
115
116      drmCommandNone( pMga->drmFD, DRM_MGA_RESET );
117   }
118}
119
120
121void MGAGetQuiescence( ScrnInfoPtr pScrn )
122{
123   MGAPtr pMga = MGAPTR(pScrn);
124#ifdef USE_XAA
125   MGAFBLayout *pLayout = &pMga->CurrentLayout;
126#endif /* USE_XAA */
127
128   pMga->haveQuiescense = 1;
129
130   if ( pMga->directRenderingEnabled ) {
131      MGAWaitForIdleDMA( pScrn );
132
133        /* FIXME what about EXA? */
134#ifdef USE_XAA
135        if (!pMga->Exa && pMga->AccelInfoRec) {
136      WAITFIFO( 11 );
137      OUTREG( MGAREG_MACCESS, pMga->MAccess );
138      OUTREG( MGAREG_PITCH, pLayout->displayWidth );
139
140      pMga->PlaneMask = ~0;
141      OUTREG( MGAREG_PLNWT, pMga->PlaneMask );
142
143      pMga->BgColor = 0;
144      pMga->FgColor = 0;
145      OUTREG( MGAREG_BCOL, pMga->BgColor );
146      OUTREG( MGAREG_FCOL, pMga->FgColor );
147      OUTREG( MGAREG_SRCORG, pMga->realSrcOrg );
148
149      pMga->SrcOrg = 0;
150      OUTREG( MGAREG_DSTORG, pMga->DstOrg );
151      OUTREG( MGAREG_OPMODE, MGAOPM_DMA_BLIT );
152      OUTREG( MGAREG_CXBNDRY, 0xFFFF0000 ); /* (maxX << 16) | minX */
153      OUTREG( MGAREG_YTOP, 0x00000000 );    /* minPixelPointer */
154      OUTREG( MGAREG_YBOT, 0x007FFFFF );    /* maxPixelPointer */
155
156            pMga->AccelFlags &= ~CLIPPER_ON;
157        }
158#endif
159   }
160}
161
162void MGAGetQuiescenceShared( ScrnInfoPtr pScrn )
163{
164   MGAPtr pMga = MGAPTR(pScrn);
165   MGAEntPtr pMGAEnt = pMga->entityPrivate;
166   MGAPtr pMGA2 = MGAPTR(pMGAEnt->pScrn_2);
167
168   pMga = MGAPTR(pMGAEnt->pScrn_1);
169   pMga->haveQuiescense = 1;
170   pMGA2->haveQuiescense = 1;
171
172   if ( pMGAEnt->directRenderingEnabled ) {
173      MGAWaitForIdleDMA( pMGAEnt->pScrn_1 );
174
175        /* FIXME what about EXA? */
176#ifdef USE_XAA
177        if (!pMga->Exa && pMga->AccelInfoRec)
178            pMga->RestoreAccelState( pScrn );
179#endif
180      xf86SetLastScrnFlag( pScrn->entityList[0], pScrn->scrnIndex );
181   }
182}
183
184static void MGASwapContext( ScreenPtr pScreen )
185{
186   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
187   MGAPtr pMga = MGAPTR(pScrn);
188
189   /* Arrange for dma_quiescence and xaa sync to be called as
190    * appropriate.
191    */
192   pMga->haveQuiescense = 0;
193
194   MGA_MARK_SYNC(pMga, pScrn);
195}
196
197static void MGASwapContextShared( ScreenPtr pScreen )
198{
199   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
200   MGAPtr pMga = MGAPTR(pScrn);
201   MGAEntPtr pMGAEnt = pMga->entityPrivate;
202   MGAPtr pMGA2 = MGAPTR(pMGAEnt->pScrn_2);
203
204   pMga = MGAPTR(pMGAEnt->pScrn_1);
205
206   pMga->haveQuiescense = pMGA2->haveQuiescense = 0;
207
208   MGA_MARK_SYNC(pMga, pScrn);
209   MGA_MARK_SYNC(pMGA2, pMGAEnt->pScrn_2);
210}
211
212/* FIXME: This comment is out of date, since we aren't overriding
213 * Block/Wakeuphandler anymore.
214 *
215 *
216 * This is really only called from validate/postvalidate as we
217 * override the dri lock/unlock.  Want to remove validate/postvalidate
218 * processing, but need to remove all client-side use of drawable lock
219 * first (otherwise there is noone recover when a client dies holding
220 * the drawable lock).
221 *
222 * What does this mean?
223 *
224 *   - The above code gets executed every time a
225 *     window changes shape or the focus changes, which isn't really
226 *     optimal.
227 *   - The X server therefore believes it needs to do an XAA sync
228 *     *and* a dma quiescense ioctl each time that happens.
229 *
230 * We don't wrap wakeuphandler any longer, so at least we can say that
231 * this doesn't happen *every time the mouse moves*...
232 */
233static void
234MGADRISwapContext( ScreenPtr pScreen, DRISyncType syncType,
235		   DRIContextType oldContextType, void *oldContext,
236		   DRIContextType newContextType, void *newContext )
237{
238   if ( syncType == DRI_3D_SYNC &&
239	oldContextType == DRI_2D_CONTEXT &&
240	newContextType == DRI_2D_CONTEXT )
241   {
242      MGASwapContext( pScreen );
243   }
244}
245
246static void
247MGADRISwapContextShared( ScreenPtr pScreen, DRISyncType syncType,
248			  DRIContextType oldContextType, void *oldContext,
249			  DRIContextType newContextType, void *newContext )
250{
251   if ( syncType == DRI_3D_SYNC &&
252	oldContextType == DRI_2D_CONTEXT &&
253	newContextType == DRI_2D_CONTEXT )
254   {
255      MGASwapContextShared( pScreen );
256   }
257}
258
259void MGASelectBuffer( ScrnInfoPtr pScrn, int which )
260{
261   MGAPtr pMga = MGAPTR(pScrn);
262   MGADRIPtr pMGADRI = (MGADRIPtr)pMga->pDRIInfo->devPrivate;
263
264   switch ( which ) {
265   case MGA_BACK:
266      OUTREG( MGAREG_DSTORG, pMGADRI->backOffset );
267      OUTREG( MGAREG_SRCORG, pMGADRI->backOffset );
268      break;
269   case MGA_DEPTH:
270      OUTREG( MGAREG_DSTORG, pMGADRI->depthOffset );
271      OUTREG( MGAREG_SRCORG, pMGADRI->depthOffset );
272      break;
273   default:
274   case MGA_FRONT:
275      OUTREG( MGAREG_DSTORG, pMGADRI->frontOffset );
276      OUTREG( MGAREG_SRCORG, pMGADRI->frontOffset );
277      break;
278   }
279}
280
281static unsigned int mylog2( unsigned int n )
282{
283   unsigned int log2 = 1;
284   while ( n > 1 ) n >>= 1, log2++;
285   return log2;
286}
287
288/**
289 * Initialize DMA and secondary texture memory
290 *
291 * \todo
292 * The sizes used for the primary DMA buffer and the bin size and count for
293 * the secondary DMA buffers should be configurable from the xorg.conf.
294 *
295 * \todo
296 * This routine should use \c mga_bios_values::host_interface to limit the
297 * AGP mode.  It the card is PCI, \c MGARec::agpSize should be forced to 0.
298 */
299static Bool MGADRIBootstrapDMA(ScreenPtr pScreen)
300{
301    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
302    MGAPtr pMga = MGAPTR(pScrn);
303    MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
304    int ret;
305    int requested_agp_mode;
306    int count;
307
308
309    if(pMga->agpSize < 12)pMga->agpSize = 12;
310    if(pMga->agpSize > 64)pMga->agpSize = 64; /* cap */
311
312
313    requested_agp_mode = 0;
314    switch ( pMga->agpMode ) {
315    case 4:
316	requested_agp_mode |= MGA_AGP_4X_MODE;
317    case 2:
318	requested_agp_mode |= MGA_AGP_2X_MODE;
319    case 1:
320    default:
321	requested_agp_mode |= MGA_AGP_1X_MODE;
322    }
323
324
325    if ( (pMGADRIServer->drm_version_minor >= 2) && !pMga->useOldDmaInit ) {
326	drm_mga_dma_bootstrap_t dma_bs;
327
328
329	(void) memset( & dma_bs, 0, sizeof( dma_bs ) );
330	dma_bs.primary_size = 1024 * 1024;
331	dma_bs.secondary_bin_count = MGA_NUM_BUFFERS;
332	dma_bs.secondary_bin_size = MGA_BUFFER_SIZE;
333	dma_bs.agp_size = pMga->agpSize;
334	dma_bs.agp_mode = (pMga->forcePciDma) ? 0 : requested_agp_mode;
335
336	ret = drmCommandWriteRead( pMga->drmFD, DRM_MGA_DMA_BOOTSTRAP,
337				   & dma_bs, sizeof( dma_bs ) );
338	if ( ret ) {
339	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[drm] Could not boot-strap DMA (%d)\n", ret );
340	    return FALSE;
341	}
342
343	pMga->agpMode = dma_bs.agp_mode;
344	pMGADRIServer->agp.size = dma_bs.agp_size;
345
346	pMGADRIServer->agpTextures.handle = dma_bs.texture_handle;
347	pMGADRIServer->agpTextures.size   = dma_bs.texture_size;
348    }
349    else {
350	unsigned long mode;
351	unsigned int vendor, device;
352	int i;
353
354
355	if ( pMga->forcePciDma ) {
356	    const char * const msg = (pMGADRIServer->drm_version_minor < 2)
357	      ? "DRM version is too old (3.2 or later required)"
358	      : "old DMA init path was requested";
359
360	    xf86DrvMsg( pScreen->myNum, X_WARNING,
361			"[agp] Cannot force PCI DMA because %s\n", msg );
362	}
363
364	if ( drmAgpAcquire( pMga->drmFD ) < 0 ) {
365	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] AGP not available\n" );
366	    return FALSE;
367	}
368
369	mode   = drmAgpGetMode( pMga->drmFD );        /* Default mode */
370	vendor = drmAgpVendorId( pMga->drmFD );
371	device = drmAgpDeviceId( pMga->drmFD );
372
373	mode = (mode & ~MGA_AGP_MODE_MASK) | requested_agp_mode;
374
375	xf86DrvMsg( pScreen->myNum, X_INFO,
376		    "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n",
377		    mode, vendor, device,
378		    VENDOR_ID(pMga->PciInfo),
379		    DEVICE_ID(pMga->PciInfo));
380
381	if ( drmAgpEnable( pMga->drmFD, mode ) < 0 ) {
382	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n" );
383	    drmAgpRelease( pMga->drmFD );
384	    return FALSE;
385	}
386
387	if ( pMga->Chipset == PCI_CHIP_MGAG200 ) {
388	    switch ( pMga->agpMode ) {
389	    case 2:
390		xf86DrvMsg( pScreen->myNum, X_INFO,
391			    "[drm] Enabling AGP 2x PLL encoding\n" );
392		OUTREG( MGAREG_AGP_PLL, MGA_AGP2XPLL_ENABLE );
393		break;
394
395	    case 1:
396	    default:
397		xf86DrvMsg( pScreen->myNum, X_INFO,
398			    "[drm] Disabling AGP 2x PLL encoding\n" );
399		OUTREG( MGAREG_AGP_PLL, MGA_AGP2XPLL_DISABLE );
400		pMga->agpMode = 1;
401		break;
402	    }
403	}
404
405	pMGADRIServer->agp.size = pMga->agpSize * 1024 * 1024;
406
407	pMGADRIServer->warp.offset = 0;
408	pMGADRIServer->warp.size = MGA_WARP_UCODE_SIZE;
409
410	pMGADRIServer->primary.offset = (pMGADRIServer->warp.offset +
411					 pMGADRIServer->warp.size);
412	pMGADRIServer->primary.size = 1024 * 1024;
413
414	pMGADRIServer->buffers.offset = (pMGADRIServer->primary.offset +
415					 pMGADRIServer->primary.size);
416	pMGADRIServer->buffers.size = MGA_NUM_BUFFERS * MGA_BUFFER_SIZE;
417
418
419	pMGADRIServer->agpTextures.offset = (pMGADRIServer->buffers.offset +
420					     pMGADRIServer->buffers.size);
421
422	pMGADRIServer->agpTextures.size = (pMGADRIServer->agp.size -
423					   pMGADRIServer->agpTextures.offset);
424
425	ret = drmAgpAlloc( pMga->drmFD, pMGADRIServer->agp.size,
426			   0, NULL, &pMGADRIServer->agp.handle );
427	if ( ret < 0 ) {
428	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret );
429	    drmAgpRelease( pMga->drmFD );
430	    return FALSE;
431	}
432	xf86DrvMsg( pScreen->myNum, X_INFO,
433 		    "[agp] %d kB allocated with handle 0x%08x\n",
434		    pMGADRIServer->agp.size/1024,
435		    (unsigned int) pMGADRIServer->agp.handle );
436
437	if ( drmAgpBind( pMga->drmFD, pMGADRIServer->agp.handle, 0 ) < 0 ) {
438	    xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not bind memory\n" );
439	    drmAgpFree( pMga->drmFD, pMGADRIServer->agp.handle );
440	    drmAgpRelease( pMga->drmFD );
441	    return FALSE;
442	}
443
444	/* WARP microcode space
445	 */
446	if ( drmAddMap( pMga->drmFD,
447			pMGADRIServer->warp.offset,
448			pMGADRIServer->warp.size,
449			DRM_AGP, DRM_READ_ONLY,
450			&pMGADRIServer->warp.handle ) < 0 ) {
451	    xf86DrvMsg( pScreen->myNum, X_ERROR,
452			"[agp] Could not add WARP microcode mapping\n" );
453	    return FALSE;
454	}
455	xf86DrvMsg( pScreen->myNum, X_INFO,
456 		    "[agp] WARP microcode handle = 0x%08x\n",
457		    (unsigned int) pMGADRIServer->warp.handle );
458
459	/* Primary DMA space
460	 */
461	if ( drmAddMap( pMga->drmFD,
462			pMGADRIServer->primary.offset,
463			pMGADRIServer->primary.size,
464			DRM_AGP, DRM_READ_ONLY,
465			&pMGADRIServer->primary.handle ) < 0 ) {
466	    xf86DrvMsg( pScreen->myNum, X_ERROR,
467			"[agp] Could not add primary DMA mapping\n" );
468	    return FALSE;
469	}
470	xf86DrvMsg( pScreen->myNum, X_INFO,
471 		    "[agp] Primary DMA handle = 0x%08x\n",
472		    (unsigned int) pMGADRIServer->primary.handle );
473
474	/* DMA buffers
475	 */
476	if ( drmAddMap( pMga->drmFD,
477			pMGADRIServer->buffers.offset,
478			pMGADRIServer->buffers.size,
479			DRM_AGP, 0,
480			&pMGADRIServer->buffers.handle ) < 0 ) {
481	    xf86DrvMsg( pScreen->myNum, X_ERROR,
482			"[agp] Could not add DMA buffers mapping\n" );
483	    return FALSE;
484	}
485	xf86DrvMsg( pScreen->myNum, X_INFO,
486 		    "[agp] DMA buffers handle = 0x%08x\n",
487		    (unsigned int) pMGADRIServer->buffers.handle );
488
489	count = drmAddBufs( pMga->drmFD,
490			    MGA_NUM_BUFFERS, MGA_BUFFER_SIZE,
491			    DRM_AGP_BUFFER, pMGADRIServer->buffers.offset );
492	if ( count <= 0 ) {
493	    xf86DrvMsg( pScrn->scrnIndex, X_INFO,
494			"[drm] failure adding %d %d byte DMA buffers\n",
495			MGA_NUM_BUFFERS, MGA_BUFFER_SIZE );
496	    return FALSE;
497	}
498	xf86DrvMsg( pScreen->myNum, X_INFO,
499		    "[drm] Added %d %d byte DMA buffers\n",
500		    count, MGA_BUFFER_SIZE );
501
502	i = mylog2(pMGADRIServer->agpTextures.size / MGA_NR_TEX_REGIONS);
503	if(i < MGA_LOG_MIN_TEX_REGION_SIZE)
504	  i = MGA_LOG_MIN_TEX_REGION_SIZE;
505	pMGADRIServer->agpTextures.size = (pMGADRIServer->agpTextures.size >> i) << i;
506
507	if ( drmAddMap( pMga->drmFD,
508			pMGADRIServer->agpTextures.offset,
509			pMGADRIServer->agpTextures.size,
510			DRM_AGP, 0,
511			&pMGADRIServer->agpTextures.handle ) < 0 ) {
512	    xf86DrvMsg( pScreen->myNum, X_ERROR,
513			"[agp] Could not add agpTexture mapping\n" );
514	    return FALSE;
515	}
516
517	xf86DrvMsg( pScreen->myNum, X_INFO,
518 		    "[agp] agpTexture handle = 0x%08x\n",
519		    (unsigned int) pMGADRIServer->agpTextures.handle );
520	xf86DrvMsg( pScreen->myNum, X_INFO,
521		    "[agp] agpTexture size: %d kb\n", pMGADRIServer->agpTextures.size/1024 );
522
523	pMGADRIServer->registers.size = MGAIOMAPSIZE;
524
525	if ( drmAddMap( pMga->drmFD,
526			(drm_handle_t) MGA_IO_ADDRESS(pMga),
527			pMGADRIServer->registers.size,
528			DRM_REGISTERS, DRM_READ_ONLY,
529			&pMGADRIServer->registers.handle ) < 0 ) {
530	    xf86DrvMsg( pScreen->myNum, X_ERROR,
531			"[drm] Could not add MMIO registers mapping\n" );
532	    return FALSE;
533	}
534	xf86DrvMsg( pScreen->myNum, X_INFO,
535 		    "[drm] Registers handle = 0x%08x\n",
536		    (unsigned int) pMGADRIServer->registers.handle );
537
538	pMGADRIServer->status.size = SAREA_MAX;
539
540	if ( drmAddMap( pMga->drmFD, 0, pMGADRIServer->status.size,
541			DRM_SHM, DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL,
542			&pMGADRIServer->status.handle ) < 0 ) {
543	    xf86DrvMsg( pScreen->myNum, X_ERROR,
544			"[drm] Could not add status page mapping\n" );
545	    return FALSE;
546	}
547	xf86DrvMsg( pScreen->myNum, X_INFO,
548 		    "[drm] Status handle = 0x%08x\n",
549		    (unsigned int) pMGADRIServer->status.handle );
550    }
551
552    return TRUE;
553}
554
555static Bool MGADRIKernelInit( ScreenPtr pScreen )
556{
557   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
558   MGAPtr pMga = MGAPTR(pScrn);
559   MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
560   drm_mga_init_t init;
561   int ret;
562
563
564   if (!pMga->chip_attribs->dri_capable) {
565       return FALSE;
566   }
567
568   memset( &init, 0, sizeof(drm_mga_init_t) );
569
570   init.func = MGA_INIT_DMA;
571   init.sarea_priv_offset = sizeof(XF86DRISAREARec);
572   init.chipset = pMga->chip_attribs->dri_chipset;
573   init.sgram = !pMga->HasSDRAM;
574
575   init.maccess = pMga->MAccess;
576
577   init.fb_cpp		= pScrn->bitsPerPixel / 8;
578   init.front_offset	= pMGADRIServer->frontOffset;
579   init.front_pitch	= pMGADRIServer->frontPitch / init.fb_cpp;
580   init.back_offset	= pMGADRIServer->backOffset;
581   init.back_pitch	= pMGADRIServer->backPitch / init.fb_cpp;
582
583   init.depth_cpp	= pScrn->bitsPerPixel / 8;
584   init.depth_offset	= pMGADRIServer->depthOffset;
585   init.depth_pitch	= pMGADRIServer->depthPitch / init.depth_cpp;
586
587   init.texture_offset[0] = pMGADRIServer->textureOffset;
588   init.texture_size[0] = pMGADRIServer->textureSize;
589
590   init.fb_offset = pMGADRIServer->fb.handle;
591   init.mmio_offset = pMGADRIServer->registers.handle;
592   init.status_offset = pMGADRIServer->status.handle;
593
594   init.warp_offset = pMGADRIServer->warp.handle;
595   init.primary_offset = pMGADRIServer->primary.handle;
596   init.buffers_offset = pMGADRIServer->buffers.handle;
597
598   init.texture_offset[1] = pMGADRIServer->agpTextures.handle;
599   init.texture_size[1] = pMGADRIServer->agpTextures.size;
600
601   ret = drmCommandWrite( pMga->drmFD, DRM_MGA_INIT, &init, sizeof(drm_mga_init_t));
602   if ( ret < 0 ) {
603      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
604		  "[drm] Failed to initialize DMA! (%d)\n", ret );
605      return FALSE;
606   }
607
608
609   return TRUE;
610}
611
612/* FIXME: This function uses the DRM to get the IRQ, but the pci_device
613 * FIXME: structure (PciInfo) already has that information.
614 */
615static void MGADRIIrqInit(MGAPtr pMga, ScreenPtr pScreen)
616{
617   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
618
619   if (!pMga->irq) {
620      pMga->irq = drmGetInterruptFromBusID(pMga->drmFD,
621#ifdef XSERVER_LIBPCIACCESS
622					   ((pMga->PciInfo->domain << 8) |
623					    pMga->PciInfo->bus),
624					   pMga->PciInfo->dev,
625					   pMga->PciInfo->func
626#else
627	 ((pciConfigPtr)pMga->PciInfo->thisCard)->busnum,
628	 ((pciConfigPtr)pMga->PciInfo->thisCard)->devnum,
629	 ((pciConfigPtr)pMga->PciInfo->thisCard)->funcnum
630#endif
631					   );
632
633      if((drmCtlInstHandler(pMga->drmFD, pMga->irq)) != 0) {
634	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
635		    "[drm] failure adding irq handler, "
636		    "there is a device already using that irq\n"
637		    "[drm] falling back to irq-free operation\n");
638	 pMga->irq = 0;
639      } else {
640          pMga->reg_ien = INREG( MGAREG_IEN );
641      }
642   }
643
644   if (pMga->irq)
645      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
646		 "[drm] dma control initialized, using IRQ %d\n",
647		 pMga->irq);
648}
649
650static Bool MGADRIBuffersInit( ScreenPtr pScreen )
651{
652   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
653   MGAPtr pMga = MGAPTR(pScrn);
654   MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
655
656
657   pMGADRIServer->drmBuffers = drmMapBufs( pMga->drmFD );
658   if ( !pMGADRIServer->drmBuffers ) {
659	xf86DrvMsg( pScreen->myNum, X_ERROR,
660		    "[drm] Failed to map DMA buffers list\n" );
661	return FALSE;
662    }
663    xf86DrvMsg( pScreen->myNum, X_INFO,
664		"[drm] Mapped %d DMA buffers\n",
665		pMGADRIServer->drmBuffers->count );
666
667    return TRUE;
668}
669
670#ifdef USE_XAA
671static void MGADRIInitBuffersXAA(WindowPtr pWin, RegionPtr prgn,
672                                 CARD32 index)
673{
674    ScreenPtr pScreen = pWin->drawable.pScreen;
675    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
676    MGAPtr pMga = MGAPTR(pScrn);
677    BoxPtr pbox = REGION_RECTS(prgn);
678    int nbox  = REGION_NUM_RECTS(prgn);
679    XAAInfoRecPtr xaa = pMga->AccelInfoRec;
680
681    CHECK_DMA_QUIESCENT(MGAPTR(pScrn), pScrn);
682
683    xaa->SetupForSolidFill(pScrn, 0, GXcopy, -1);
684
685    while (nbox--) {
686        MGASelectBuffer(pScrn, MGA_BACK);
687        xaa->SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1,
688                                     pbox->x2-pbox->x1, pbox->y2-pbox->y1);
689        MGASelectBuffer(pScrn, MGA_DEPTH);
690        xaa->SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1,
691                                     pbox->x2-pbox->x1, pbox->y2-pbox->y1);
692        pbox++;
693    }
694
695    MGASelectBuffer(pScrn, MGA_FRONT);
696
697    pMga->AccelInfoRec->NeedToSync = TRUE;
698}
699#endif
700
701static void MGADRIInitBuffersEXA(WindowPtr pWin, RegionPtr prgn,
702                                 CARD32 index)
703{
704    /* FIXME */
705}
706
707#ifdef USE_XAA
708/*
709  This routine is a modified form of XAADoBitBlt with the calls to
710  ScreenToScreenBitBlt built in. My routine has the prgnSrc as source
711  instead of destination. My origin is upside down so the ydir cases
712  are reversed.
713*/
714static void MGADRIMoveBuffersXAA(WindowPtr pParent, DDXPointRec ptOldOrg,
715                                 RegionPtr prgnSrc, CARD32 index)
716{
717    ScreenPtr pScreen = pParent->drawable.pScreen;
718    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
719    MGAPtr pMga = MGAPTR(pScrn);
720    int nbox;
721    BoxPtr pbox, pboxTmp, pboxNext, pboxBase, pboxNew1, pboxNew2;
722    DDXPointPtr pptTmp, pptNew1, pptNew2;
723    int xdir, ydir;
724    int dx, dy;
725    DDXPointPtr pptSrc;
726    int screenwidth = pScrn->virtualX;
727    int screenheight = pScrn->virtualY;
728    XAAInfoRecPtr xaa = pMga->AccelInfoRec;
729
730    CHECK_DMA_QUIESCENT(pMga, pScrn);
731
732    pbox = REGION_RECTS(prgnSrc);
733    nbox = REGION_NUM_RECTS(prgnSrc);
734    pboxNew1 = 0;
735    pptNew1 = 0;
736    pboxNew2 = 0;
737    pptNew2 = 0;
738    pptSrc = &ptOldOrg;
739
740    dx = pParent->drawable.x - ptOldOrg.x;
741    dy = pParent->drawable.y - ptOldOrg.y;
742
743    /* If the copy will overlap in Y, reverse the order */
744    if (dy>0) {
745        ydir = -1;
746
747        if (nbox>1) {
748	    /* Keep ordering in each band, reverse order of bands */
749	    pboxNew1 = (BoxPtr)malloc(sizeof(BoxRec)*nbox);
750	    if (!pboxNew1) return;
751	    pptNew1 = (DDXPointPtr)malloc(sizeof(DDXPointRec)*nbox);
752	    if (!pptNew1) {
753	        free(pboxNew1);
754	        return;
755	    }
756	    pboxBase = pboxNext = pbox+nbox-1;
757	    while (pboxBase >= pbox) {
758	        while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1))
759		  pboxNext--;
760	        pboxTmp = pboxNext+1;
761	        pptTmp = pptSrc + (pboxTmp - pbox);
762	        while (pboxTmp <= pboxBase) {
763		    *pboxNew1++ = *pboxTmp++;
764		    *pptNew1++ = *pptTmp++;
765		}
766	        pboxBase = pboxNext;
767	    }
768	    pboxNew1 -= nbox;
769	    pbox = pboxNew1;
770	    pptNew1 -= nbox;
771	    pptSrc = pptNew1;
772	}
773    } else {
774        /* No changes required */
775        ydir = 1;
776    }
777
778    /* If the regions will overlap in X, reverse the order */
779    if (dx>0) {
780        xdir = -1;
781
782        if (nbox > 1) {
783	    /*reverse orderof rects in each band */
784	    pboxNew2 = (BoxPtr)malloc(sizeof(BoxRec)*nbox);
785	    pptNew2 = (DDXPointPtr)malloc(sizeof(DDXPointRec)*nbox);
786	    if (!pboxNew2 || !pptNew2) {
787	        free(pptNew2);
788	        free(pboxNew2);
789	        if (pboxNew1) {
790		    free(pptNew1);
791		    free(pboxNew1);
792		}
793	       return;
794	    }
795	    pboxBase = pboxNext = pbox;
796	    while (pboxBase < pbox+nbox) {
797	        while ((pboxNext < pbox+nbox) &&
798		       (pboxNext->y1 == pboxBase->y1))
799		  pboxNext++;
800	        pboxTmp = pboxNext;
801	        pptTmp = pptSrc + (pboxTmp - pbox);
802	        while (pboxTmp != pboxBase) {
803		    *pboxNew2++ = *--pboxTmp;
804		    *pptNew2++ = *--pptTmp;
805		}
806	        pboxBase = pboxNext;
807	    }
808	    pboxNew2 -= nbox;
809	    pbox = pboxNew2;
810	    pptNew2 -= nbox;
811	    pptSrc = pptNew2;
812	}
813    } else {
814        /* No changes are needed */
815        xdir = 1;
816    }
817
818    xaa->SetupForScreenToScreenCopy(pScrn, xdir, ydir, GXcopy, -1, -1);
819    for ( ; nbox-- ; pbox++) {
820	 int x1 = pbox->x1;
821	 int y1 = pbox->y1;
822	 int destx = x1 + dx;
823	 int desty = y1 + dy;
824	 int w = pbox->x2 - x1 + 1;
825	 int h = pbox->y2 - y1 + 1;
826
827	 if ( destx < 0 ) x1 -= destx, w += destx, destx = 0;
828	 if ( desty < 0 ) y1 -= desty, h += desty, desty = 0;
829	 if ( destx + w > screenwidth ) w = screenwidth - destx;
830	 if ( desty + h > screenheight ) h = screenheight - desty;
831	 if ( w <= 0 ) continue;
832	 if ( h <= 0 ) continue;
833
834	 MGASelectBuffer(pScrn, MGA_BACK);
835	 xaa->SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h);
836	 MGASelectBuffer(pScrn, MGA_DEPTH);
837	 xaa->SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h);
838    }
839    MGASelectBuffer(pScrn, MGA_FRONT);
840
841    if (pboxNew2) {
842        free(pptNew2);
843        free(pboxNew2);
844    }
845    if (pboxNew1) {
846        free(pptNew1);
847        free(pboxNew1);
848    }
849
850    pMga->AccelInfoRec->NeedToSync = TRUE;
851
852}
853#endif
854
855static void MGADRIMoveBuffersEXA(WindowPtr pParent, DDXPointRec ptOldOrg,
856                                 RegionPtr prgnSrc, CARD32 index)
857{
858    /* FIXME */
859}
860
861Bool MGADRIScreenInit( ScreenPtr pScreen )
862{
863   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
864   MGAPtr pMga = MGAPTR(pScrn);
865   DRIInfoPtr pDRIInfo;
866   MGADRIPtr pMGADRI;
867   MGADRIServerPrivatePtr pMGADRIServer;
868
869   if (!pMga->chip_attribs->dri_capable) {
870       xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[drm] Direct rendering only supported with G200/G400/G450/G550.\n");
871       return FALSE;
872   }
873
874   /* Check that the DRI, and DRM modules have been loaded by testing
875    * for canonical symbols in each module.
876    */
877   if ( !xf86LoaderCheckSymbol( "drmAvailable" ) )		return FALSE;
878   if ( !xf86LoaderCheckSymbol( "DRIQueryVersion" ) ) {
879      xf86DrvMsg( pScreen->myNum, X_ERROR,
880		  "[dri] MGADRIScreenInit failed (libdri.a too old)\n" );
881      return FALSE;
882   }
883
884   /* Check the DRI version */
885   {
886      int major, minor, patch;
887      DRIQueryVersion( &major, &minor, &patch );
888      if ( major != DRIINFO_MAJOR_VERSION || minor < DRIINFO_MINOR_VERSION ) {
889         xf86DrvMsg( pScreen->myNum, X_ERROR,
890		     "[dri] MGADRIScreenInit failed because of a version mismatch.\n"
891		     "[dri] libdri version = %d.%d.%d but version %d.%d.x is needed.\n"
892		     "[dri] Disabling the DRI.\n",
893		     major, minor, patch,
894                     DRIINFO_MAJOR_VERSION, DRIINFO_MINOR_VERSION );
895         return FALSE;
896      }
897   }
898
899   xf86DrvMsg( pScreen->myNum, X_INFO,
900	       "[drm] bpp: %d depth: %d\n",
901	       pScrn->bitsPerPixel, pScrn->depth );
902
903   if ( (pScrn->bitsPerPixel / 8) != 2 &&
904	(pScrn->bitsPerPixel / 8) != 4 ) {
905      xf86DrvMsg( pScreen->myNum, X_ERROR,
906		  "[dri] Direct rendering only supported in 16 and 32 bpp modes\n" );
907      return FALSE;
908   }
909
910   pDRIInfo = DRICreateInfoRec();
911   if ( !pDRIInfo ) {
912      xf86DrvMsg( pScreen->myNum, X_ERROR,
913		  "[dri] DRICreateInfoRec() failed\n" );
914      return FALSE;
915   }
916   pMga->pDRIInfo = pDRIInfo;
917
918   pDRIInfo->drmDriverName = MGAKernelDriverName;
919   pDRIInfo->clientDriverName = MGAClientDriverName;
920   if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) {
921      pDRIInfo->busIdString = DRICreatePCIBusID(pMga->PciInfo);
922   } else {
923      pDRIInfo->busIdString = malloc(64);
924      sprintf( pDRIInfo->busIdString, "PCI:%d:%d:%d",
925#ifdef XSERVER_LIBPCIACCESS
926	       ((pMga->PciInfo->domain << 8) | pMga->PciInfo->bus),
927	       pMga->PciInfo->dev, pMga->PciInfo->func
928#else
929	       ((pciConfigPtr)pMga->PciInfo->thisCard)->busnum,
930	       ((pciConfigPtr)pMga->PciInfo->thisCard)->devnum,
931	       ((pciConfigPtr)pMga->PciInfo->thisCard)->funcnum
932#endif
933	       );
934   }
935   pDRIInfo->ddxDriverMajorVersion = PACKAGE_VERSION_MAJOR;
936   pDRIInfo->ddxDriverMinorVersion = PACKAGE_VERSION_MINOR;
937   pDRIInfo->ddxDriverPatchVersion = PACKAGE_VERSION_PATCHLEVEL;
938   pDRIInfo->frameBufferPhysicalAddress = (void *) pMga->FbAddress;
939   pDRIInfo->frameBufferSize = pMga->FbMapSize;
940   pDRIInfo->frameBufferStride = pScrn->displayWidth*(pScrn->bitsPerPixel/8);
941   pDRIInfo->ddxDrawableTableEntry = MGA_MAX_DRAWABLES;
942
943   pDRIInfo->createDummyCtx = TRUE;
944   pDRIInfo->createDummyCtxPriv = FALSE;
945
946   if ( SAREA_MAX_DRAWABLES < MGA_MAX_DRAWABLES ) {
947      pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES;
948   } else {
949      pDRIInfo->maxDrawableTableEntry = MGA_MAX_DRAWABLES;
950   }
951
952   /* For now the mapping works by using a fixed size defined
953    * in the SAREA header.
954    */
955   if ( sizeof(XF86DRISAREARec) + sizeof(MGASAREAPrivRec) > SAREA_MAX ) {
956      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
957		  "[drm] Data does not fit in SAREA\n" );
958      return FALSE;
959   }
960
961   xf86DrvMsg( pScrn->scrnIndex, X_INFO,
962	       "[drm] Sarea %d+%d: %d\n",
963	       (int)sizeof(XF86DRISAREARec), (int)sizeof(MGASAREAPrivRec),
964	       (int)sizeof(XF86DRISAREARec) + (int)sizeof(MGASAREAPrivRec) );
965
966   pDRIInfo->SAREASize = SAREA_MAX;
967
968   pMGADRI = (MGADRIPtr)calloc( sizeof(MGADRIRec), 1 );
969   if ( !pMGADRI ) {
970      DRIDestroyInfoRec( pMga->pDRIInfo );
971      pMga->pDRIInfo = 0;
972      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
973		  "[drm] Failed to allocate memory for private record\n" );
974      return FALSE;
975   }
976
977   pMGADRIServer = (MGADRIServerPrivatePtr)
978      calloc( sizeof(MGADRIServerPrivateRec), 1 );
979   if ( !pMGADRIServer ) {
980      free( pMGADRI );
981      DRIDestroyInfoRec( pMga->pDRIInfo );
982      pMga->pDRIInfo = 0;
983      xf86DrvMsg( pScrn->scrnIndex, X_ERROR,
984		  "[drm] Failed to allocate memory for private record\n" );
985      return FALSE;
986   }
987   pMga->DRIServerInfo = pMGADRIServer;
988
989   pDRIInfo->devPrivate = pMGADRI;
990   pDRIInfo->devPrivateSize = sizeof(MGADRIRec);
991   pDRIInfo->contextSize = sizeof(MGADRIContextRec);
992
993   pDRIInfo->CreateContext = MGACreateContext;
994   pDRIInfo->DestroyContext = MGADestroyContext;
995   if ( xf86IsEntityShared( pScrn->entityList[0] )
996		&& pMga->DualHeadEnabled) {
997      pDRIInfo->SwapContext = MGADRISwapContextShared;
998   } else {
999      pDRIInfo->SwapContext = MGADRISwapContext;
1000   }
1001
1002   pDRIInfo->InitBuffers = MGADRIInitBuffersEXA;
1003   pDRIInfo->MoveBuffers = MGADRIMoveBuffersEXA;
1004#ifdef USE_EXA
1005    if (pMga->Exa) {
1006        pDRIInfo->InitBuffers = MGADRIInitBuffersEXA;
1007        pDRIInfo->MoveBuffers = MGADRIMoveBuffersEXA;
1008    } else {
1009#endif
1010#ifdef USE_XAA
1011        pDRIInfo->InitBuffers = MGADRIInitBuffersXAA;
1012        pDRIInfo->MoveBuffers = MGADRIMoveBuffersXAA;
1013#endif
1014#ifdef USE_EXA
1015    }
1016#endif
1017
1018   pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
1019
1020   if ( !DRIScreenInit( pScreen, pDRIInfo, &pMga->drmFD ) ) {
1021      free( pMGADRIServer );
1022      pMga->DRIServerInfo = 0;
1023      free( pDRIInfo->devPrivate );
1024      pDRIInfo->devPrivate = 0;
1025      DRIDestroyInfoRec( pMga->pDRIInfo );
1026      pMga->pDRIInfo = 0;
1027      xf86DrvMsg( pScreen->myNum, X_ERROR,
1028		  "[drm] DRIScreenInit failed.  Disabling DRI.\n" );
1029      return FALSE;
1030   }
1031
1032   /* Check the DRM versioning */
1033   {
1034      drmVersionPtr version;
1035
1036      /* Check the DRM lib version.
1037	 drmGetLibVersion was not supported in version 1.0, so check for
1038	 symbol first to avoid possible crash or hang.
1039       */
1040      if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
1041         version = drmGetLibVersion(pMga->drmFD);
1042      }
1043      else {
1044	 /* drmlib version 1.0.0 didn't have the drmGetLibVersion
1045	    entry point.  Fake it by allocating a version record
1046	    via drmGetVersion and changing it to version 1.0.0
1047	  */
1048	 version = drmGetVersion(pMga->drmFD);
1049	 version->version_major      = 1;
1050	 version->version_minor      = 0;
1051	 version->version_patchlevel = 0;
1052      }
1053
1054      if (version) {
1055	 if (version->version_major != 1 ||
1056	     version->version_minor < 1) {
1057	     /* incompatible drm library version */
1058	    xf86DrvMsg(pScreen->myNum, X_ERROR,
1059		       "[dri] MGADRIScreenInit failed because of a version mismatch.\n"
1060		       "[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n"
1061		       "[dri] Disabling DRI.\n",
1062		       version->version_major,
1063		       version->version_minor,
1064		       version->version_patchlevel);
1065	    drmFreeVersion(version);
1066	    MGADRICloseScreen( pScreen );		/* FIXME: ??? */
1067	    return FALSE;
1068	 }
1069	 drmFreeVersion(version);
1070      }
1071
1072      /* Check the MGA DRM version */
1073      version = drmGetVersion(pMga->drmFD);
1074      if ( version ) {
1075         if ( version->version_major != 3 ||
1076	      version->version_minor < 0 ) {
1077            /* incompatible drm version */
1078            xf86DrvMsg( pScreen->myNum, X_ERROR,
1079			"[dri] MGADRIScreenInit failed because of a version mismatch.\n"
1080			"[dri] mga.o kernel module version is %d.%d.%d but version 3.0.x is needed.\n"
1081			"[dri] Disabling DRI.\n",
1082			version->version_major,
1083			version->version_minor,
1084			version->version_patchlevel );
1085            drmFreeVersion( version );
1086	    MGADRICloseScreen( pScreen );		/* FIXME: ??? */
1087            return FALSE;
1088         }
1089	 pMGADRIServer->drm_version_major = version->version_major;
1090	 pMGADRIServer->drm_version_minor = version->version_minor;
1091
1092         drmFreeVersion( version );
1093      }
1094   }
1095
1096   if ( (pMga->bios.host_interface == MGA_HOST_PCI) &&
1097	((pMGADRIServer->drm_version_minor < 2) || pMga->useOldDmaInit) ) {
1098       /* PCI cards are supported if the DRM version is at least 3.2 and the
1099	* user has not explicitly disabled the new DMA init path (i.e., to
1100	* support old version of the client-side driver that don't use the
1101	* new features of the 3.2 DRM).
1102	*/
1103       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1104		  "[drm] Direct rendering on PCI cards requires DRM version 3.2 or higher\n");
1105       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1106		  "[drm] and a recent client-side driver.  Also make sure that 'OldDmaInit'\n");
1107       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1108		  "[drm] is not selected in xorg.conf.'\n");
1109       return FALSE;
1110   }
1111
1112
1113   if ( !MGADRIBootstrapDMA( pScreen ) ) {
1114      DRICloseScreen( pScreen );
1115      return FALSE;
1116   }
1117
1118   {
1119       void *scratch_ptr;
1120       int scratch_int;
1121
1122       DRIGetDeviceInfo(pScreen, &pMGADRIServer->fb.handle,
1123			&scratch_int, &scratch_int,
1124			&scratch_int, &scratch_int,
1125			&scratch_ptr);
1126   }
1127
1128   xf86DrvMsg( pScrn->scrnIndex, X_INFO, "[dri] visual configs initialized\n" );
1129
1130   return TRUE;
1131}
1132
1133
1134Bool MGADRIFinishScreenInit( ScreenPtr pScreen )
1135{
1136   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1137   MGAPtr pMga = MGAPTR(pScrn);
1138   MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
1139   MGADRIPtr pMGADRI;
1140   int i;
1141
1142   if ( !pMga->pDRIInfo )
1143      return FALSE;
1144
1145   pMGADRI = (MGADRIPtr)pMga->pDRIInfo->devPrivate;
1146
1147   pMga->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
1148
1149   /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit
1150    * because *DRIKernelInit requires that the hardware lock is held by
1151    * the X server, and the first time the hardware lock is grabbed is
1152    * in DRIFinishScreenInit.
1153    */
1154   if ( !DRIFinishScreenInit( pScreen ) ) {
1155      MGADRICloseScreen( pScreen );
1156      return FALSE;
1157   }
1158
1159   if ( !MGADRIKernelInit( pScreen ) ) {
1160      MGADRICloseScreen( pScreen );
1161      return FALSE;
1162   }
1163
1164   if ( !MGADRIBuffersInit( pScreen ) ) {
1165      MGADRICloseScreen( pScreen );
1166      return FALSE;
1167   }
1168
1169   MGADRIIrqInit(pMga, pScreen);
1170
1171   pMGADRI->chipset		= pMga->chip_attribs->dri_chipset;
1172   pMGADRI->width		= pScrn->virtualX;
1173   pMGADRI->height		= pScrn->virtualY;
1174   pMGADRI->cpp			= pScrn->bitsPerPixel / 8;
1175
1176   pMGADRI->agpMode		= pMga->agpMode;
1177
1178   pMGADRI->frontOffset		= pMGADRIServer->frontOffset;
1179   pMGADRI->frontPitch		= pMGADRIServer->frontPitch;
1180   pMGADRI->backOffset		= pMGADRIServer->backOffset;
1181   pMGADRI->backPitch		= pMGADRIServer->backPitch;
1182   pMGADRI->depthOffset		= pMGADRIServer->depthOffset;
1183   pMGADRI->depthPitch		= pMGADRIServer->depthPitch;
1184   pMGADRI->textureOffset	= pMGADRIServer->textureOffset;
1185   pMGADRI->textureSize		= pMGADRIServer->textureSize;
1186
1187   pMGADRI->agpTextureOffset = (unsigned int)pMGADRIServer->agpTextures.handle;
1188   pMGADRI->agpTextureSize = (unsigned int)pMGADRIServer->agpTextures.size;
1189
1190   pMGADRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
1191
1192
1193   /* Newer versions of the client-side driver do not need these if the
1194    * kernel version is high enough to support interrupt based waiting.
1195    */
1196
1197   pMGADRI->registers.handle	= pMGADRIServer->registers.handle;
1198   pMGADRI->registers.size	= pMGADRIServer->registers.size;
1199   pMGADRI->primary.handle	= pMGADRIServer->primary.handle;
1200   pMGADRI->primary.size	= pMGADRIServer->primary.size;
1201
1202
1203   /* These are no longer used by the client-side DRI driver.  They should
1204    * be removed in the next release (i.e., 6.9 / 7.0).
1205    */
1206
1207   pMGADRI->status.handle	= pMGADRIServer->status.handle;
1208   pMGADRI->status.size		= pMGADRIServer->status.size;
1209   pMGADRI->buffers.handle	= pMGADRIServer->buffers.handle;
1210   pMGADRI->buffers.size	= pMGADRIServer->buffers.size;
1211
1212   i = mylog2( pMGADRI->textureSize / MGA_NR_TEX_REGIONS );
1213   if ( i < MGA_LOG_MIN_TEX_REGION_SIZE )
1214      i = MGA_LOG_MIN_TEX_REGION_SIZE;
1215
1216   pMGADRI->logTextureGranularity = i;
1217   pMGADRI->textureSize = (pMGADRI->textureSize >> i) << i; /* truncate */
1218
1219   i = mylog2( pMGADRIServer->agpTextures.size / MGA_NR_TEX_REGIONS );
1220   if ( i < MGA_LOG_MIN_TEX_REGION_SIZE )
1221      i = MGA_LOG_MIN_TEX_REGION_SIZE;
1222
1223   pMGADRI->logAgpTextureGranularity = i;
1224
1225   return TRUE;
1226}
1227
1228
1229void MGADRICloseScreen( ScreenPtr pScreen )
1230{
1231   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1232   MGAPtr pMga = MGAPTR(pScrn);
1233   MGADRIServerPrivatePtr pMGADRIServer = pMga->DRIServerInfo;
1234   drm_mga_init_t init;
1235
1236   if ( pMGADRIServer->drmBuffers ) {
1237      drmUnmapBufs( pMGADRIServer->drmBuffers );
1238      pMGADRIServer->drmBuffers = NULL;
1239   }
1240
1241   if (pMga->irq) {
1242      drmCtlUninstHandler(pMga->drmFD);
1243      pMga->irq = 0;
1244      pMga->reg_ien = 0;
1245   }
1246
1247   /* Cleanup DMA */
1248   memset( &init, 0, sizeof(drm_mga_init_t) );
1249   init.func = MGA_CLEANUP_DMA;
1250   drmCommandWrite( pMga->drmFD, DRM_MGA_INIT, &init, sizeof(drm_mga_init_t) );
1251
1252   if ( pMGADRIServer->agp.handle != DRM_AGP_NO_HANDLE ) {
1253      drmAgpUnbind( pMga->drmFD, pMGADRIServer->agp.handle );
1254      drmAgpFree( pMga->drmFD, pMGADRIServer->agp.handle );
1255      pMGADRIServer->agp.handle = DRM_AGP_NO_HANDLE;
1256      drmAgpRelease( pMga->drmFD );
1257   }
1258
1259   DRICloseScreen( pScreen );
1260
1261   if ( pMga->pDRIInfo ) {
1262      free(pMga->pDRIInfo->devPrivate);
1263      pMga->pDRIInfo->devPrivate = 0;
1264      DRIDestroyInfoRec( pMga->pDRIInfo );
1265      pMga->pDRIInfo = 0;
1266   }
1267   free(pMga->DRIServerInfo);
1268   pMga->DRIServerInfo = 0;
1269}
1270