/****************************************************************************
 * Rage 128 Chapter 7 sample code                                           *
 *                                                                          *
 * bmutil.c - This module contains bus master utility code,                 *
 *            mainly related to queue maintenance.                          *
 *                                                                          *
 * Copyright (c) 1999 ATI Technologies Inc. All rights reserved.            *
 ****************************************************************************/
#include <stdio.h>
#include <i86.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include "regdef.h"
#include "defines.h"
#include "main.h"

extern _bm_info BM_INFO;

WORD R128_BMWaitForEntry (WORD queue)
{
    WORD retval = 0;
    DWORD ticker = 0;

    /* wait for queue entry */
    while ((R128_BMGetQueueEntries (queue) == 0) && (ticker < BM_INFO.count))
    {
        ticker++;
    }
    if (ticker < BM_INFO.count)
    {
        retval = 1;
    }

    return (retval);
} /* R128_BMWaitForEntry () */

void R128_BMWaitForQueueIdle (WORD queue)
{
    DWORD ticker = 0;

    while ((R128_BMGetQueueEntries (queue) < BM_INFO.entries) && (ticker < BM_INFO.count))
    {
        ticker++;
    }
    if (ticker < BM_INFO.count)
    {
        /* wait for queue to become inactive */
        ticker = 0;
        while ((R128_BMGetQueueStatus (queue) == 1) && (ticker < BM_INFO.count))
        {
            ticker++;
        }
        if (ticker > BM_INFO.count)
        {
            R128_ShutDown ();
            printf ("\nBus Mastering idle timeout error");
            printf ("\nTicker value: %ld", ticker);
            exit (1);
        }
    }

}  /* R128_BMWaitForQueueIdle () */

DWORD R128_BMGetTimeoutCount (DWORD ticks)
{
    WORD i, starttick, endtick;
    DWORD count = 0;

    for (i=0; i< (ticks/4); i++)
    {
        starttick = *((WORD *)(DOS_TICK_ADDRESS));
        endtick = starttick;
        while (endtick == starttick)
        {
            regr (BM_QUEUE_FREE_STATUS);
            endtick = *((WORD *)DOS_TICK_ADDRESS);
            count ++;
        }
    }

    /* adjust count since only 1/4 of the tick time was used in the test */
    count = count * 4;

    return (count);
}

WORD R128_BMGetQueueStatus (WORD queue)
{
    DWORD mask;
    WORD retval;

    /* determine which mask is required */
    switch (queue)
    {
        case BM_VIP0_BUF:   mask = 0x01000000;
                            break;

        case BM_VIP1_BUF:   mask = 0x02000000;
                            break;

        case BM_VIP2_BUF:   mask = 0x03000000;
                            break;

        case BM_VIP3_BUF:   mask = 0x04000000;
                            break;

        case BM_VIDCAP_BUF0:    mask = 0x80000000;
                                break;
    }

    if ((regr (BM_QUEUE_STATUS) & mask) == mask)
    {
        retval = 1;
    }
    else
    {
        retval = 0;
    }

    return (retval);
}  /* R128_BMGetQueueStatus () */

WORD R128_BMGetQueueEntries (WORD queue)
{
    WORD entries = 0;

    switch (queue)
    {
        case BM_VIP0_BUF:
            entries = (WORD) (regr (BM_QUEUE_FREE_STATUS) & 0x0000000F);
            break;
        case BM_VIP1_BUF:
            entries = (WORD) ((regr (BM_QUEUE_FREE_STATUS) & 0x000000F0) >> 4);
            break;
        case BM_VIP2_BUF:
            entries = (WORD) ((regr (BM_QUEUE_FREE_STATUS) & 0x00000F00) >> 8);
            break;
        case BM_VIP3_BUF:
            entries = (WORD) ((regr (BM_QUEUE_FREE_STATUS) & 0x0000F000) >> 12);
            break;
        case BM_VIDCAP_BUF0:
            entries = (WORD) ((regr (BM_QUEUE_FREE_STATUS) & 0x00F00000) >> 20);
            break;
    }

    return (entries);
} /* R128_BMGetQueueEntries () */


