diff options
Diffstat (limited to 'src/mesa/drivers/dri/mga/mgaioctl.c')
-rw-r--r-- | src/mesa/drivers/dri/mga/mgaioctl.c | 747 |
1 files changed, 0 insertions, 747 deletions
diff --git a/src/mesa/drivers/dri/mga/mgaioctl.c b/src/mesa/drivers/dri/mga/mgaioctl.c deleted file mode 100644 index a54d86a178d..00000000000 --- a/src/mesa/drivers/dri/mga/mgaioctl.c +++ /dev/null @@ -1,747 +0,0 @@ -/* - * Copyright 2000-2001 VA Linux Systems, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * on the rights to use, copy, modify, merge, publish, distribute, sub - * license, and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file mgaioctl.c - * MGA IOCTL related wrapper functions. - * - * \author Keith Whitwell <[email protected]> - * \author Gareth Hughes <[email protected]> - */ - -#include <errno.h> -#include "main/mtypes.h" -#include "main/macros.h" -#include "main/dd.h" -#include "swrast/swrast.h" - -#include "main/mm.h" -#include "drm.h" -#include "mga_drm.h" -#include "mgacontext.h" -#include "mgadd.h" -#include "mgastate.h" -#include "mgaioctl.h" - -#include "vblank.h" - - -static int -mgaSetFence( mgaContextPtr mmesa, uint32_t * fence ) -{ - int ret = ENOSYS; - - if ( mmesa->driScreen->drm_version.minor >= 2 ) { - ret = drmCommandWriteRead( mmesa->driScreen->fd, DRM_MGA_SET_FENCE, - fence, sizeof( uint32_t )); - if (ret) { - fprintf(stderr, "drmMgaSetFence: %d\n", ret); - exit(1); - } - } - - return ret; -} - - -static int -mgaWaitFence( mgaContextPtr mmesa, uint32_t fence, uint32_t * curr_fence ) -{ - int ret = ENOSYS; - - if ( mmesa->driScreen->drm_version.minor >= 2 ) { - uint32_t temp = fence; - - ret = drmCommandWriteRead( mmesa->driScreen->fd, - DRM_MGA_WAIT_FENCE, - & temp, sizeof( uint32_t )); - if (ret) { - fprintf(stderr, "drmMgaSetFence: %d\n", ret); - exit(1); - } - - if ( curr_fence ) { - *curr_fence = temp; - } - } - - return ret; -} - - -static void mga_iload_dma_ioctl(mgaContextPtr mmesa, - unsigned long dest, - int length) -{ - drmBufPtr buf = mmesa->iload_buffer; - drm_mga_iload_t iload; - int ret, i; - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n", - buf->idx, (int) dest, length); - - if ( (length & MGA_ILOAD_MASK) != 0 ) { - UNLOCK_HARDWARE( mmesa ); - fprintf( stderr, "%s: Invalid ILOAD datasize (%d), must be " - "multiple of %u.\n", __FUNCTION__, length, MGA_ILOAD_ALIGN ); - exit( 1 ); - } - - iload.idx = buf->idx; - iload.dstorg = dest; - iload.length = length; - - i = 0; - do { - ret = drmCommandWrite( mmesa->driFd, DRM_MGA_ILOAD, - &iload, sizeof(iload) ); - } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY ); - - if ( ret < 0 ) { - printf("send iload retcode = %d\n", ret); - exit(1); - } - - mmesa->iload_buffer = 0; - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "finished iload dma put\n"); - -} - -drmBufPtr mga_get_buffer_ioctl( mgaContextPtr mmesa ) -{ - int idx = 0; - int size = 0; - drmDMAReq dma; - int retcode; - drmBufPtr buf; - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "Getting dma buffer\n"); - - dma.context = mmesa->hHWContext; - dma.send_count = 0; - dma.send_list = NULL; - dma.send_sizes = NULL; - dma.flags = 0; - dma.request_count = 1; - dma.request_size = MGA_BUFFER_SIZE; - dma.request_list = &idx; - dma.request_sizes = &size; - dma.granted_count = 0; - - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "drmDMA (get) ctx %d count %d size 0x%x\n", - dma.context, dma.request_count, - dma.request_size); - - while (1) { - retcode = drmDMA(mmesa->driFd, &dma); - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "retcode %d sz %d idx %d count %d\n", - retcode, - dma.request_sizes[0], - dma.request_list[0], - dma.granted_count); - - if (retcode == 0 && - dma.request_sizes[0] && - dma.granted_count) - break; - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "\n\nflush"); - - UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT ); - } - - buf = &(mmesa->mgaScreen->bufs->list[idx]); - buf->used = 0; - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, - "drmDMA (get) returns size[0] 0x%x idx[0] %d\n" - "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n", - dma.request_sizes[0], dma.request_list[0], - buf->idx, buf->total, - buf->used, buf->address); - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "finished getbuffer\n"); - - return buf; -} - - - - -static void -mgaClear( struct gl_context *ctx, GLbitfield mask ) -{ - mgaContextPtr mmesa = MGA_CONTEXT(ctx); - __DRIdrawable *dPriv = mmesa->driDrawable; - GLuint flags = 0; - GLuint clear_color = mmesa->ClearColor; - GLuint clear_depth = 0; - GLuint color_mask = 0; - GLuint depth_mask = 0; - int ret; - int i; - static int nrclears; - drm_mga_clear_t clear; - GLint cx, cy, cw, ch; - - FLUSH_BATCH( mmesa ); - - if ( mask & BUFFER_BIT_FRONT_LEFT ) { - flags |= MGA_FRONT; - color_mask = mmesa->setup.plnwt; - mask &= ~BUFFER_BIT_FRONT_LEFT; - } - - if ( mask & BUFFER_BIT_BACK_LEFT ) { - flags |= MGA_BACK; - color_mask = mmesa->setup.plnwt; - mask &= ~BUFFER_BIT_BACK_LEFT; - } - - if ( (mask & BUFFER_BIT_DEPTH) && ctx->Depth.Mask ) { - flags |= MGA_DEPTH; - clear_depth = (mmesa->ClearDepth & mmesa->depth_clear_mask); - depth_mask |= mmesa->depth_clear_mask; - mask &= ~BUFFER_BIT_DEPTH; - } - - if ( (mask & BUFFER_BIT_STENCIL) && mmesa->hw_stencil ) { - flags |= MGA_DEPTH; - clear_depth |= (ctx->Stencil.Clear & mmesa->stencil_clear_mask); - depth_mask |= mmesa->stencil_clear_mask; - mask &= ~BUFFER_BIT_STENCIL; - } - - if ( flags ) { - LOCK_HARDWARE( mmesa ); - - /* compute region after locking: */ - cx = ctx->DrawBuffer->_Xmin; - cy = ctx->DrawBuffer->_Ymin; - cw = ctx->DrawBuffer->_Xmax - cx; - ch = ctx->DrawBuffer->_Ymax - cy; - - if ( mmesa->dirty_cliprects ) - mgaUpdateRects( mmesa, (MGA_FRONT | MGA_BACK) ); - - /* flip top to bottom */ - cy = dPriv->h-cy-ch; - cx += mmesa->drawX; - cy += mmesa->drawY; - - if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL ) - fprintf( stderr, "Clear, bufs %x nbox %d\n", - (int)flags, (int)mmesa->numClipRects ); - - for (i = 0 ; i < mmesa->numClipRects ; ) - { - int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, mmesa->numClipRects); - drm_clip_rect_t *box = mmesa->pClipRects; - drm_clip_rect_t *b = mmesa->sarea->boxes; - int n = 0; - - if (cw != dPriv->w || ch != dPriv->h) { - /* clear subregion */ - for ( ; i < nr ; i++) { - GLint x = box[i].x1; - GLint y = box[i].y1; - GLint w = box[i].x2 - x; - GLint h = box[i].y2 - y; - - if (x < cx) w -= cx - x, x = cx; - if (y < cy) h -= cy - y, y = cy; - if (x + w > cx + cw) w = cx + cw - x; - if (y + h > cy + ch) h = cy + ch - y; - if (w <= 0) continue; - if (h <= 0) continue; - - b->x1 = x; - b->y1 = y; - b->x2 = x + w; - b->y2 = y + h; - b++; - n++; - } - } else { - /* clear whole window */ - for ( ; i < nr ; i++) { - *b++ = box[i]; - n++; - } - } - - - if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL ) - fprintf( stderr, - "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n", - flags, clear_color, clear_depth, mmesa->sarea->nbox ); - - mmesa->sarea->nbox = n; - - clear.flags = flags; - clear.clear_color = clear_color; - clear.clear_depth = clear_depth; - clear.color_mask = color_mask; - clear.depth_mask = depth_mask; - ret = drmCommandWrite( mmesa->driFd, DRM_MGA_CLEAR, - &clear, sizeof(clear)); - if ( ret ) { - fprintf( stderr, "send clear retcode = %d\n", ret ); - exit( 1 ); - } - if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL ) - fprintf( stderr, "finished clear %d\n", ++nrclears ); - } - - UNLOCK_HARDWARE( mmesa ); - mmesa->dirty |= MGA_UPLOAD_CLIPRECTS|MGA_UPLOAD_CONTEXT; - } - - if (mask) - _swrast_Clear( ctx, mask ); -} - - -/** - * Wait for the previous frame of rendering has completed. - * - * \param mmesa Hardware context pointer. - * - * \bug - * The loop in this function should have some sort of a timeout mechanism. - * - * \warning - * This routine used to assume that the hardware lock was held on entry. It - * now assumes that the lock is \b not held on entry. - */ - -static void mgaWaitForFrameCompletion( mgaContextPtr mmesa ) -{ - if ( mgaWaitFence( mmesa, mmesa->last_frame_fence, NULL ) == ENOSYS ) { - unsigned wait = 0; - GLuint last_frame; - GLuint last_wrap; - - - LOCK_HARDWARE( mmesa ); - last_frame = mmesa->sarea->last_frame.head; - last_wrap = mmesa->sarea->last_frame.wrap; - - /* The DMA routines in the kernel track a couple values in the SAREA - * that we use here. The number of times that the primary DMA buffer - * has "wrapped" around is tracked in last_wrap. In addition, the - * wrap count and the buffer position at the end of the last frame are - * stored in last_frame.wrap and last_frame.head. - * - * By comparing the wrap counts and the current DMA pointer value - * (read directly from the hardware) to last_frame.head, we can - * determine when the graphics processor has processed all of the - * commands for the last frame. - * - * In this case "last frame" means the frame of the *previous* swap- - * buffers call. This is done to prevent queuing a second buffer swap - * before the previous swap is executed. - */ - while ( 1 ) { - if ( last_wrap < mmesa->sarea->last_wrap || - ( last_wrap == mmesa->sarea->last_wrap && - last_frame <= (MGA_READ( MGAREG_PRIMADDRESS ) - - mmesa->primary_offset) ) ) { - break; - } - if ( 0 ) { - wait++; - fprintf( stderr, " last: head=0x%06x wrap=%d\n", - last_frame, last_wrap ); - fprintf( stderr, " head: head=0x%06lx wrap=%d\n", - (long)(MGA_READ( MGAREG_PRIMADDRESS ) - mmesa->primary_offset), - mmesa->sarea->last_wrap ); - } - UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH ); - - UNLOCK_HARDWARE( mmesa ); - DO_USLEEP( 1 ); - LOCK_HARDWARE( mmesa ); - } - if ( wait ) - fprintf( stderr, "\n" ); - - UNLOCK_HARDWARE( mmesa ); - } -} - - -/* - * Copy the back buffer to the front buffer. - */ -void mgaCopyBuffer( __DRIdrawable *dPriv ) -{ - mgaContextPtr mmesa; - drm_clip_rect_t *pbox; - GLint nbox; - GLint ret; - GLint i; - GLboolean missed_target; - __DRIscreen *psp = dPriv->driScreenPriv; - - assert(dPriv); - assert(dPriv->driContextPriv); - assert(dPriv->driContextPriv->driverPrivate); - - mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate; - - FLUSH_BATCH( mmesa ); - - mgaWaitForFrameCompletion( mmesa ); - driWaitForVBlank( dPriv, & missed_target ); - if ( missed_target ) { - mmesa->swap_missed_count++; - (void) (*psp->systemTime->getUST)( & mmesa->swap_missed_ust ); - } - LOCK_HARDWARE( mmesa ); - - /* Use the frontbuffer cliprects - */ - if (mmesa->dirty_cliprects & MGA_FRONT) - mgaUpdateRects( mmesa, MGA_FRONT ); - - - pbox = dPriv->pClipRects; - nbox = dPriv->numClipRects; - - for (i = 0 ; i < nbox ; ) - { - int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, dPriv->numClipRects); - drm_clip_rect_t *b = mmesa->sarea->boxes; - - mmesa->sarea->nbox = nr - i; - - for ( ; i < nr ; i++) - *b++ = pbox[i]; - - if (0) - fprintf(stderr, "DRM_IOCTL_MGA_SWAP\n"); - - ret = drmCommandNone( mmesa->driFd, DRM_MGA_SWAP ); - if ( ret ) { - printf("send swap retcode = %d\n", ret); - exit(1); - } - } - - (void) mgaSetFence( mmesa, & mmesa->last_frame_fence ); - UNLOCK_HARDWARE( mmesa ); - - mmesa->dirty |= MGA_UPLOAD_CLIPRECTS; - mmesa->swap_count++; - (void) (*psp->systemTime->getUST)( & mmesa->swap_ust ); -} - - -/** - * Implement the hardware-specific portion of \c glFinish. - * - * Flushes all pending commands to the hardware and wait for them to finish. - * - * \param ctx Context where the \c glFinish command was issued. - * - * \sa glFinish, mgaFlush, mgaFlushDMA - */ -static void mgaFinish( struct gl_context *ctx ) -{ - mgaContextPtr mmesa = MGA_CONTEXT(ctx); - uint32_t fence; - - - LOCK_HARDWARE( mmesa ); - if ( mmesa->vertex_dma_buffer != NULL ) { - mgaFlushVerticesLocked( mmesa ); - } - - if ( mgaSetFence( mmesa, & fence ) == 0 ) { - UNLOCK_HARDWARE( mmesa ); - (void) mgaWaitFence( mmesa, fence, NULL ); - } - else { - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) { - fprintf(stderr, "mgaRegetLockQuiescent\n"); - } - - UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH ); - UNLOCK_HARDWARE( mmesa ); - } -} - - -/** - * Flush all commands upto at least a certain point to the hardware. - * - * \note - * The term "wait" in the name of this function is misleading. It doesn't - * actually wait for anything. It just makes sure that the commands have - * been flushed to the hardware. - * - * \warning - * As the name implies, this function assumes that the hardware lock is - * held on entry. - */ -void mgaWaitAgeLocked( mgaContextPtr mmesa, int age ) -{ - if (GET_DISPATCH_AGE(mmesa) < age) { - UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH ); - } -} - - -static GLboolean intersect_rect( drm_clip_rect_t *out, - const drm_clip_rect_t *a, - const drm_clip_rect_t *b ) -{ - *out = *a; - if (b->x1 > out->x1) out->x1 = b->x1; - if (b->y1 > out->y1) out->y1 = b->y1; - if (b->x2 < out->x2) out->x2 = b->x2; - if (b->y2 < out->y2) out->y2 = b->y2; - - return ((out->x1 < out->x2) && (out->y1 < out->y2)); -} - - - - -static void age_mmesa( mgaContextPtr mmesa, int age ) -{ - if (mmesa->CurrentTexObj[0]) mmesa->CurrentTexObj[0]->age = age; - if (mmesa->CurrentTexObj[1]) mmesa->CurrentTexObj[1]->age = age; -} - - -void mgaFlushVerticesLocked( mgaContextPtr mmesa ) -{ - drm_clip_rect_t *pbox = mmesa->pClipRects; - int nbox = mmesa->numClipRects; - drmBufPtr buffer = mmesa->vertex_dma_buffer; - drm_mga_vertex_t vertex; - int i; - - mmesa->vertex_dma_buffer = 0; - - if (!buffer) - return; - - if (mmesa->dirty_cliprects & mmesa->draw_buffer) - mgaUpdateRects( mmesa, mmesa->draw_buffer ); - - if (mmesa->dirty & ~MGA_UPLOAD_CLIPRECTS) - mgaEmitHwStateLocked( mmesa ); - - /* FIXME: Workaround bug in kernel module. - */ - mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT; - - if (!nbox) - buffer->used = 0; - - if (nbox >= MGA_NR_SAREA_CLIPRECTS) - mmesa->dirty |= MGA_UPLOAD_CLIPRECTS; - -#if 0 - if (!buffer->used || !(mmesa->dirty & MGA_UPLOAD_CLIPRECTS)) - { - if (nbox == 1) - mmesa->sarea->nbox = 0; - else - mmesa->sarea->nbox = nbox; - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "Firing vertex -- case a nbox %d\n", nbox); - - vertex.idx = buffer->idx; - vertex.used = buffer->used; - vertex.discard = 1; - drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX, - &vertex, sizeof(drmMGAVertex) ); - - age_mmesa(mmesa, mmesa->sarea->last_enqueue); - } - else -#endif - { - for (i = 0 ; i < nbox ; ) - { - int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, nbox); - drm_clip_rect_t *b = mmesa->sarea->boxes; - int discard = 0; - - if (mmesa->scissor) { - mmesa->sarea->nbox = 0; - - for ( ; i < nr ; i++) { - *b = pbox[i]; - if (intersect_rect(b, b, &mmesa->scissor_rect)) { - mmesa->sarea->nbox++; - b++; - } - } - - /* Culled? - */ - if (!mmesa->sarea->nbox) { - if (nr < nbox) continue; - buffer->used = 0; - } - } else { - mmesa->sarea->nbox = nr - i; - for ( ; i < nr ; i++) - *b++ = pbox[i]; - } - - /* Finished with the buffer? - */ - if (nr == nbox) - discard = 1; - - mmesa->sarea->dirty |= MGA_UPLOAD_CLIPRECTS; - - vertex.idx = buffer->idx; - vertex.used = buffer->used; - vertex.discard = discard; - drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX, - &vertex, sizeof(vertex) ); - - age_mmesa(mmesa, mmesa->sarea->last_enqueue); - } - } - - mmesa->dirty &= ~MGA_UPLOAD_CLIPRECTS; -} - -void mgaFlushVertices( mgaContextPtr mmesa ) -{ - LOCK_HARDWARE( mmesa ); - mgaFlushVerticesLocked( mmesa ); - UNLOCK_HARDWARE( mmesa ); -} - - -void mgaFireILoadLocked( mgaContextPtr mmesa, - GLuint offset, GLuint length ) -{ - if (!mmesa->iload_buffer) { - fprintf(stderr, "mgaFireILoad: no buffer\n"); - return; - } - - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "mgaFireILoad idx %d ofs 0x%x length %d\n", - mmesa->iload_buffer->idx, (int)offset, (int)length ); - - mga_iload_dma_ioctl( mmesa, offset, length ); -} - -void mgaGetILoadBufferLocked( mgaContextPtr mmesa ) -{ - if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) - fprintf(stderr, "mgaGetIloadBuffer (buffer now %p)\n", - (void *) mmesa->iload_buffer); - - mmesa->iload_buffer = mga_get_buffer_ioctl( mmesa ); -} - - -/** - * Implement the hardware-specific portion of \c glFlush. - * - * \param ctx Context to be flushed. - * - * \sa glFlush, mgaFinish, mgaFlushDMA - */ -static void mgaFlush( struct gl_context *ctx ) -{ - mgaContextPtr mmesa = MGA_CONTEXT( ctx ); - - - LOCK_HARDWARE( mmesa ); - if ( mmesa->vertex_dma_buffer != NULL ) { - mgaFlushVerticesLocked( mmesa ); - } - - UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH ); - UNLOCK_HARDWARE( mmesa ); -} - - -int mgaFlushDMA( int fd, drmLockFlags flags ) -{ - drm_lock_t lock; - int ret, i = 0; - - memset( &lock, 0, sizeof(lock) ); - - lock.flags = flags & (DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH - | DRM_LOCK_FLUSH_ALL); - - do { - ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) ); - } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY ); - - if ( ret == 0 ) - return 0; - if ( errno != EBUSY ) - return -errno; - - if ( lock.flags & DRM_LOCK_QUIESCENT ) { - /* Only keep trying if we need quiescence. - */ - lock.flags &= ~(DRM_LOCK_FLUSH | DRM_LOCK_FLUSH_ALL); - - do { - ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) ); - } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY ); - } - - if ( ret == 0 ) { - return 0; - } else { - return -errno; - } -} - -void mgaInitIoctlFuncs( struct dd_function_table *functions ) -{ - functions->Clear = mgaClear; - functions->Flush = mgaFlush; - functions->Finish = mgaFinish; -} |