/******************************************************************************
 * ioreg.c - Chapter 6 sample code                                            *
 *                                                                            *
 * mach64 functions to access the memory mapped registers.                    *
 *                                                                            *
 * Copyright (c) 1994-1998 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

#include "defines.h"
#include "main.h"

// Prototypes.

unsigned int get_io_port (int regindex);

/******************************************************************************
 * iow32                                                                      *
 *  Function: Writes 32 bits to a specified I/O port.                         *
 *    Inputs: regindex - Register byte offset from start of register block.   *
 *            data - 32 bit data value to fill register.                      *
 *   Outputs: 0 - unsuccessful                                                *
 *            1 - successful                                                  *
 *     Notes: It is assumed that the global structure IO_DATA is filled.      *
 *            this is done on mach64 detection during the short query 12h     *
 ******************************************************************************/

int iow32 (int regindex, unsigned long data)
{
    unsigned int phys;                  // Port address.

    // Get physical port address.
    phys = get_io_port (regindex);
    if (phys == 0)
    {
        // Error - unable to get I/O port.

        return (0);
    } // if

    // Write value.
    outpd (phys, data);

    return (1);

} // iow32


/******************************************************************************
 * ior32                                                                      *
 *  Function: Reads 32 bits from a specified I/O port.                        *
 *    Inputs: regindex - Register byte offset from start of register block.   *
 *   Outputs: data - 32 bit value of I/O port.                                *
 *     Notes: It is assumed that the global structure IO_DATA is filled.      *
 *            this is done on mach64 detection during the short query 12h     *
 ******************************************************************************/

unsigned long ior32 (int regindex)
{
    unsigned int phys;                  // Port address.
    unsigned long data;

    // Get physical port address.
    phys = get_io_port (regindex);
    if (phys == 0)
    {
        // Error - unable to get I/O port.

        return (0);
    } // if

    // Read value.
    data = inpd (phys);

    return (data);

} // ior32


/******************************************************************************
 * iow16                                                                      *
 *  Function: Writes 16 bits to a specified I/O port.                         *
 *    Inputs: regindex - Register byte offset from start of register block.   *
 *            data - 16 bit data value to fill register.                      *
 *   Outputs: 0 - unsuccessful                                                *
 *            1 - successful                                                  *
 *     Notes: It is assumed that the global structure IO_DATA is filled.      *
 *            this is done on mach64 detection during the short query 12h     *
 ******************************************************************************/

int iow16 (int regindex, unsigned short data)
{
    unsigned int phys;                  // Port address.

    // Get physical port address.
    phys = get_io_port (regindex);
    if (phys == 0)
    {
        // Error - unable to get I/O port.

        return (0);
    } // if

    // Write value.
    outpw (phys, data);

    return (1);

} // iow16


/******************************************************************************
 * ior16                                                                      *
 *  Function: Reads 16 bits from a specified I/O port.                        *
 *    Inputs: regindex - Register byte offset from start of register block.   *
 *   Outputs: data - 16 bit value of I/O port.                                *
 *     Notes: It is assumed that the global structure IO_DATA is filled.      *
 *            this is done on mach64 detection during the short query 12h     *
 ******************************************************************************/

unsigned short ior16 (int regindex)
{
    unsigned int phys;                  // Port address.
    unsigned short data;

    // Get physical port address.
    phys = get_io_port (regindex);
    if (phys == 0)
    {
        // Error - unable to get I/O port.

        return (0);
    } // if

    // Read value.
    data = inpw (phys);

    return (data);

} // ior16


/******************************************************************************
 * iow8                                                                       *
 *  Function: Writes 8 bits to a specified I/O port.                          *
 *    Inputs: regindex - Register byte offset from start of register block.   *
 *            data - 8 bit data value to fill register.                       *
 *   Outputs: 0 - unsuccessful                                                *
 *            1 - successful                                                  *
 *     Notes: It is assumed that the global structure IO_DATA is filled.      *
 *            this is done on mach64 detection during the short query 12h     *
 ******************************************************************************/

int iow8 (int regindex, char data)
{
    unsigned int phys;                  // Port address.

    // Get physical port address.
    phys = get_io_port (regindex);
    if (phys == 0)
    {
        // Error - unable to get I/O port.

        return (0);
    } // if

    // Write value.
    outp (phys, data);

    return (1);

} // iow8


/******************************************************************************
 * ior8                                                                       *
 *  Function: Reads 8 bits from a specified I/O port.                         *
 *    Inputs: regindex - Register byte offset from start of register block.   *
 *   Outputs: data - 8 bit value of I/O port.                                 *
 *     Notes: It is assumed that the global structure IO_DATA is filled.      *
 *            this is done on mach64 detection during the short query 12h     *
 ******************************************************************************/

char ior8 (int regindex)
{
    unsigned int phys;                  // Port address.
    char data;

    // Get physical port address.
    phys = get_io_port (regindex);
    if (phys == 0)
    {
        // Error - unable to get I/O port.

        return (0);
    } // if

    // Read value.
    data = inp (phys);

    return (data);

} // ior8


/******************************************************************************
 * get_io_port                                                                *
 *  Function: Computes physical port address.                                 *
 *    Inputs: mmindex - Memory mapped register index.                         *
 *   Outputs: port - I/O port address.                                        *
 *     Notes: It is assumed that the global structure IO_DATA is filled.      *
 *            this is done on mach64 detection during the short query 12h     *
 ******************************************************************************/

unsigned int get_io_port (int mmindex)
{
    unsigned int ioport;                // Port address.

    // Ensure that the specified register has a DWORD index less than 0x40
    // (equivalent to a BYTE index less than 0x0100).
    if (mmindex >= 0x0100)
    {
        return (0);
    } // if

    // Calculate physical address.
    if (IO_DATA.io_type == FIXED)
    {
        if (IO_DATA.io_base == 0x2EC)
        {
            ioport = IO_REGISTER[mmindex >> 2] + (mmindex & 0x0003);
            if (ioport < 4)
            {
                return (0);
            } // if
        }
        else
        {
            // Base address of fixed I/O is not 2ECh.
            return (0);
        } // if
    }
    else if (IO_DATA.io_type == RELOCATABLE)
    {
        ioport = IO_DATA.io_base + mmindex;
    }
    else
    {
        // Error - invalid I/O type.
        return (0);
    } // if

    return (ioport);

} // get_io_port
