NT4/private/ntos/video/wd90c24a/ioaccess.h
2020-09-30 17:12:29 +02:00

592 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++ BUILD Version: 0002 // Increment this if a change has global effects
Copyright (c) 1989-91 Microsoft Corporation
Copyright (c) 1992 Digital Equipment Corporation
Module Name:
ioaccess.h
Abstract:
Definitions of function prototypes for accessing I/O ports and
memory on I/O adapters from user mode programs.
Cloned from parts of nti386.h.
Author:
--*/
#ifndef _IOACCESS_
#define _IOACCESS_
// Only define these prototypes if they're not already defined
#if defined (i386)
//
// I/O space read and write macros.
//
// These have to be actual functions on the 386, because we need
// to use assembler, but cannot return a value if we inline it.
//
// The READ/WRITE_REGISTER_* calls manipulate I/O registers in MEMORY space.
// (Use x86 move instructions, with LOCK prefix to force correct behavior
// w.r.t. caches and write buffers.)
//
// The READ/WRITE_PORT_* calls manipulate I/O registers in PORT space.
// (Use x86 in/out instructions.)
//
#define READ_REGISTER_UCHAR(Register) (*(PUCHAR)(Register))
#define READ_REGISTER_USHORT(Register) (*(PUSHORT)(Register))
#define READ_REGISTER_ULONG(Register) (*(PULONG)(Register))
#define WRITE_REGISTER_UCHAR(Register, Value) (*(volatile UCHAR *)(Register) = (Value))
#define WRITE_REGISTER_USHORT(Register, Value) (*(volatile USHORT *)(Register) = (Value))
#define WRITE_REGISTER_ULONG(Register, Value) (*(volatile ULONG *)(Register) = (Value))
#define READ_PORT_UCHAR(Port) inp (Port)
#define READ_PORT_USHORT(Port) inpw (Port)
#define WRITE_PORT_UCHAR(Port, Value) outp ((Port), (Value))
#define WRITE_PORT_USHORT(Port, Value) outpw ((Port), (Value))
#define MEMORY_BARRIER()
#endif // defined(i386)
#if defined (ALPHA)
//
// I/O space read and write macros.
//
// The READ/WRITE_REGISTER_* calls manipulate I/O registers in MEMORY space.
// (Use simple C macros. The caller is responsible for inserting memory
// barriers, as appropriate.)
//
// The READ/WRITE_PORT_* calls manipulate I/O registers in PORT space.
// (Use subroutine calls, since these are used less frequently than the
// register routines, and require more context.)
//
/*++
VOID
MEMORY_BARRIER(
VOID
)
Routine Description:
Execute an Alpha AXP MB instruction, to force pending writes
out to the bus.
Arguments:
None.
Return Value:
None.
--*/
#if defined(_MSC_VER)
#define MEMORY_BARRIER() __MB()
#else
#if defined(ACCASM) && !defined(__CPLUSPLUS)
long asm(const char *,...);
#pragma intrinsic(asm)
//
// ACC has a bug whereby an "asm" directive that occurs in a
// routine *before* any function calls, will bugcheck the
// compiler.
// Remove the following symbol definition when this is fixed.
//
#define ACC_ASM_BUG 1
#define MEMORY_BARRIER() asm("mb")
#endif // ACCASM
#endif // _MSC_VER
#if defined (JENSEN)
// JENSEN (ALPHA) Platform support
//
// Note that these macros are cloned from ...\ntos\hal\alpha.jxiouser.c.
//
// All these macros require that the calling argument is a QVA, such
// as would be returned by the wrapper around MmMapIoSpace - this should
// have QVA_ENABLE set. They assume the QVA represents an EISA address,
// and thus do NO CHECKING of this.
//
// Note that the argument is declared as PUCHAR or PUSHORT or
// whatever, even though it really is a QUASI_VIRTUAL_ADDRESS. This
// is for driver compatibility: all the drivers out there get a
// PVOID from MmMapIoSpace, then cast it to PU* before calling these
// routines. If we insisted on declaring them correctly, we would
// have to change all the drivers, which is what we are trying to avoid.
//
// Lane shifting: the Jensen box will not do lane shifting in EISA
// space. That means that for access shorter than a longword, the
// data will NOT show up in the lowest bit position, but will be in
// the byte/word that it would have started in. For longwords, the
// value will show up on the data path correctly. For, say, the 3rd
// byte in a word, a longword would be returned, and bytes 0, 1 and 3
// would be garbage, and the value in byte 2 would be the one you
// wanted. The same applies for writing: a longword will always be
// sent out onto the bus, and we must move the valid data byte into
// the correct position, and set the byte enables to say which byte
// to use. Note that what you cannot do is leave the byte in the
// lowest position, and set the byte enable to the lowest byte,
// because this would generate an unaligned longword access, which
// the chip cannot handle.
//
// So, for bytes, the access must be an aligned longword, with byte
// enables set to indicate which byte to get/set, and the byte moved
// to/from the desired position within the longword. Similarly for
// shorts. Tribytes are not supported.
//
#define EISA_BIT_SHIFT 0x07 // Bits to shift address
#define EISA_BYTE_LEN 0x00 // Byte length
#define EISA_WORD_LEN 0x20 // Word length
#define EISA_LONG_LEN 0x60 // LONGWORD length
#define QVA_ENABLE 0xA0000000 // If set, this is a QVA
#define EISA_QVA (QVA_ENABLE | 0x10000000)
/*++
UCHAR
READ_PORT_Usize(
volatile PUsize Port
)
Routine Description:
Read from the specified I/O port (CSR) address.
Note these macros do *not* perform a memory barrier. The
rationale for this is that reading from a CSR is informative,
rather than active. This is a weak rationale, but fits in OK
with the VGA driver. Trying to use this module for other
purposes may require the use of memory barriers.
Arguments:
Port - Supplies a pointer to the port in EISA I/O space.
Return Value:
Returns the value read from the specified port address.
--*/
#define READ_PORT_UCHAR READ_REGISTER_UCHAR
#define READ_PORT_USHORT READ_REGISTER_USHORT
#define READ_PORT_ULONG READ_REGISTER_ULONG
/*++
VOID
WRITE_PORT_Usize(
volatile PUsize Port,
Usize Value
)
Routine Description:
Write to the specified port (CSR) address.
Note we perform a memory barrier before we modify the CSR. The
rationale for this is that writing to a CSR clearly has active
effects, and thus all writes that take place before the CSR is
changed must be completed before the CSR change takes effect.
We also perform a memory barrier after we modify the CSR. The
rationale for this is that any writes which follow the CSR
modification may be affected by the change in state, and thus
must be ordered with respect to the CSR modification.
Note that if you're updating multiple CSRs in a row, there will
be more memory barriers than needed. Do we want another set of
macros to get around this?
The QUICK_WRITE_PORT_Usize functions perform the same functions
as their WRITE_PORT_Usize variants, except they do *not* execute
memory barriers. The invoker is responsible for using the
MEMORY_BARRIER function to synchronize with the write buffers and
cache.
Arguments:
Port - Supplies a pointer to the port in EISA I/O space.
Value - The value to be written to the port.
Return Value:
None
--*/
#define WRITE_PORT_UCHAR(Port,Value) \
( \
MEMORY_BARRIER(), \
WRITE_REGISTER_UCHAR ((Port), (Value)), \
MEMORY_BARRIER() \
)
#define QUICK_WRITE_PORT_UCHAR(Port,Value) \
WRITE_REGISTER_UCHAR ((Port), (Value))
#define WRITE_PORT_USHORT(Port,Value) \
( \
MEMORY_BARRIER(), \
WRITE_REGISTER_USHORT ((Port), (Value)), \
MEMORY_BARRIER() \
)
#define QUICK_WRITE_PORT_USHORT(Port,Value) \
WRITE_REGISTER_USHORT ((Port), (Value))
#define WRITE_PORT_ULONG(Port,Value) \
( \
MEMORY_BARRIER(), \
WRITE_REGISTER_ULONG ((Port), (Value)), \
MEMORY_BARRIER() \
)
#define QUICK_WRITE_PORT_ULONG(Port,Value) \
WRITE_REGISTER_ULONG ((Port), (Value))
/*++
UCHAR
READ_REGISTER_Usize(
volatile PUsize Register
)
Routine Description:
Read from the specified register address.
Arguments:
Register - Supplies a pointer to the register in EISA I/O space.
Return Value:
Returns the value read from the specified register address.
--*/
#define READ_REGISTER_UCHAR(Register) \
((UCHAR)((*(volatile ULONG *)((((ULONG)(Register) & ~(EISA_QVA) \
) << EISA_BIT_SHIFT) | EISA_BYTE_LEN)) >> (((ULONG)(Register) & 3) * 8)))
#define READ_REGISTER_USHORT(Register) \
((USHORT)((*(volatile ULONG *)((((ULONG)(Register) & ~(EISA_QVA) \
) << EISA_BIT_SHIFT) | EISA_WORD_LEN)) >> (((ULONG)(Register) & 3) * 8)))
#define READ_REGISTER_ULONG(Register) \
(*(volatile ULONG *)((((ULONG)(Register) & ~(EISA_QVA)) << EISA_BIT_SHIFT) | EISA_LONG_LEN))
/*++
VOID
WRITE_REGISTER_Usize(
volatile PUsize Register,
Usize Value
)
Routine Description:
Write to the specified register address.
Arguments:
Register - Supplies a pointer to the register in EISA I/O space.
Value - The value to be written to the register.
Return Value:
None
--*/
#define WRITE_REGISTER_UCHAR(Register,Value) \
(*(volatile ULONG *)((((ULONG)(Register) & ~(EISA_QVA)) << EISA_BIT_SHIFT) | EISA_BYTE_LEN) = \
(ULONG)((ULONG)(Value) << (((ULONG)(Register) & 3) * 8)))
#define WRITE_REGISTER_USHORT(Register,Value) \
(*(volatile ULONG *)((((ULONG)(Register) & ~(EISA_QVA)) << EISA_BIT_SHIFT) | EISA_WORD_LEN) = \
(ULONG)((ULONG)(Value) << (((ULONG)(Register) & 3) * 8)))
#define WRITE_REGISTER_ULONG(Register,Value) \
(*(volatile ULONG *)((((ULONG)(Register) & ~(EISA_QVA)) << EISA_BIT_SHIFT) | EISA_LONG_LEN) = \
(ULONG)(Value))
#else
#error // Unsupported ALPHA platform!
#endif // defined(JENSEN)
#endif // defined(ALPHA)
#if defined(MIPS)
//
// There is no such thing as a memory barrier on MIPS ...
//
#define MEMORY_BARRIER()
/*++
UCHAR
READ_WRITE_PORT_Usize(
volatile PUsize Port
)
Routine Description:
Read from the specified I/O port (CSR) address.
Note these macros do *not* perform a memory barrier. The
rationale for this is that reading from a CSR is informative,
rather than active. This is a weak rationale, but fits in OK
with the VGA driver. Trying to use this module for other
purposes may require the use of memory barriers.
Arguments:
Port - Supplies a pointer to the port in EISA I/O space.
Return Value:
Returns the value read from the specified port address.
--*/
#define READ_PORT_UCHAR(A) READ_REGISTER_UCHAR((PUCHAR)(A))
#define READ_PORT_USHORT(A) READ_REGISTER_USHORT((PUSHORT)(A))
#define READ_PORT_ULONG(A) READ_REGISTER_ULONG((PULONG)(A))
#define WRITE_PORT_UCHAR(A,V) WRITE_REGISTER_UCHAR((PUCHAR)(A),(UCHAR)(V))
#define WRITE_PORT_USHORT(A,V) WRITE_REGISTER_USHORT((PUSHORT)(A),(USHORT)(V))
#define WRITE_PORT_ULONG(A,V) WRITE_REGISTER_ULONG((PULONG)(A),(ULONG)(V))
/*++
UCHAR
READ_REGISTER_Usize(
volatile PUsize Register
)
Routine Description:
Read from the specified register address.
Arguments:
Register - Supplies a pointer to the register in EISA I/O space.
Return Value:
Returns the value read from the specified register address.
--*/
#define READ_REGISTER_UCHAR(x) \
(*(volatile UCHAR * const)(x))
#define READ_REGISTER_USHORT(x) \
(*(volatile USHORT * const)(x))
#define READ_REGISTER_ULONG(x) \
(*(volatile ULONG * const)(x))
/*++
VOID
WRITE_REGISTER_Usize(
volatile PUsize Register,
Usize Value
)
Routine Description:
Write to the specified register address.
Arguments:
Register - Supplies a pointer to the register in EISA I/O space.
Value - The value to be written to the register.
Return Value:
None
--*/
#define WRITE_REGISTER_UCHAR(x, y) \
(*(volatile UCHAR * const)(x) = (y))
#define WRITE_REGISTER_USHORT(x, y) \
(*(volatile USHORT * const)(x) = (y))
#define WRITE_REGISTER_ULONG(x, y) \
(*(volatile ULONG * const)(x) = (y))
#endif // defined(MIPS)
#if defined(_PPC_)
//
// There is no such thing as a memory barrier on PPC ...
//
#define MEMORY_BARRIER()
/*++
UCHAR
READ_WRITE_PORT_Usize(
volatile PUsize Port
)
Routine Description:
Read from the specified I/O port (CSR) address.
Note these macros do *not* perform a memory barrier. The
rationale for this is that reading from a CSR is informative,
rather than active. This is a weak rationale, but fits in OK
with the VGA driver. Trying to use this module for other
purposes may require the use of memory barriers.
Arguments:
Port - Supplies a pointer to the port in EISA I/O space.
Return Value:
Returns the value read from the specified port address.
--*/
#define READ_PORT_UCHAR(A) READ_REGISTER_UCHAR((PUCHAR)(A))
#define READ_PORT_USHORT(A) READ_REGISTER_USHORT((PUSHORT)(A))
#define READ_PORT_ULONG(A) READ_REGISTER_ULONG((PULONG)(A))
#define WRITE_PORT_UCHAR(A,V) WRITE_REGISTER_UCHAR((PUCHAR)(A),(UCHAR)(V))
#define WRITE_PORT_USHORT(A,V) WRITE_REGISTER_USHORT((PUSHORT)(A),(USHORT)(V))
#define WRITE_PORT_ULONG(A,V) WRITE_REGISTER_ULONG((PULONG)(A),(ULONG)(V))
/*++
UCHAR
READ_REGISTER_Usize(
volatile PUsize Register
)
Routine Description:
Read from the specified register address.
Arguments:
Register - Supplies a pointer to the register in EISA I/O space.
Return Value:
Returns the value read from the specified register address.
--*/
#define READ_REGISTER_UCHAR(x) \
(*(volatile UCHAR * const)(x))
#define READ_REGISTER_USHORT(x) \
(*(volatile USHORT * const)(x))
#define READ_REGISTER_ULONG(x) \
(*(volatile ULONG * const)(x))
/*++
VOID
WRITE_REGISTER_Usize(
volatile PUsize Register,
Usize Value
)
Routine Description:
Write to the specified register address.
Arguments:
Register - Supplies a pointer to the register in EISA I/O space.
Value - The value to be written to the register.
Return Value:
None
--*/
#define WRITE_REGISTER_UCHAR(x, y) \
(*(volatile UCHAR * const)(x) = (y))
#define WRITE_REGISTER_USHORT(x, y) \
(*(volatile USHORT * const)(x) = (y))
#define WRITE_REGISTER_ULONG(x, y) \
(*(volatile ULONG * const)(x) = (y))
#endif // defined(_PPC_)
#endif // _IOACCESS_