root/src/add-ons/accelerants/s3/register_io.cpp
/*
        Copyright 2008 Haiku, Inc.  All rights reserved.
        Distributed under the terms of the MIT license.

        Authors:
        Gerald Zajac 2008
*/

#include "accel.h"

#include <unistd.h>


// Macros for memory mapped I/O.
//==============================

#define INREG8(addr)            *((vuint8*)(gInfo.regs + addr))
#define INREG16(addr)           *((vuint16*)(gInfo.regs + addr))
#define INREG32(addr)           *((vuint32*)(gInfo.regs + addr))

#define OUTREG8(addr, val)      *((vuint8*)(gInfo.regs + addr)) = val
#define OUTREG16(addr, val)     *((vuint16*)(gInfo.regs + addr)) = val
#define OUTREG32(addr, val)     *((vuint32*)(gInfo.regs + addr)) = val


// Functions for PIO.
//===================

uint32 ReadPIO(uint32 addr, uint8 numBytes)
{
        S3GetSetPIO gsp;
        gsp.magic = S3_PRIVATE_DATA_MAGIC;
        gsp.offset = addr;
        gsp.size = numBytes;
        gsp.value = 0;

        status_t result = ioctl(gInfo.deviceFileDesc, S3_GET_PIO, &gsp, sizeof(gsp));
        if (result != B_OK)
                TRACE("ReadPIO() failed, result = 0x%x\n", result);

        return gsp.value;
}


void WritePIO(uint32 addr, uint8 numBytes, uint32 value)
{
        S3GetSetPIO gsp;
        gsp.magic = S3_PRIVATE_DATA_MAGIC;
        gsp.offset = addr;
        gsp.size = numBytes;
        gsp.value = value;

        status_t result = ioctl(gInfo.deviceFileDesc, S3_SET_PIO, &gsp, sizeof(gsp));
        if (result != B_OK)
                TRACE("WritePIO() failed, result = 0x%x\n", result);
}


// Functions to read 8/16/32 bit registers.
//=========================================

uint8 ReadReg8(uint32 addr)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64)
                return ReadPIO(addr, 1);

        return INREG8(addr);
}


uint16 ReadReg16(uint32 addr)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64)
                return ReadPIO(addr, 2);

        return INREG16(addr);
}


uint32 ReadReg32(uint32 addr)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64)
                return ReadPIO(addr, 4);

        return INREG32(addr);
}


// Functions to write 8/16/32 bit registers.
//=========================================

void WriteReg8(uint32 addr, uint8 value)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64)
                WritePIO(addr, 1, value);
        else
                OUTREG8(addr, value);
}


void WriteReg16(uint32 addr, uint16 value)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64)
                WritePIO(addr, 2, value);
        else
                OUTREG16(addr, value);
}


void WriteReg32(uint32 addr, uint32 value)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64)
                WritePIO(addr, 4, value);
        else
                OUTREG32(addr, value);
}


// Functions to read/write CRTC registers.
//========================================

uint8 ReadCrtcReg(uint8 index)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64) {
                WritePIO_8(0x3d4, index);
                return ReadPIO_8(0x3d5);
        }

        OUTREG8(0x83d4, index);
        return INREG8(0x83d5);
}


void WriteCrtcReg(uint8 index, uint8 value)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64) {
                WritePIO_8(0x3d4, index);
                WritePIO_8(0x3d5, value);
        } else {
                OUTREG8(0x83d4, index);
                OUTREG8(0x83d5, value);
        }
}


void WriteCrtcReg(uint8 index, uint8 value, uint8 mask)
{
        // Write a value to a CRTC reg using a mask.  The mask selects the
        // bits to be modified.

        if (gInfo.sharedInfo->chipType == S3_TRIO64) {
                WritePIO_8(0x3d4, index);
                WritePIO_8(0x3d5, (ReadPIO_8(0x3d5) & ~mask) | (value & mask));
        } else {
                OUTREG8(0x83d4, index);
                OUTREG8(0x83d5, (INREG8(0x83d5) & ~mask) | (value & mask));
        }
}


// Functions to read/write Sequence registers.
//============================================

uint8 ReadSeqReg(uint8 index)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64) {
                WritePIO_8(0x3c4, index);
                return ReadPIO_8(0x3c5);
        }

        OUTREG8(0x83c4, index);
        return INREG8(0x83c5);
}


void WriteSeqReg(uint8 index, uint8 value)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64) {
                WritePIO_8(0x3c4, index);
                WritePIO_8(0x3c5, value);
        } else {
                OUTREG8(0x83c4, index);
                OUTREG8(0x83c5, value);
        }
}


void WriteSeqReg(uint8 index, uint8 value, uint8 mask)
{
        // Write a value to a Sequencer reg using a mask.  The mask selects the
        // bits to be modified.

        if (gInfo.sharedInfo->chipType == S3_TRIO64) {
                WritePIO_8(0x3c4, index);
                WritePIO_8(0x3c5, (ReadPIO_8(0x3c5) & ~mask) | (value & mask));
        } else {
                OUTREG8(0x83c4, index);
                OUTREG8(0x83c5, (INREG8(0x83c5) & ~mask) | (value & mask));
        }
}


// Functions to read/write the misc output register.
//==================================================

uint8 ReadMiscOutReg()
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64)
                return ReadPIO_8(0x3cc);

        return INREG8(0x83cc);
}


void WriteMiscOutReg(uint8 value)
{
        if (gInfo.sharedInfo->chipType == S3_TRIO64)
                WritePIO_8(0x3c2, value);
        else
                OUTREG8(0x83c2, value);
}


void WriteIndexedColor(uint8 index, uint8 red, uint8 green, uint8 blue)
{
        // Write an indexed color.  Argument index is the index (0-255) of the
        // color, and arguments red, green, & blue are the components of the color.

        // Note that although the Trio64V+ chip supports MMIO in nearly all areas,
        // it does not support MMIO for setting indexed colors;  thus, use PIO to
        // set the indexed color.

        if (gInfo.sharedInfo->chipType == S3_TRIO64
                        || gInfo.sharedInfo->chipType == S3_TRIO64_VP) {
                WritePIO_8(0x3c8, index);       // color index
                WritePIO_8(0x3c9, red);
                WritePIO_8(0x3c9, green);
                WritePIO_8(0x3c9, blue);
        } else {
                OUTREG8(0x83c8, index);         // color index
                OUTREG8(0x83c9, red);
                OUTREG8(0x83c9, green);
                OUTREG8(0x83c9, blue);
        }
}