Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

713 lines
17 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
port.c
Abstract:
Author:
Ken Reneris (kenr) March-13-1885
Environment:
Kernel mode only.
Revision History:
--*/
#include "pciport.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,PcipAssignSlotResources)
#pragma alloc_text(PAGE,PcipQueryBusSlots)
#pragma alloc_text(PAGE,PcipHibernateBus)
#pragma alloc_text(PAGE,PcipResumeBus)
#pragma alloc_text(PAGE,PcipSuspendNotification)
#pragma alloc_text(PAGE,PcipReferenceDeviceHandler)
#endif
ULONG
PcipGetBusData (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN PCI_SLOT_NUMBER SlotNumber,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
The function returns the Pci bus data for a device.
Arguments:
BusNumber - Indicates which bus.
VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
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.
If this PCI slot has never been set, then the configuration information
returned is zeroed.
--*/
{
PPCI_COMMON_CONFIG PciData;
UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
PPCIBUSDATA BusData;
ULONG Len;
ULONG i, bit;
BusData = (PPCIBUSDATA) BusHandler->BusData;
if (Length > sizeof (PCI_COMMON_CONFIG)) {
Length = sizeof (PCI_COMMON_CONFIG);
}
Len = 0;
PciData = (PPCI_COMMON_CONFIG) iBuffer;
if (Offset >= PCI_COMMON_HDR_LENGTH) {
//
// The user did not request any data from the common
// header. Verify the PCI device exists, then continue
// in the device specific area.
//
BusData->ReadConfig (BusHandler, SlotNumber, PciData, 0, sizeof (ULONG));
if (PciData->VendorID == PCI_INVALID_VENDORID) {
return 0;
}
} else {
//
// Caller requested at least some data within the
// common header. Read the whole header, effect the
// fields we need to and then copy the user's requested
// bytes from the header
//
//
// Read this PCI devices slot data
//
Len = PCI_COMMON_HDR_LENGTH;
BusData->ReadConfig (BusHandler, SlotNumber, PciData, 0, Len);
if (PciData->VendorID == PCI_INVALID_VENDORID ||
PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) {
PciData->VendorID = PCI_INVALID_VENDORID;
Len = 2; // only return invalid id
} else {
BusData->Pin2Line (BusHandler, RootHandler, SlotNumber, PciData);
}
//
// Copy whatever data overlaps into the callers buffer
//
if (Len < Offset) {
// no data at caller's buffer
return 0;
}
Len -= Offset;
if (Len > Length) {
Len = Length;
}
RtlMoveMemory(Buffer, iBuffer + Offset, Len);
Offset += Len;
Buffer += Len;
Length -= Len;
}
if (Length) {
if (Offset >= PCI_COMMON_HDR_LENGTH) {
//
// The remaining Buffer comes from the Device Specific
// area - put on the kitten gloves and read from it.
//
// Specific read/writes to the PCI device specific area
// are guarenteed:
//
// Not to read/write any byte outside the area specified
// by the caller. (this may cause WORD or BYTE references
// to the area in order to read the non-dword aligned
// ends of the request)
//
// To use a WORD access if the requested length is exactly
// a WORD long.
//
// To use a BYTE access if the requested length is exactly
// a BYTE long.
//
BusData->ReadConfig (BusHandler, SlotNumber, Buffer, Offset, Length);
Len += Length;
}
}
return Len;
}
ULONG
PcipGetDeviceData (
IN struct _BUS_HANDLER *BusHandler,
IN struct _BUS_HANDLER *RootHandler,
IN PDEVICE_HANDLER_OBJECT DeviceHandler,
IN ULONG DataType,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
)
{
ULONG Status;
PDEVICE_DATA DeviceData;
PCI_SLOT_NUMBER SlotNumber;
Status = 0;
DeviceData = DeviceHandler2DeviceData (DeviceHandler);
//
// Verify caller has a valid DeviceHandler object
//
if (!DeviceData->Valid) {
//
// Obsolete object, return no data
//
return 0;
}
//
// Get the device's data.
//
if (DataType == 0) {
//
// Type 0 is the same as GetBusData for the slot
//
SlotNumber.u.AsULONG = DeviceHandler->SlotNumber;
Status = PcipGetBusData (
BusHandler,
RootHandler,
SlotNumber,
Buffer,
Offset,
Length
);
}
return Status;
}
ULONG
PcipSetBusData (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN PCI_SLOT_NUMBER SlotNumber,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
)
{
PPCI_COMMON_CONFIG PciData, PciData2;
UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH];
PPCIBUSDATA BusData;
ULONG Len, cnt;
BusData = (PPCIBUSDATA) BusHandler->BusData;
if (Length > sizeof (PCI_COMMON_CONFIG)) {
Length = sizeof (PCI_COMMON_CONFIG);
}
Len = 0;
PciData = (PPCI_COMMON_CONFIG) iBuffer;
PciData2 = (PPCI_COMMON_CONFIG) iBuffer2;
if (Offset >= PCI_COMMON_HDR_LENGTH) {
//
// The user did not request any data from the common
// header. Verify the PCI device exists, then continue in
// the device specific area.
//
BusData->ReadConfig (BusHandler, SlotNumber, PciData, 0, sizeof(ULONG));
if (PciData->VendorID == PCI_INVALID_VENDORID) {
return 0;
}
} else {
//
// Caller requested to set at least some data within the
// common header.
//
Len = PCI_COMMON_HDR_LENGTH;
BusData->ReadConfig (BusHandler, SlotNumber, PciData, 0, Len);
if (PciData->VendorID == PCI_INVALID_VENDORID ||
PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) {
// no device, or header type unkown
return 0;
}
//
// Copy COMMON_HDR values to buffer2, then overlay callers changes.
//
RtlMoveMemory (iBuffer2, iBuffer, Len);
BusData->Pin2Line (BusHandler, RootHandler, SlotNumber, PciData2);
Len -= Offset;
if (Len > Length) {
Len = Length;
}
RtlMoveMemory (iBuffer2+Offset, Buffer, Len);
// in case interrupt line or pin was editted
BusData->Line2Pin (BusHandler, RootHandler, SlotNumber, PciData2, PciData);
#if DBG
//
// Verify R/O fields haven't changed
//
if (PciData2->VendorID != PciData->VendorID ||
PciData2->DeviceID != PciData->DeviceID ||
PciData2->RevisionID != PciData->RevisionID ||
PciData2->ProgIf != PciData->ProgIf ||
PciData2->SubClass != PciData->SubClass ||
PciData2->BaseClass != PciData->BaseClass ||
PciData2->HeaderType != PciData->HeaderType ||
PciData2->BaseClass != PciData->BaseClass ||
PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant ||
PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) {
DbgPrint ("PCI SetBusData: Read-Only configuration value changed\n");
DbgBreakPoint ();
}
#endif
//
// Set new PCI configuration
//
BusData->WriteConfig (BusHandler, SlotNumber, iBuffer2+Offset, Offset, Len);
Offset += Len;
Buffer += Len;
Length -= Len;
}
if (Length) {
if (Offset >= PCI_COMMON_HDR_LENGTH) {
//
// The remaining Buffer comes from the Device Specific
// area - put on the kitten gloves and write it
//
// Specific read/writes to the PCI device specific area
// are guarenteed:
//
// Not to read/write any byte outside the area specified
// by the caller. (this may cause WORD or BYTE references
// to the area in order to read the non-dword aligned
// ends of the request)
//
// To use a WORD access if the requested length is exactly
// a WORD long.
//
// To use a BYTE access if the requested length is exactly
// a BYTE long.
//
BusData->WriteConfig (BusHandler, SlotNumber, Buffer, Offset, Length);
Len += Length;
}
}
return Len;
}
ULONG
PcipSetDeviceData (
IN struct _BUS_HANDLER *BusHandler,
IN struct _BUS_HANDLER *RootHandler,
IN PDEVICE_HANDLER_OBJECT DeviceHandler,
IN ULONG DataType,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length
)
{
ULONG Status;
PDEVICE_DATA DeviceData;
PCI_SLOT_NUMBER SlotNumber;
Status = 0;
DeviceData = DeviceHandler2DeviceData (DeviceHandler);
//
// Verify caller has a valid DeviceHandler object
//
if (!DeviceData->Valid) {
//
// Obsolete object, return no data
//
return 0;
}
//
// Get the device's data.
//
if (DataType == 0) {
//
// Type 0 is the same as SetBusData for the slot
//
SlotNumber.u.AsULONG = DeviceHandler->SlotNumber;
Status = PcipGetBusData (
BusHandler,
RootHandler,
SlotNumber,
Buffer,
Offset,
Length
);
}
return Status;
}
NTSTATUS
PcipAssignSlotResources (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN PUNICODE_STRING RegistryPath,
IN PUNICODE_STRING DriverClassName OPTIONAL,
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
IN ULONG SlotNumber,
IN OUT PCM_RESOURCE_LIST *AllocatedResources
)
{
CTL_ASSIGN_RESOURCES AssignResources;
KEVENT CompletionEvent;
ULONG BufferSize;
PDEVICE_HANDLER_OBJECT DeviceHandler;
NTSTATUS Status;
PAGED_CODE ();
//
// Foreward this request through a DeviceControl such that it
// gets the proper synchronzation on the device
//
DeviceHandler = BusHandler->ReferenceDeviceHandler (
BusHandler,
BusHandler,
SlotNumber
);
if (!DeviceHandler) {
return STATUS_NO_SUCH_DEVICE;
}
AssignResources.RegistryPath = RegistryPath;
AssignResources.DriverClassName = DriverClassName;
AssignResources.DriverObject = DriverObject;
AssignResources.AllocatedResources = AllocatedResources;
BufferSize = sizeof (AssignResources);
//
// Make synchrous DeviceControl request
//
Status = HalDeviceControl (
DeviceHandler,
DeviceObject,
BCTL_ASSIGN_SLOT_RESOURCES,
&AssignResources,
&BufferSize,
NULL,
NULL
);
//
// Free the reference to DeviceHandler
//
ObDereferenceObject (DeviceHandler);
//
// Done
//
return Status;
}
NTSTATUS
PcipQueryBusSlots (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG BufferSize,
OUT PULONG SlotNumbers,
OUT PULONG ReturnedLength
)
{
PSINGLE_LIST_ENTRY Link;
PPCI_PORT PciPort;
PDEVICE_DATA DeviceData;
ULONG cnt;
PAGED_CODE ();
PciPort = PCIPORTDATA (BusHandler);
//
// Synchronize will new devices being added
//
ExAcquireFastMutex (&PcipMutex);
//
// Fill in returned buffer length, or what size buffer is needed
//
*ReturnedLength = PciPort->NoValidSlots * sizeof (ULONG);
if (BufferSize < *ReturnedLength) {
//
// Callers buffer is not large enough
//
ExReleaseFastMutex (&PcipMutex);
return STATUS_BUFFER_TOO_SMALL;
}
//
// Return caller all the possible slot number
//
cnt = 0;
for (Link = PciPort->ValidSlots.Next; Link; Link = Link->Next) {
DeviceData = CONTAINING_RECORD (Link, DEVICE_DATA, Next);
if (DeviceData->Valid) {
cnt += 1;
*(SlotNumbers++) = DeviceDataSlot(DeviceData);
}
}
*ReturnedLength = cnt * sizeof (ULONG);
ExReleaseFastMutex (&PcipMutex);
return STATUS_SUCCESS;
}
NTSTATUS
PcipDeviceControl (
IN PHAL_DEVICE_CONTROL_CONTEXT Context
)
{
ULONG i;
ULONG ControlCode;
ULONG Junk;
PULONG BufferLength;
PLIST_ENTRY OldTail;
BOOLEAN UseWorker;
for (i=0; PcipControl[i].ControlHandler; i++) {
if (PcipControl[i].ControlCode == Context->DeviceControl.ControlCode) {
//
// Found DeviceControl handler
//
Context->ContextControlHandler = (ULONG) (PcipControl + i);
//
// Verify callers buffer is the min required length
//
if (*Context->DeviceControl.BufferLength < PcipControl[i].MinBuffer) {
Context->DeviceControl.Status = STATUS_BUFFER_TOO_SMALL;
*Context->DeviceControl.BufferLength = PcipControl[i].MinBuffer;
HalCompleteDeviceControl (Context);
return STATUS_BUFFER_TOO_SMALL;
}
if (KeGetCurrentIrql() < DISPATCH_LEVEL ||
(Context->DeviceControl.ControlCode == BCTL_SET_POWER &&
*((PPOWER_STATE) Context->DeviceControl.Buffer) == PowerUp)){
//
// All slot controls, expect a power up request, may touch
// paged code or data. If the current irql is low enough or
// this is a power up go dispatch now; otherwise, queue the
// request to a worker thread.
//
PcipDispatchControl (Context);
} else {
//
// Enqueue to worker thread
//
ExInterlockedInsertTailList (
&PcipControlWorkerList,
(PLIST_ENTRY) &Context->ContextWorkQueue,
&PcipSpinlock
);
//
// Make sure worker is requested
//
PcipStartWorker ();
}
return STATUS_PENDING;
}
}
//
// Unkown control code
//
return STATUS_INVALID_PARAMETER;
}
PDEVICE_HANDLER_OBJECT
PcipReferenceDeviceHandler (
IN struct _BUS_HANDLER *BusHandler,
IN struct _BUS_HANDLER *RootHandler,
IN PCI_SLOT_NUMBER SlotNumber
)
{
PDEVICE_DATA DeviceData;
PDEVICE_HANDLER_OBJECT DeviceHandler;
PPCI_PORT PciPort;
NTSTATUS Status;
PAGED_CODE ();
ExAcquireFastMutex (&PcipMutex);
PciPort = PCIPORTDATA(BusHandler);
DeviceData = PcipFindDeviceData (PciPort, SlotNumber);
DeviceHandler = NULL;
if (DeviceData) {
DeviceHandler = DeviceData2DeviceHandler (DeviceData);
Status = ObReferenceObjectByPointer(
DeviceHandler,
FILE_READ_DATA | FILE_WRITE_DATA,
*IoDeviceHandlerObjectType,
KernelMode
);
if (!NT_SUCCESS(Status)) {
DeviceHandler = NULL;
}
}
ExReleaseFastMutex (&PcipMutex);
return DeviceHandler;
}
NTSTATUS
PcipHibernateBus (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler
)
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
PcipResumeBus (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler
)
{
return STATUS_NOT_IMPLEMENTED;
}
VOID
PcipSuspendNotification (
IN PVOID CallbackContext,
IN PVOID Argument1,
IN PVOID Argument2
)
{
PAGED_CODE();
switch ((ULONG) Argument1) {
case 0:
//
// Lock code down which might be needed to perform a suspend
//
ASSERT (PciCodeLock == NULL);
PciCodeLock = MmLockPagableCodeSection (&PcipHibernateBus);
break;
case 1:
//
// Release the code lock
//
MmUnlockPagableImageSection (PciCodeLock);
PciCodeLock = NULL;
break;
}
}