Leaked source code of windows server 2003
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.
 
 
 
 
 
 

664 lines
16 KiB

/*++
Copyright (c) 1991 - 2001 Microsoft Corporation
Module Name:
### ## # ## ## # ## ## ##### ### ## ## #### ##### #####
## # ## ### ## ### # ## ## ## ## ### ### ### ## # ## ## ## ##
### ## ### ## #### # ## ## ## ## ## ## ######## ## ## ## ## ##
### ## # # ## # #### #### ##### ## ## # ### ## ## ## ## ## ##
### ### ### # ### #### #### ####### # # ## ## ##### #####
# ## ### ### # ## ## ## ## ## ## # ## ## ## # ## ##
### ## ## # # ## ## ## ## ## # ## ## #### ## ##
Abstract:
This module contains the entire implementation of
the NVRAM miniport for the ServerWorks
CSB5 server chip set.
Author:
Wesley Witt (wesw) 1-Oct-2001
Environment:
Kernel mode only.
Notes:
--*/
#include "swnvram.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#endif
#define CLEARBITS(_val,_mask) ((_val) &= ~(_mask))
#define SETBITS(_val,_mask) ((_val) |= (_mask))
BOOLEAN
SaNvramStartNextIo(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This function is called by the ISR and the StartIo functions.
The purpose is to modify the device's hardware registers
such that the next I/O is started on the device.
Arguments:
DeviceExtension - A pointer to the mini-port's device extension
Context:
IRQL: DISPATCH_LEVEL or DIRQL, arbitrary thread context
Return Value:
A value of TRUE is returned if the I/O is started successfully.
Otherwise a value of FALSE is returned.
--*/
{
USHORT Control;
//
// This function executes at DIRQL and it synchronized
// with the ISR.
//
//
// Read the current value of the NVRAM address register
//
Control = READ_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase );
if (Control & NVRAM_CONTROL_BUSY) {
//
// This should never happen, but the device us telling
// us that it is busy.
//
return FALSE;
}
//
// Setup the device for the I/O
//
//
// Clear the Function code
//
CLEARBITS( Control, NVRAM_CONTROL_FUNCTION_CODE );
switch (DeviceExtension->IoFunction) {
case IRP_MJ_WRITE:
//
// Stuff the next dword into the data register
//
WRITE_REGISTER_ULONG(
(PULONG)(DeviceExtension->NvramMemBase+4),
DeviceExtension->IoBuffer[DeviceExtension->IoIndex]
);
//
// Set the bit to indicate a write
//
SETBITS( Control, NVRAM_CONTROL_FUNCTION_WRITE );
break;
case IRP_MJ_READ:
//
// Set the bit to indicate a read
//
SETBITS( Control, NVRAM_CONTROL_FUNCTION_READ );
break;
default:
return FALSE;
}
//
// Clear the I/O address
//
CLEARBITS( Control, NVRAM_CONTROL_ADDRESS );
//
// Set the requested I/O address
//
Control = Control | (USHORT) (DeviceExtension->IoOffset + DeviceExtension->IoIndex);
//
// Write the new control value to the address register
//
WRITE_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase, Control );
return TRUE;
}
BOOLEAN
SaNvramInterruptService(
IN PKINTERRUPT InterruptObject,
IN PVOID ServiceContext
)
/*++
Routine Description:
This function is the device's interrupt service routine and
is called by the OS to service the interrupt. The interrupt
spin lock is held so work here is kept to a minimum.
Arguments:
InterruptObject - Pointer to an interrupt object.
DeviceExtension - Pointer to the mini-port's device extension
Context:
IRQL: DIRQL, arbitrary thread context
Return Value:
A value of TRUE is returned if the interrupt is serviced by
this function. Otherwise a value of FALSE is returned.
--*/
{
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) ServiceContext;
USHORT Control;
//
// First thing is to check the DONE bit in the NVRAM address register.
// This bit indicates that the device has completed a previous
// command request. This tells the ISR that the interrupt was
// likely generated by the NVRAM device.
//
Control = READ_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase );
if ((Control & NVRAM_CONTROL_DONE) == 0) {
return FALSE;
}
//
// Now the interrupt must be stopped.
// This is accomplished by setting the done
// bit and clearing the function code.
//
CLEARBITS( Control, NVRAM_CONTROL_FUNCTION_CODE );
SETBITS( Control, NVRAM_CONTROL_DONE );
WRITE_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase, Control );
//
// Check to see if this is a bogus interrupt
//
if (DeviceExtension->IoIndex >= DeviceExtension->IoLength) {
return FALSE;
}
//
// Process the I/O
//
if (DeviceExtension->IoFunction == IRP_MJ_READ) {
//
// Fetch the double word value from the NVRAM data register
//
DeviceExtension->IoBuffer[DeviceExtension->IoIndex] = READ_REGISTER_ULONG( (PULONG)(DeviceExtension->NvramMemBase+4) );
}
DeviceExtension->IoIndex += 1;
DeviceExtension->CompletedIoSize += sizeof(ULONG);
if (DeviceExtension->IoIndex >= DeviceExtension->IoLength) {
//
// We're done so we need to have the DPC start the next I/O
//
SaPortRequestDpc( DeviceExtension, NULL );
} else {
//
// More I/O necessary so request the device start the next I/O
//
if (!SaNvramStartNextIo( DeviceExtension )) {
//
// Something failed so be sure that the next I/O is started
//
SaPortRequestDpc( DeviceExtension, NULL );
}
}
return TRUE;
}
NTSTATUS
SaNvramRead(
IN PVOID DeviceExtensionIn,
IN PIRP Irp,
IN PVOID FsContext,
IN LONGLONG StartingOffset,
IN PVOID DataBuffer,
IN ULONG DataBufferLength
)
/*++
Routine Description:
This routine processes the read requests for the local display miniport.
Arguments:
DeviceExtensionIn - Miniport's device extension
StartingOffset - Starting offset for the I/O
DataBuffer - Pointer to the data buffer
DataBufferLength - Length of the data buffer in bytes
Return Value:
NT status code.
--*/
{
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
//
// Validate the I/O parameters
//
if (((StartingOffset + DataBufferLength) / sizeof(ULONG)) > MAX_NVRAM_SIZE) {
REPORT_ERROR( SA_DEVICE_NVRAM, "Starting offset is too large\n", STATUS_INVALID_PARAMETER_1 );
return STATUS_INVALID_PARAMETER_1;
}
//
// Save the I/O parameters
//
DeviceExtension->IoBuffer = (PULONG)DataBuffer;
DeviceExtension->IoLength = DataBufferLength / sizeof(ULONG);
DeviceExtension->IoFunction = IRP_MJ_READ;
DeviceExtension->IoOffset = (ULONG) (StartingOffset / sizeof(ULONG));
DeviceExtension->IoIndex = 0;
DeviceExtension->CompletedIoSize = 0;
//
// Start the I/O
if (!SaNvramStartNextIo( DeviceExtension )) {
REPORT_ERROR( SA_DEVICE_NVRAM, "SaNvramStartNextIo failed\n", STATUS_UNSUCCESSFUL );
return STATUS_UNSUCCESSFUL;
}
return STATUS_PENDING;
}
NTSTATUS
SaNvramWrite(
IN PVOID DeviceExtensionIn,
IN PIRP Irp,
IN PVOID FsContext,
IN LONGLONG StartingOffset,
IN PVOID DataBuffer,
IN ULONG DataBufferLength
)
/*++
Routine Description:
This routine processes the write requests for the local display miniport.
Arguments:
DeviceExtensionIn - Miniport's device extension
StartingOffset - Starting offset for the I/O
DataBuffer - Pointer to the data buffer
DataBufferLength - Length of the data buffer in bytes
Return Value:
NT status code.
--*/
{
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
//
// Validate the I/O parameters
//
if (((StartingOffset + DataBufferLength) / sizeof(ULONG)) > MAX_NVRAM_SIZE) {
REPORT_ERROR( SA_DEVICE_NVRAM, "Starting offset is too large\n", STATUS_INVALID_PARAMETER_1 );
return STATUS_INVALID_PARAMETER_1;
}
//
// Save the I/O parameters
//
DeviceExtension->IoBuffer = (PULONG)DataBuffer;
DeviceExtension->IoLength = DataBufferLength / sizeof(ULONG);
DeviceExtension->IoFunction = IRP_MJ_WRITE;
DeviceExtension->IoOffset = (ULONG) (StartingOffset / sizeof(ULONG));
DeviceExtension->IoIndex = 0;
DeviceExtension->CompletedIoSize = 0;
//
// Start the I/O
if (!SaNvramStartNextIo( DeviceExtension )) {
REPORT_ERROR( SA_DEVICE_NVRAM, "SaNvramStartNextIo failed\n", STATUS_UNSUCCESSFUL );
return STATUS_UNSUCCESSFUL;
}
return STATUS_PENDING;
}
VOID
SaNvramDpcRoutine(
IN PKDPC Dpc,
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This function is the device's DPC-for-ISR function. It is called
only by the ISR function and it's only function is to start the
next I/O.
Arguments:
DeviceObject - Pointer to the target device object.
DeviceExtension - Pointer to the mini-port's device extension.
Context - Mini-port supplied context pointer.
Context:
IRQL: DISPATCH_LEVEL, DPC context
Return Value:
None.
--*/
{
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Irp;
NTSTATUS Status;
//
// Set the status based on the data
// that was transfered.
//
if (DeviceExtension->CompletedIoSize == (DeviceExtension->IoIndex * sizeof(ULONG))) {
Status = STATUS_SUCCESS;
} else {
Status = STATUS_UNEXPECTED_IO_ERROR;
}
//
// Reset the current I/O paramaters to
// prevent the ISR from reacting to a
// bogus interrupt.
//
DeviceExtension->IoBuffer = NULL;
DeviceExtension->IoLength = 0;
DeviceExtension->IoFunction = 0;
DeviceExtension->IoOffset = 0;
DeviceExtension->IoIndex = 0;
//
// Complete this IRP and start the next
// IRP is there is one in the queue
//
SaPortCompleteRequest(
DeviceExtension,
NULL,
DeviceExtension->CompletedIoSize,
Status,
FALSE
);
}
NTSTATUS
SaNvramDeviceIoctl(
IN PVOID DeviceExtension,
IN PIRP Irp,
IN PVOID FsContext,
IN ULONG FunctionCode,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
IN PVOID OutputBuffer,
IN ULONG OutputBufferLength
)
/*++
Routine Description:
This function is called by the SAPORT driver so that
the mini-port driver can service an IOCTL call.
Arguments:
DeviceExtension - A pointer to the mini-port's device extension
FunctionCode - The IOCTL function code
InputBuffer - Pointer to the input buffer, contains the data sent down by the I/O
InputBufferLength - Length in bytes of the InputBuffer
OutputBuffer - Pointer to the output buffer, contains the data generated by this call
OutputBufferLength - Length in bytes of the OutputBuffer
Context:
IRQL: IRQL PASSIVE_LEVEL, arbitrary thread context
Return Value:
If the function succeeds, it must return STATUS_SUCCESS.
Otherwise, it must return one of the error status values defined in ntstatus.h.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PSA_NVRAM_CAPS NvramCaps = NULL;
switch (FunctionCode) {
case FUNC_SA_GET_VERSION:
*((PULONG)OutputBuffer) = SA_INTERFACE_VERSION;
break;
case FUNC_SA_GET_CAPABILITIES:
NvramCaps = (PSA_NVRAM_CAPS)OutputBuffer;
NvramCaps->SizeOfStruct = sizeof(SA_NVRAM_CAPS);
NvramCaps->NvramSize = MAX_NVRAM_SIZE;
break;
default:
Status = STATUS_NOT_SUPPORTED;
REPORT_ERROR( SA_DEVICE_NVRAM, "Unsupported device control", Status );
break;
}
return Status;
}
NTSTATUS
SaNvramHwInitialize(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID DeviceExtensionIn,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResources,
IN ULONG PartialResourceCount
)
/*++
Routine Description:
This function is called by the SAPORT driver so that
the mini-port driver can initialize it's hardware
resources.
Arguments:
DeviceObject - Pointer to the target device object.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
DeviceExtension - A pointer to the mini-port's device extension.
PartialResources - Pointer to the translated resources alloacted by the system.
PartialResourceCount - The number of resources in the PartialResources array.
Context:
IRQL: IRQL PASSIVE_LEVEL, system thread context
Return Value:
If the function succeeds, it must return STATUS_SUCCESS.
Otherwise, it must return one of the error status values defined in ntstatus.h.
--*/
{
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceMemory = NULL;
ULONG i;
for (i=0; i<PartialResourceCount; i++) {
if (PartialResources[i].Type == CmResourceTypeMemory) {
ResourceMemory = &PartialResources[i];
}
}
if (ResourceMemory == NULL) {
REPORT_ERROR( SA_DEVICE_NVRAM, "Missing memory resource", STATUS_UNSUCCESSFUL );
return STATUS_UNSUCCESSFUL;
}
//
// Setup the memory base address
//
DeviceExtension->NvramMemBase = (PUCHAR) SaPortGetVirtualAddress(
DeviceExtension,
ResourceMemory->u.Memory.Start,
ResourceMemory->u.Memory.Length
);
if (DeviceExtension->NvramMemBase == NULL) {
REPORT_ERROR( SA_DEVICE_NVRAM, "SaPortGetVirtualAddress failed", STATUS_NO_MEMORY );
return STATUS_NO_MEMORY;
}
//
// Enable interrupts on the hardware
//
WRITE_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase, NVRAM_CONTROL_INTERRUPT_ENABLE );
return STATUS_SUCCESS;
}
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine is the driver's entry point, called by the I/O system
to load the driver. The driver's entry points are initialized and
a mutex to control paging is initialized.
In DBG mode, this routine also examines the registry for special
debug parameters.
Arguments:
DriverObject - a pointer to the object that represents this device driver.
RegistryPath - a pointer to this driver's key in the Services tree.
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS Status;
SAPORT_INITIALIZATION_DATA SaPortInitData;
RtlZeroMemory( &SaPortInitData, sizeof(SAPORT_INITIALIZATION_DATA) );
SaPortInitData.StructSize = sizeof(SAPORT_INITIALIZATION_DATA);
SaPortInitData.DeviceType = SA_DEVICE_NVRAM;
SaPortInitData.HwInitialize = SaNvramHwInitialize;
SaPortInitData.DeviceIoctl = SaNvramDeviceIoctl;
SaPortInitData.Read = SaNvramRead;
SaPortInitData.Write = SaNvramWrite;
SaPortInitData.InterruptServiceRoutine = SaNvramInterruptService;
SaPortInitData.IsrForDpcRoutine = SaNvramDpcRoutine;
SaPortInitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
Status = SaPortInitialize( DriverObject, RegistryPath, &SaPortInitData );
if (!NT_SUCCESS(Status)) {
REPORT_ERROR( SA_DEVICE_NVRAM, "SaPortInitialize failed\n", Status );
return Status;
}
return STATUS_SUCCESS;
}