972 lines
20 KiB
C
972 lines
20 KiB
C
#if defined (JENSEN)
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1992 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
jxioacc.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the Jensen I/O space access routines for user mode
|
||
mapped addresses.
|
||
|
||
The READ_PORT_Uxxx MACROs simply call the equivalent READ_REGISTER_Uxxx
|
||
routine. Similarly, the WRITE_PORT_Uxxx MACROs call the equivalent
|
||
WRITE_REGISTER_Uxxx routines. Since Jensen uses 64 bit super pages for
|
||
Virtual I/O, and that super pages are only accessable through kernel
|
||
mode, these routines here will decode a QVA and do the access, but
|
||
through normal translations.
|
||
|
||
All these routines ensure that the calling argument is a QVA, such
|
||
as would be returned by the wrapper around MmMapIoSpace - this should
|
||
have QVA_ENABLE set. They determine which type of shift should be
|
||
used, based on the next bit in the longword.
|
||
|
||
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.
|
||
|
||
Lane shifting is not an issue for accessing the Combo chip, which
|
||
only allows byte accesses, and for which the data is always moved
|
||
to the low 8 bits of the HBUS data longword, according to the spec.
|
||
|
||
Performance: If the buffer routines get used alot, something we
|
||
could do to improve performance would be to send four byte or two
|
||
shorts out to the bus at a time (or get them). This would work
|
||
because the PIC queries the device about the size of transfer that
|
||
it can accept (or the device rejects a transfer that it cannot
|
||
handle) and parcels the data out in correct size chunks.
|
||
|
||
Author:
|
||
|
||
Rod N. Gamache (DEC) 5-May-1992
|
||
Miche Baker-Harvey (miche) 21-May-1992
|
||
Jeff McLeman (DEC) 30-Jul-1992
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
// Include files
|
||
|
||
#include "halp.h"
|
||
#include "jnsndef.h"
|
||
|
||
|
||
UCHAR
|
||
READ_REGISTER_UCHAR(
|
||
volatile PUCHAR 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG mv; // Local value
|
||
ULONG byte; // which byte we want
|
||
volatile PULONG ma; // Local address
|
||
|
||
HalpMb;
|
||
|
||
//
|
||
// If it's an EISA address, use EISA shifts, byte enables
|
||
//
|
||
|
||
if (IS_EISA_QVA(Register)) {
|
||
|
||
//
|
||
// Determine which byte it is that we want.
|
||
//
|
||
|
||
byte = (ULONG)Register & 0x3;
|
||
|
||
//
|
||
// Shift the virtual address into position, and indicate that
|
||
// we want a byte.
|
||
//
|
||
// The desired byte enable is set automatically because the
|
||
// Jensen designers picked values which correspond exactly
|
||
// to the actual byte addresses
|
||
//
|
||
|
||
ma = (volatile PULONG)
|
||
(EISA_BYTE_LEN | ((ULONG)Register << EISA_BIT_SHIFT));
|
||
|
||
//
|
||
// Get the longword value, which will only have one valid byte
|
||
//
|
||
|
||
mv = *ma;
|
||
|
||
//
|
||
// Extract out and return the desired byte
|
||
// The compiler should convert the multiplication
|
||
//
|
||
|
||
return((UCHAR)(mv >> (byte * 8)));
|
||
|
||
}
|
||
|
||
//
|
||
// If it's a Combo Chip address, use those shifts, byte enables
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Register)) {
|
||
return ((UCHAR)(*(volatile PULONG )(COMBO_BYTE_LEN |
|
||
((ULONG)Register << COMBO_BIT_SHIFT))));
|
||
}
|
||
|
||
//
|
||
// It's not a valid QVA
|
||
//
|
||
|
||
KeBugCheck("Invalid QVA in READ_REGISTER_UCHAR\n");
|
||
}
|
||
|
||
|
||
|
||
USHORT
|
||
READ_REGISTER_USHORT(
|
||
volatile PUSHORT 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG mv, word; // Local value and word we want
|
||
volatile PULONG ma; // Local address
|
||
|
||
//
|
||
// This works as long as we don't want the fourth short!
|
||
//
|
||
ASSERT(((ULONG)Register & 0x3) != 0x3);
|
||
|
||
//
|
||
// If it's an EISA address, use EISA shifts, word enables
|
||
//
|
||
|
||
if (IS_EISA_QVA(Register)) {
|
||
|
||
//
|
||
// Determine which word it is that we want.
|
||
//
|
||
|
||
word = (ULONG)Register & 0x3;
|
||
|
||
//
|
||
// Shift the virtual address into position, and indicate that
|
||
// we want a word.
|
||
//
|
||
// The desired word enable is set automatically because the
|
||
// Jensen designers picked values which correspond exactly
|
||
// to the actual word addresses
|
||
//
|
||
|
||
ma = (volatile PULONG)
|
||
(EISA_WORD_LEN | ((ULONG)Register << EISA_BIT_SHIFT));
|
||
|
||
//
|
||
// Get the longword value, which will only have one valid word
|
||
//
|
||
|
||
mv = *ma;
|
||
|
||
//
|
||
// Extract out and return the desired word
|
||
// The compiler should convert the multiplication
|
||
//
|
||
|
||
return((USHORT)(mv >> (8 * word)));
|
||
|
||
}
|
||
|
||
//
|
||
// USHORT operations are not supported on the combo chip
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Register)) {
|
||
|
||
KeBugCheck("Invalid Combo QVA in READ_REGISTER_USHORT\n");
|
||
}
|
||
|
||
KeBugCheck("Invalid QVA in READ_REGISTER_USHORT\n");
|
||
}
|
||
|
||
|
||
ULONG
|
||
READ_REGISTER_ULONG(
|
||
volatile PULONG 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// We are assuming that the longword is aligned
|
||
//
|
||
ASSERT(((ULONG)Register & 0x3) == 0x0);
|
||
|
||
if (IS_EISA_QVA(Register)) {
|
||
|
||
HalpMb;
|
||
return (*(volatile PULONG)(EISA_LONG_LEN |
|
||
((ULONG)Register << EISA_BIT_SHIFT)));
|
||
|
||
}
|
||
|
||
//
|
||
// ULONG operations are not supported on the combo chip
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Register)) {
|
||
|
||
KeBugCheck("Invalid Combo QVA in READ_REGISTER_ULONG\n");
|
||
}
|
||
|
||
KeBugCheck("Invalid QVA in READ_REGISTER_ULONG\n");
|
||
}
|
||
|
||
|
||
VOID
|
||
WRITE_REGISTER_UCHAR(
|
||
volatile PUCHAR Register,
|
||
UCHAR 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
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG mv; // local copy of value for shifting
|
||
ULONG byte; // the byte position requested
|
||
|
||
//
|
||
// If it's an EISA address, use EISA shifts, byte enables
|
||
//
|
||
|
||
if (IS_EISA_QVA(Register)) {
|
||
|
||
//
|
||
// Determine which byte it is that we want.
|
||
//
|
||
|
||
byte = (ULONG)Register & 0x3;
|
||
|
||
//
|
||
// Move value into appropriate byte position in longword
|
||
// The compiler should convert the multiplication
|
||
//
|
||
|
||
mv = (ULONG)(Value << (8 * byte));
|
||
|
||
//
|
||
// The address is long aligned and the byte enables set
|
||
// automagically by the way the Jensen physical map is set
|
||
//
|
||
*(volatile PULONG)(EISA_BYTE_LEN |
|
||
((ULONG)Register << EISA_BIT_SHIFT)) = mv;
|
||
HalpMb;
|
||
return;
|
||
}
|
||
|
||
//
|
||
// If it's a Combo Chip address, use those shifts, byte enables
|
||
// No lane shifting is required for the Combo chip.
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Register)) {
|
||
|
||
*(volatile PULONG)(COMBO_BYTE_LEN |
|
||
((ULONG)Register << COMBO_BIT_SHIFT)) = Value;
|
||
HalpMb;
|
||
return;
|
||
}
|
||
|
||
//
|
||
// It's not a valid QVA
|
||
//
|
||
|
||
KeBugCheck("Invalid QVA in WRITE_REGISTER_UCHAR\n");
|
||
}
|
||
|
||
|
||
VOID
|
||
WRITE_REGISTER_USHORT(
|
||
volatile PUSHORT Register,
|
||
USHORT 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
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG mv; // local copy of value for shifting
|
||
UCHAR word; // the word position requested
|
||
|
||
//
|
||
// This works as long as we don't want the fourth short!
|
||
//
|
||
ASSERT(((ULONG)Register & 0x3) != 0x3);
|
||
|
||
//
|
||
// If it's an EISA address, use EISA shifts, word enables
|
||
//
|
||
|
||
if (IS_EISA_QVA(Register)) {
|
||
|
||
|
||
//
|
||
// Determine which word it is that we want.
|
||
//
|
||
|
||
word = (ULONG)Register & 0x3;
|
||
|
||
//
|
||
// Move value into appropriate word position in longword
|
||
// The compiler should convert the multiplication
|
||
//
|
||
|
||
mv = (ULONG)(Value << (8 * word));
|
||
|
||
//
|
||
// The address is long aligned and the word enables set
|
||
// automagically by the way the Jensen physical map is set
|
||
//
|
||
|
||
*(volatile PULONG)(EISA_WORD_LEN |
|
||
((ULONG)Register << EISA_BIT_SHIFT)) = mv;
|
||
HalpMb;
|
||
return;
|
||
}
|
||
|
||
//
|
||
// USHORT operations are not supported on the combo chip
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Register)) {
|
||
|
||
KeBugCheck("Invalid Combo QVA in WRITE_REGISTER_USHORT\n");
|
||
}
|
||
|
||
KeBugCheck("Invalid QVA in WRITE_REGISTER_USHORT\n");
|
||
}
|
||
|
||
|
||
VOID
|
||
WRITE_REGISTER_ULONG(
|
||
volatile PULONG Register,
|
||
ULONG 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
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// We are assuming that the longword is aligned
|
||
//
|
||
ASSERT(((ULONG)Register & 0x3) == 0x0);
|
||
|
||
if (IS_EISA_QVA(Register)) {
|
||
|
||
*(volatile PULONG)(EISA_LONG_LEN |
|
||
((ULONG)Register << EISA_BIT_SHIFT)) = Value;
|
||
HalpMb;
|
||
return;
|
||
}
|
||
|
||
//
|
||
// ULONG operations are not supported on the combo chip
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Register)) {
|
||
|
||
KeBugCheck("Invalid Combo QVA in WRITE_REGISTER_ULONG\n");
|
||
}
|
||
|
||
KeBugCheck("Invalid QVA in WRITE_REGISTER_ULONG\n");
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
READ_PORT_BUFFER_UCHAR(
|
||
volatile PUCHAR Port,
|
||
PUCHAR Buffer,
|
||
ULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Read from the specified port buffer address.
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies a pointer to the port in EISA space.
|
||
Buffer - the address of the buffer in memory to copy the data to.
|
||
Count - the number of bytes to move.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, mv;
|
||
volatile PULONG ma;
|
||
ULONG byte;
|
||
|
||
HalpMb;
|
||
if (IS_EISA_QVA(Port)) {
|
||
|
||
//
|
||
// Shift the virtual address into position, and indicate that
|
||
// we want a byte.
|
||
//
|
||
// The desired byte enable is set automatically because the
|
||
// Jensen designers picked values which correspond exactly
|
||
// to the actual byte addresses
|
||
//
|
||
|
||
ma = (volatile PULONG)
|
||
(EISA_BYTE_LEN | ((ULONG)Port << EISA_BIT_SHIFT));
|
||
|
||
for ( i = 0 ; i < Count ; i++) {
|
||
|
||
//
|
||
// Determine which byte it is that we want.
|
||
//
|
||
|
||
byte = (ULONG)ma & (0x3 << EISA_BIT_SHIFT);
|
||
|
||
//
|
||
// Get the longword value, which will only have one valid byte
|
||
//
|
||
|
||
mv = *ma;
|
||
|
||
//
|
||
// Extract out the desired byte
|
||
// The compiler should convert the multiplication
|
||
//
|
||
|
||
*Buffer++ = ((UCHAR)(mv >> (8 * byte)));
|
||
|
||
|
||
}
|
||
|
||
} else if (IS_COMBO_QVA(Port)) {
|
||
|
||
ma = (volatile PULONG) (COMBO_BYTE_LEN |
|
||
((ULONG)Port << COMBO_BIT_SHIFT));
|
||
for ( i = 0 ; i < Count ; i++) {
|
||
*Buffer++ = *ma;
|
||
ma = (PULONG)((PUCHAR)ma + COMBO_BYTE_OFFSET);
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Invalid QVA
|
||
//
|
||
KeBugCheck("Invalid QVA in READ_PORT_BUFFER_UCHAR\n");
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
READ_PORT_BUFFER_USHORT(
|
||
volatile PUSHORT Port,
|
||
PUSHORT Buffer,
|
||
ULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Read from the specified port buffer address.
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies a pointer to the port in EISA space.
|
||
Buffer - the address of the buffer in memory to copy the data to.
|
||
Count - the number of shorts to move.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, mv;
|
||
volatile PULONG ma;
|
||
ULONG word;
|
||
|
||
//
|
||
// The code gets really ugly if shorts are not aligned!
|
||
//
|
||
ASSERT(((ULONG)Port & 0x1) == 0x0);
|
||
|
||
if (IS_EISA_QVA(Port)) {
|
||
|
||
HalpMb;
|
||
|
||
//
|
||
// Shift the virtual address into position, and indicate that
|
||
// we want a word.
|
||
//
|
||
// The desired word enable is set automatically because the
|
||
// Jensen designers picked values which correspond exactly
|
||
// to the actual word addresses
|
||
//
|
||
|
||
ma = (volatile PULONG)
|
||
(EISA_WORD_LEN | ((ULONG)Port << EISA_BIT_SHIFT));
|
||
|
||
for ( i = 0 ; i < Count ; i++) {
|
||
|
||
//
|
||
// Determine which word it is that we want; the low
|
||
// order bit cannot be set.
|
||
//
|
||
|
||
word = (ULONG)ma & (0x2 << EISA_BIT_SHIFT);
|
||
|
||
//
|
||
// Get the longword value, which will only have one valid word
|
||
//
|
||
|
||
mv = *ma;
|
||
|
||
//
|
||
// Extract out the desired word
|
||
// The compiler should convert the multiplication
|
||
//
|
||
|
||
*Buffer++ = ((USHORT)(mv >> (8 * word)));
|
||
|
||
|
||
}
|
||
return;
|
||
}
|
||
|
||
//
|
||
// USHORT operations are not supported on the combo chip
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Port)) {
|
||
|
||
KeBugCheck("Invalid Combo QVA in READ_PORT_BUFFER_USHORT\n");
|
||
}
|
||
|
||
KeBugCheck("Invalid QVA in READ_PORT_BUFFER_USHORT\n");
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
READ_PORT_BUFFER_ULONG(
|
||
volatile PULONG Port,
|
||
PULONG Buffer,
|
||
ULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Read from the specified port address.
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies a pointer to the port in EISA space.
|
||
Buffer - the address of the buffer in memory to copy the data to.
|
||
Count - the number of longs to move.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
volatile PULONG ptr;
|
||
|
||
//
|
||
// We are assuming that the longword is aligned
|
||
//
|
||
ASSERT(((ULONG)Port & 0x3) == 0x0);
|
||
|
||
if (IS_EISA_QVA(Port)) {
|
||
HalpMb;
|
||
ptr = (volatile ULONG *) (EISA_LONG_LEN |
|
||
((ULONG)Port << EISA_BIT_SHIFT));
|
||
for ( i = 0 ; i < Count ; i++) {
|
||
*Buffer++ = *ptr;
|
||
}
|
||
return;
|
||
}
|
||
|
||
//
|
||
// ULONG operations are not supported on the combo chip
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Port)) {
|
||
|
||
KeBugCheck("Invalid Combo QVA in READ_PORT_BUFFER_ULONG\n");
|
||
}
|
||
|
||
KeBugCheck("Invalid QVA in READ_PORT_BUFFER_ULONG\n");
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
WRITE_PORT_BUFFER_UCHAR(
|
||
volatile PUCHAR Port,
|
||
PUCHAR Buffer,
|
||
ULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Write to the specified port buffer address.
|
||
|
||
If the Port and Buffer addresses are aligned with respect to each
|
||
other, we don't have to do a shift on each move - which would be a
|
||
bit faster. On the other hand, no one calls this routine, and it
|
||
would be more complicated to handle the two cases, so let it be.
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies a pointer to the port in EISA space.
|
||
Buffer - the address of the buffer in memory to copy the data from.
|
||
Count - the number of bytes to move.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, mv;
|
||
volatile PULONG ma;
|
||
ULONG byte;
|
||
|
||
|
||
if (IS_EISA_QVA(Port)) {
|
||
|
||
ma = (volatile PULONG) (EISA_BYTE_LEN |
|
||
((ULONG)Port << EISA_BIT_SHIFT));
|
||
|
||
for ( i = 0 ; i < Count ; i++) {
|
||
|
||
//
|
||
// Determine which byte it is that we want to write to
|
||
// This changes with every byte written.
|
||
//
|
||
|
||
byte = (ULONG)ma & (0x3 << EISA_BIT_SHIFT);
|
||
|
||
//
|
||
// Move value into appropriate byte position in longword,
|
||
// and advance our position in the buffer.
|
||
// The compiler should convert the multiplication
|
||
//
|
||
|
||
mv = (ULONG)(*Buffer << (8 * byte));
|
||
Buffer++;
|
||
|
||
//
|
||
// send the lane shifted value to the EISA bus
|
||
//
|
||
|
||
*ma = mv;
|
||
|
||
}
|
||
|
||
HalpMb;
|
||
return;
|
||
}
|
||
|
||
if (IS_COMBO_QVA(Port)) {
|
||
|
||
ma = (volatile PULONG) (COMBO_BYTE_LEN |
|
||
((ULONG)Port << COMBO_BIT_SHIFT));
|
||
for ( i = 0 ; i < Count ; i++) {
|
||
*ma = *Buffer++;
|
||
ma = (PULONG)((PUCHAR)ma + COMBO_BYTE_OFFSET);
|
||
}
|
||
HalpMb;
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// Invalid QVA
|
||
//
|
||
KeBugCheck("Invalid QVA in WRITE_PORT_BUFFER_UCHAR\n");
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
WRITE_PORT_BUFFER_USHORT(
|
||
volatile PUSHORT Port,
|
||
PUSHORT Buffer,
|
||
ULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Write to the specified port buffer address.
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies a pointer to the port in EISA space.
|
||
Buffer - the address of the buffer in memory to copy the data from.
|
||
Count - the number of shorts to move.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, mv;
|
||
volatile PULONG ma;
|
||
ULONG word;
|
||
|
||
//
|
||
// The code gets really ugly if shorts are not aligned!
|
||
//
|
||
ASSERT(((ULONG)Port & 0x1) == 0x0);
|
||
|
||
if (IS_EISA_QVA(Port)) {
|
||
|
||
ma = (volatile PULONG) (EISA_WORD_LEN |
|
||
((ULONG)Port << EISA_BIT_SHIFT));
|
||
|
||
for ( i = 0 ; i < Count ; i++) {
|
||
|
||
//
|
||
// Determine which word it is that we want to write to
|
||
// This changes with every word written.
|
||
//
|
||
|
||
word = (ULONG)ma & (0x2 << EISA_BIT_SHIFT);
|
||
|
||
//
|
||
// Move value into appropriate word position in longword,
|
||
// and advance our position in the buffer.
|
||
// The compiler should convert the multiplication
|
||
//
|
||
|
||
mv = (ULONG)(*Buffer++ << (8 * word));
|
||
|
||
//
|
||
// send the lane shifted value to the EISA bus
|
||
//
|
||
|
||
*ma = mv;
|
||
|
||
}
|
||
|
||
HalpMb;
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// USHORT operations are not supported on the combo chip
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Port)) {
|
||
|
||
KeBugCheck("Invalid Combo QVA in WRITE_PORT_BUFFER_USHORT\n");
|
||
}
|
||
|
||
KeBugCheck("Invalid QVA in WRITE_PORT_BUFFER_USHORT\n");
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
WRITE_PORT_BUFFER_ULONG(
|
||
volatile PULONG Port,
|
||
PULONG Buffer,
|
||
ULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Write to teh specified port buffer address.
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies a pointer to the port in EISA space.
|
||
Buffer - the address of the buffer in memory to copy the data from.
|
||
Count - the number of longs to move.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
volatile PULONG ptr;
|
||
|
||
//
|
||
// We are assuming that the port address is long aligned
|
||
//
|
||
ASSERT(((ULONG)Port & 0x3) == 0x0);
|
||
|
||
if (IS_EISA_QVA(Port)) {
|
||
ptr = (volatile ULONG *) (EISA_LONG_LEN |
|
||
((ULONG)Port << EISA_BIT_SHIFT));
|
||
for ( i = 0 ; i < Count ; i++) {
|
||
*ptr = *Buffer++;
|
||
}
|
||
HalpMb;
|
||
return;
|
||
}
|
||
|
||
//
|
||
// ULONG operations are not supported on the combo chip
|
||
//
|
||
|
||
if (IS_COMBO_QVA(Port)) {
|
||
|
||
KeBugCheck("Invalid Combo QVA in WRITE_PORT_BUFFER_ULONG\n");
|
||
}
|
||
|
||
KeBugCheck("Invalid QVA in WRITE_PORT_BUFFER_ULONG\n");
|
||
|
||
}
|
||
#endif // JENSEN
|