mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
366 lines
8.6 KiB
366 lines
8.6 KiB
/*++
|
|
|
|
Copyright (c) 1992, 1993, 1994 Corollary Inc.
|
|
|
|
Module Name:
|
|
|
|
cbdrivers.c
|
|
|
|
Abstract:
|
|
|
|
This Windows NT module creates a software-viewable table of the valid
|
|
element spaces present in a Corollary C-bus II machine. Since
|
|
searching through non-existent memory space can cause NMIs,
|
|
it is highly recommended that all areas needing this information
|
|
consult the built software table rather than rescanning themselves.
|
|
|
|
Author:
|
|
|
|
Landy Wang ([email protected]) 26-Mar-1992
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "cbus.h" // C-bus hardware architecture definitions
|
|
#include "cbus_nt.h" // C-bus NT-specific implementation #defines
|
|
|
|
VOID
|
|
CbusIOPresent(
|
|
IN ULONG Id,
|
|
IN ULONG IoFunction,
|
|
IN ULONG IoAttribute,
|
|
IN ULONG IoStart,
|
|
IN ULONG IoSize,
|
|
IN PVOID Csr
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,CbusIOPresent)
|
|
#endif
|
|
|
|
#define MIN(a,b) (((a)>(b))?(b):(a))
|
|
|
|
//
|
|
// C-bus II half-card device driver interface:
|
|
//
|
|
// this scheme allows a single driver can have multiple
|
|
// cards (ie: elements) present, and the single driver can
|
|
// support all of them.
|
|
//
|
|
// to identify what I/O devices exist on the Cbus2 bus, software
|
|
// would need to disable NMI, and check all element spaces for
|
|
// valid element_type IDs (ie: NOT 0xff == BUS_TIMEOUT). since this
|
|
// work is HIGHLY Cbus2 specific (poking the interrupt control
|
|
// registers, turning off fault-enables, etc), this will be done
|
|
// by our ROM and passed to the HAL.
|
|
//
|
|
// the kernel will build a software table of all elements,
|
|
// CbusIoElements[]. software can scan this table at any time,
|
|
// looking for specific io_type IDs. no entries in this table
|
|
// should ever change once the table has been initially built.
|
|
// in this way, other pieces of NT can determine what's in the
|
|
// machine without worrying about generating NMIs, etc, etc.
|
|
// this software still needs to be integrated into the registry.
|
|
//
|
|
// it is assumed drivers MUST use the same intr map lines on all
|
|
// CBCs where his cards are attached. ie: it is ILLEGAL for a
|
|
// SCSI driver to use local irq4 for CPU1's adapter 6 and local
|
|
// irq5 for CPU2's adapter 6.
|
|
//
|
|
// it is legal for CPU3's localirq 5 can be a SCSI, whilst CPU4's
|
|
// localirq 5 can be an SIO. we distinguish them in the kernel
|
|
// because SIO and SCSI will have different io_type IDs.
|
|
//
|
|
// public I/O devices, control I/O, Prog I/O space of each
|
|
// element is to be mapped in by the drivers themselves. the
|
|
// HAL will not do this. the driver is provided the physical
|
|
// start and length of each element space via CbusIoElements[].
|
|
// as described above. hence, no driver should scan global memory
|
|
// space searching for elements, which can cause NMIs, etc.
|
|
//
|
|
|
|
typedef struct _cbus_io_elements {
|
|
|
|
ULONG EntryLength;
|
|
ULONG ElementID;
|
|
ULONG ElementType;
|
|
ULONG IoAttribute;
|
|
ULONG AddressStart; // physical address in bytes
|
|
ULONG AddressLength; // length in bytes
|
|
ULONG CbcNumber; // BusNumber to drivers
|
|
PVOID Csr; // virtually mapped space
|
|
|
|
} CBUS_IO_ELEMENTS_T, *PCBUS_IO_ELEMENTS;
|
|
|
|
CBUS_IO_ELEMENTS_T CbusIoElements[MAX_ELEMENT_CSRS];
|
|
|
|
ULONG CbusIoElementIndex;
|
|
|
|
ULONG CBCIndex;
|
|
|
|
PVOID CbusCBCtoCSR(
|
|
IN ULONG CbcNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert the CBC number to a CSR pointer.
|
|
|
|
Arguments:
|
|
|
|
CbcNumber - Supplies the CBC number whose registers need to be accessed.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the CSR referenced by the argument CBC number, 0 if the
|
|
argument was invalid.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCBUS_IO_ELEMENTS p;
|
|
|
|
if (CbcNumber >= CBCIndex) {
|
|
return (PVOID)0;
|
|
}
|
|
|
|
for (p = CbusIoElements; p < &CbusIoElements[CbusIoElementIndex]; p++) {
|
|
if (p->CbcNumber == CbcNumber) {
|
|
return (PVOID)(p->Csr);
|
|
}
|
|
}
|
|
|
|
return (PVOID)0;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
CbusIOPresent(
|
|
IN ULONG Id,
|
|
IN ULONG IoFunction,
|
|
IN ULONG IoAttribute,
|
|
IN ULONG IoStart,
|
|
IN ULONG IoSize,
|
|
IN PVOID Csr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add the passed I/O entry to the table of Cbus I/O devices.
|
|
Note this table is for Cbus I/O devices only - EISA/ISA/MCA
|
|
devices are not part of this table.
|
|
|
|
This table containing all the elements is constructed so we can
|
|
give Cbus hardware drivers (and the rest of NT) meaningful information.
|
|
|
|
Arguments:
|
|
|
|
From - Supplies a pointer to the RRD source table
|
|
|
|
To - Supplies a pointer to the destination storage for the table
|
|
|
|
Return Value:
|
|
|
|
Number of valid table entries.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCBUS_IO_ELEMENTS p, q;
|
|
|
|
//
|
|
// If no room, can't register this I/O device. Should never happen.
|
|
//
|
|
|
|
if (CbusIoElementIndex < MAX_ELEMENT_CSRS) {
|
|
|
|
p = &CbusIoElements[CbusIoElementIndex];
|
|
|
|
//
|
|
// Storing the length field allows the HAL to add more
|
|
// information to an entry in the future, and still
|
|
// maintain compatibility with older driver binaries.
|
|
//
|
|
p->EntryLength = sizeof (CBUS_IO_ELEMENTS_T);
|
|
|
|
//
|
|
// Process valid elements - these may or may
|
|
// not have a CPU on the card, but all can be accessed
|
|
// from any CPU in the system. memory cards and processors
|
|
// are not included here - this is for device drivers only.
|
|
//
|
|
p->ElementID = Id;
|
|
p->ElementType = IoFunction;
|
|
p->IoAttribute = IoAttribute;
|
|
p->AddressStart = IoStart;
|
|
p->AddressLength = IoSize;
|
|
p->Csr = Csr;
|
|
|
|
//
|
|
// More than one I/O element may share a single CBC.
|
|
// This is handled right here.
|
|
//
|
|
for (q = CbusIoElements; q < p; q++) {
|
|
if (q->ElementID == Id) {
|
|
p->CbcNumber = q->CbcNumber;
|
|
break;
|
|
}
|
|
}
|
|
if (q == p) {
|
|
p->CbcNumber = CBCIndex++;
|
|
}
|
|
|
|
CbusIoElementIndex++;
|
|
}
|
|
}
|
|
|
|
|
|
ULONG
|
|
Cbus2GetCbusData(
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN ULONG SlotNumber,
|
|
IN PVOID Buffer,
|
|
IN ULONG Offset,
|
|
IN ULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The function returns the Corollary Cbus data for a slot or address.
|
|
Drivers will be expected to call this function repeatedly with
|
|
incrementing BusNumbers & SlotNumbers, until this function returns 0,
|
|
indicating that the last slot has been read. Only one slot is
|
|
allowed per bus, with each I/O CBC representing a "bus". This is
|
|
necessary for interrupt vector allocation since slot numbers are
|
|
not passed into GetInterruptVector()...
|
|
|
|
Each chunk of slot data should then be examined by the driver.
|
|
The driver may skip any chunk that doesn't belong to him.
|
|
Once a chunk is encountered that belongs to him, the CBCNumber
|
|
field must be treated as the "Cbus BusNumber" (it's really a CBC number,
|
|
not including the CBCs of the EISA bridges), to pass in when he asks for
|
|
an interrupt vector via HalGetInterruptVector().
|
|
|
|
Arguments:
|
|
|
|
BusNumber - Indicates which bus.
|
|
|
|
SlotNumber - Indicates which entry.
|
|
|
|
Buffer - Supplies the space to store the data.
|
|
|
|
Length - Supplies a count in bytes of the maximum amount to return.
|
|
|
|
Return Value:
|
|
|
|
Returns the amount of data stored into the buffer.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG BusNumber = RootHandler->BusNumber;
|
|
PUCHAR From;
|
|
ULONG MaxLength;
|
|
|
|
//
|
|
// let our caller know when he's hit the end
|
|
//
|
|
|
|
if (BusNumber >= CbusIoElementIndex) {
|
|
return 0;
|
|
}
|
|
|
|
if (SlotNumber != 0) {
|
|
return 0;
|
|
}
|
|
|
|
From = (PUCHAR)(CbusIoElements + BusNumber);
|
|
MaxLength = (CbusIoElementIndex - BusNumber) * sizeof (CBUS_IO_ELEMENTS_T);
|
|
|
|
if (Offset >= MaxLength) {
|
|
return 0;
|
|
}
|
|
|
|
if (Length+Offset > MaxLength) {
|
|
Length = MaxLength - Offset;
|
|
}
|
|
|
|
RtlMoveMemory(Buffer, From+Offset, Length);
|
|
|
|
return Length;
|
|
}
|
|
|
|
|
|
ULONG
|
|
Cbus2SetCbusData(
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN ULONG SlotNumber,
|
|
IN PVOID Buffer,
|
|
IN ULONG Offset,
|
|
IN ULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The function sets the Corollary Cbus data for a slot or address.
|
|
|
|
Arguments:
|
|
|
|
BusNumber - Indicates which bus.
|
|
|
|
SlotNumber - Indicates which entry.
|
|
|
|
Buffer - Supplies the space to store the data.
|
|
|
|
Length - Supplies a count in bytes of the maximum amount to return.
|
|
|
|
Return Value:
|
|
|
|
Returns the amount of data stored into the buffer.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG BusNumber = RootHandler->BusNumber;
|
|
PUCHAR To;
|
|
ULONG MaxLength;
|
|
|
|
//
|
|
// don't allow writes beyond the end
|
|
//
|
|
if (BusNumber >= CbusIoElementIndex) {
|
|
return 0;
|
|
}
|
|
|
|
if (SlotNumber != 0) {
|
|
return 0;
|
|
}
|
|
|
|
To = (PUCHAR)(CbusIoElements + BusNumber);
|
|
MaxLength = (CbusIoElementIndex - BusNumber) * sizeof (CBUS_IO_ELEMENTS_T);
|
|
|
|
if (Offset >= MaxLength) {
|
|
return 0;
|
|
}
|
|
|
|
if (Length+Offset > MaxLength) {
|
|
Length = MaxLength - Offset;
|
|
}
|
|
|
|
RtlMoveMemory(To+Offset, Buffer, Length);
|
|
|
|
return Length;
|
|
}
|