📄 register.c
字号:
//
// Permedia3 Sample Display Driver
// register.c
//
// Copyright (c) 2000 Microsoft Corporation. All rights reserved.
//
// This module contains code to initialize the card after it has been located
// on the PCI bus to a state where register writes are possible, as well as
// helpers for register writes and reads.
#include "pch.h" // Precompiled header support.
#include "debug.h"
#include "const.h"
#include "struct.h"
#include "global.h"
#include "register.h"
#include "proto.h"
// This is a cached copy of the base address for the memory region 0. It is
// used whenever a region 0 register is accessed.
volatile ULONG * g_Region0Base;
BOOL
InitializeRegisters()
{
// InitializeRegisters
// This function uses only the PCI configuration information stored in the
// g_Config global to initizlize the card such that general register access
// is possible.
// Local variables.
BOOL FnRetVal = FALSE; // Return value for this function.
PHYSICAL_ADDRESS Region0Bus;
PHYSICAL_ADDRESS Region0Physical;
ULONG AddressSpace;
Enter(L"InitializeRegisters");
// VirtualAlloc enough virtual addresses in order to map the whole memory
// region 0 into virtual space.
g_Region0Base = VirtualAlloc(NULL, // System locates virtual space
REGION0_SIZE,
MEM_RESERVE,
PAGE_NOACCESS);
if (g_Region0Base != NULL) {
// Use HalTranslateBusAddress to turn the PCI address into a physical
// address. Essentially, this is finding out what physical address the
// processor needs to issue to the PCI bus to get to the given PCI address.
AddressSpace = 0; // Memory mapped, not port mapped
Region0Physical.QuadPart = 0;
Region0Bus.LowPart = g_Config.PciCommonConfig.u.type0.BaseAddresses[0];
Region0Bus.HighPart = 0;
if (HalTranslateBusAddress(PCIBus,
g_Config.PciBusNumber,
Region0Bus,
&AddressSpace,
&Region0Physical)) {
// Now, actually map the physical address to a virtual address. We need
// to shift the physcial address right because when PAGE_PHYSICAL is
// specified, VirtualCopy expects the high 32 bits of a 40 bit
// address. The shift essentially sets those high 8 bits to 0.
if (VirtualCopy((LPVOID)g_Region0Base,
(LPVOID)(Region0Physical.LowPart >> 8),
REGION0_SIZE,
PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL)) {
Message(L"Permedia3 registers sucessfully mapped.\n");
FnRetVal = TRUE;
}
else {
Error(L"Unable to map physical address to virtual address!\n");
}
}
else {
Error(L"Unable to translate bus address to physical address!\n");
}
}
else {
Error(L"Unable to allocate virtual address for memory region 0!\n");
}
Exit(L"InitializeRegisters");
return FnRetVal;
}
void
WriteRegByte(
ULONG Offset,
BYTE Value
)
{
// WriteRegByte
// This function allows us to write into a memory region 0 register by
// identifying the offset of that register and the value to put there.
// We do not use the Enter/Exit routines here as this is not really a
// function.
*((BYTE *)g_Region0Base + Offset) = Value;
}
void
WriteMaskedRegByte(
ULONG Offset,
BYTE Mask,
BYTE Value
)
{
// WriteMaskedRegByte
// This function allows us to write to a register in memory region 0
// identified by offset. We are also given a mask, which are the only bits
// we will change. The Enter/Exit routines are not used here as this is not
// really a function.
*((BYTE *)g_Region0Base + Offset) = (*((BYTE *)g_Region0Base + Offset) & ~Mask) | (Value & Mask);
}
BYTE
ReadRegByte(
ULONG Offset
)
{
// ReadRegByte
// This function allows us to read a register in memory region 0 identified
// by offset. An 8 bit value is returned. The Enter/Exit routines are not
// used here as this is not really a function.
return (*((BYTE *)g_Region0Base + Offset));
}
BYTE
ReadMaskedRegByte(
ULONG Offset,
BYTE Mask
)
{
// ReadMaskedRegByte
// This function allows us to read only the bits specified by a given mask
// from a memory region 0 register specified by offset. An 8 bit value is
// returned with 0s in all bits maksed off. The Enter/Exit routines are
// not used here as this is not really a function.
return (*((BYTE *)g_Region0Base + Offset) & Mask);
}
void
WriteRegUlong(
ULONG Offset,
ULONG Value
)
{
// WriteRegUlong
// This function allows us to write into a memory region 0 register by
// identifying the offset of that register and the value to put there.
// We do not use the Enter/Exit routines here as this is not really a
// function.
*(ULONG *)((BYTE *)g_Region0Base + Offset) = Value;
}
void
WriteMaskedRegUlong(
ULONG Offset,
ULONG Mask,
ULONG Value
)
{
// WriteMaskedRegUlong
// This function allows us to write to a register in memory region 0
// identified by offset. We are also given a mask, which are the only bits
// we will change. The Enter/Exit routines are not used here as this is not
// really a function.
*(ULONG *)((BYTE *)g_Region0Base + Offset) = (*(ULONG *)((BYTE *)g_Region0Base + Offset) & ~Mask) | (Value & Mask);
}
ULONG
ReadRegUlong(
ULONG Offset
)
{
// ReadRegUlong
// This function allows us to read a register in memory region 0 identified
// by offset. A 32 bit value is returned. The Enter/Exit routines are not
// used here as this is not really a function.
return (*(ULONG *)((BYTE *)g_Region0Base + Offset));
}
ULONG
ReadMaskedRegUlong(
ULONG Offset,
ULONG Mask
)
{
// ReadMaskedRegUlong
// This function allows us to read only the bits specified by a given mask
// from a memory region 0 register specified by offset. A 32 bit value is
// returned with 0s in all bits maksed off. The Enter/Exit routines are
// not used here as this is not really a function.
return (*(ULONG *)((BYTE *)g_Region0Base + Offset) & Mask);
}
void
WriteRdReg(
ULONG Index,
BYTE Value
)
{
// WriteRdReg
// This function is used to write to one of the indexed RAMDAC registers
// on the Permedia3. The register's index, and the value to be written is
// passed. No Enter/Exit semantics for inlined functions.
WriteRegByte(r_RDIndexLow, (BYTE)(Index & b_RDIndexLow_Index));
WriteRegByte(r_RDIndexHigh, (BYTE)((Index >> 8) & b_RDIndexHigh_Index));
WriteRegByte(r_RDIndexedData, Value);
}
void
WriteMaskedRdReg(
ULONG Index,
BYTE Mask,
BYTE Value
)
{
// WriteMaskedRdReg
// Write only the specified bits of a indexed RAMDAC register. The index of
// the register, the value to write and the bits to mask out are specified.
// No Enter/Exit semantics for an inlined function.
WriteRegByte(r_RDIndexLow, (BYTE)(Index & b_RDIndexLow_Index));
WriteRegByte(r_RDIndexHigh, (BYTE)((Index >> 8) & b_RDIndexHigh_Index));
WriteRegByte(r_RDIndexedData, (BYTE)((ReadRegByte(r_RDIndexedData) & ~Mask) | (Value & Mask)));
}
BYTE
ReadRdReg(
ULONG Index
)
{
// ReadRdReg
// Read an indexed RAMDAC register. Index is specified, it's value returned.
// No Enter/Exit semantics for inlined functions.
WriteRegByte(r_RDIndexLow, (BYTE)(Index & b_RDIndexLow_Index));
WriteRegByte(r_RDIndexHigh, (BYTE)((Index >> 8) & b_RDIndexHigh_Index));
return (ReadRegByte(r_RDIndexedData));
}
BYTE
ReadMaskedRdReg(
ULONG Index,
BYTE Mask
)
{
// ReadMaskedRdReg
// This function allows us to read only the bits specified by a given mask
// from an indexed RAMDAC register specified by index. A 32 bit value is
// returned with 0s in all bits maksed off. The Enter/Exit routines are
// not used for inlined functions.
WriteRegByte(r_RDIndexLow, (BYTE)(Index & b_RDIndexLow_Index));
WriteRegByte(r_RDIndexHigh, (BYTE)((Index >> 8) & b_RDIndexHigh_Index));
return (ReadRegByte(r_RDIndexedData) & Mask);
}
void
WriteVgaReg(
ULONG Index,
BYTE Value
)
{
// WriteVgaReg
// This function is used to write to one of the indexed VGA sequencer
// registers on the Permedia3. The register's index, and the value to
// be written is passed. No Enter/Exit semantics for inlined functions.
WriteRegByte(r_SequencerIndexReg, (BYTE)(Index & b_SequencerIndexReg_Index));
WriteRegByte(r_SequencerDataReg, Value);
}
void
WriteMaskedVgaReg(
ULONG Index,
BYTE Mask,
BYTE Value
)
{
// WriteMaskedVgaReg
// Write only the specified bits of a indexed VGA sequencer register.
// The index of the register, the value to write and the bits to mask
// out are specified. No Enter/Exit semantics for an inlined function.
// Local variables.
BYTE MaskedValue;
WriteRegByte(r_SequencerIndexReg, (BYTE)(Index & b_SequencerIndexReg_Index));
MaskedValue = (BYTE)((ReadRegByte(r_SequencerDataReg) & ~Mask) | (Value & Mask));
WriteRegByte(r_SequencerIndexReg, (BYTE)(Index & b_SequencerIndexReg_Index));
WriteRegByte(r_SequencerDataReg, MaskedValue);
}
BYTE
ReadVgaReg(
ULONG Index
)
{
// ReadVgaReg
// Read an indexed VGA sequencer register. Index is specified, it's
// value returned. No Enter/Exit semantics for inlined functions.
WriteRegByte(r_SequencerIndexReg, (BYTE)(Index & b_SequencerIndexReg_Index));
return (ReadRegByte(r_SequencerDataReg));
}
BYTE
ReadMaskedVgaReg(
ULONG Index,
BYTE Mask
)
{
// ReadMaskedVgaReg
// This function allows us to read only the bits specified by a given mask
// from an indexed VGA sequencer register specified by index. A 32 bit
// value is returned with 0s in all bits maksed off. The Enter/Exit routines
// are not used for inlined functions.
WriteRegByte(r_SequencerIndexReg, (BYTE)(Index & b_SequencerIndexReg_Index));
return (ReadRegByte(r_SequencerDataReg) & Mask);
}
void
WaitForInputFIFO(
ULONG Writes
)
{
// WaitForInputFIFO
// This method polls the InFIFOSpace register to insure that there is
// sufficent space for a given number of register writes. Relies on the
// fact that the g_Region0Base pointer is volatile. No Enter/Exit
// semantics for inlined functions.
while (ReadRegUlong(r_InFIFOSpace) < Writes);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -