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.
 
 
 
 
 
 

2715 lines
80 KiB

/*****************************************************************************
* portcls.cpp - WDM Streaming port class driver
*****************************************************************************
* Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
*/
#define KSDEBUG_INIT
#include "private.h"
#include "perf.h"
#include <ksmediap.h>
#ifdef TIME_BOMB
#include "..\..\..\timebomb\timebomb.c"
#endif
/*****************************************************************************
* Referenced forward.
*/
NTSTATUS
DispatchPnp
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
);
NTSTATUS
DispatchSystemControl
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
);
#define PORTCLS_DRIVER_EXTENSION_ID 0x0ABADCAFE
/*****************************************************************************
* Globals
*/
ULONG gBufferDuration=0;
KAFFINITY gInterruptAffinity=0;
/*****************************************************************************
* Functions.
*/
// TODO: put this someplace better?
int __cdecl
_purecall( void )
{
ASSERT(!"Pure virtual function called");
return 0;
}
#pragma code_seg("PAGE")
NTSTATUS
QueryRegistryValueEx(
ULONG Hive,
PWSTR pwstrRegistryPath,
PWSTR pwstrRegistryValue,
ULONG uValueType,
PVOID *ppValue,
PVOID pDefaultData,
ULONG DefaultDataLength
)
{
PRTL_QUERY_REGISTRY_TABLE pRegistryValueTable = NULL;
UNICODE_STRING usString;
DWORD dwValue;
NTSTATUS Status = STATUS_SUCCESS;
usString.Buffer = NULL;
pRegistryValueTable = (PRTL_QUERY_REGISTRY_TABLE) ExAllocatePoolWithTag(
PagedPool,
(sizeof(RTL_QUERY_REGISTRY_TABLE)*2),
'vRcP');
if(!pRegistryValueTable) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
RtlZeroMemory(pRegistryValueTable, (sizeof(RTL_QUERY_REGISTRY_TABLE)*2));
pRegistryValueTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
pRegistryValueTable[0].Name = pwstrRegistryValue;
pRegistryValueTable[0].DefaultType = uValueType;
pRegistryValueTable[0].DefaultLength = DefaultDataLength;
pRegistryValueTable[0].DefaultData = pDefaultData;
switch (uValueType) {
case REG_SZ:
pRegistryValueTable[0].EntryContext = &usString;
break;
case REG_DWORD:
pRegistryValueTable[0].EntryContext = &dwValue;
break;
default:
Status = STATUS_INVALID_PARAMETER ;
goto exit;
}
Status = RtlQueryRegistryValues(
Hive,
pwstrRegistryPath,
pRegistryValueTable,
NULL,
NULL);
if(!NT_SUCCESS(Status)) {
goto exit;
}
switch (uValueType) {
case REG_SZ:
*ppValue = ExAllocatePoolWithTag(
PagedPool,
usString.Length + sizeof(UNICODE_NULL),
'sUcP');
if(!(*ppValue)) {
RtlFreeUnicodeString(&usString);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
memcpy(*ppValue, usString.Buffer, usString.Length);
((PWCHAR)*ppValue)[usString.Length/sizeof(WCHAR)] = UNICODE_NULL;
RtlFreeUnicodeString(&usString);
break;
case REG_DWORD:
*ppValue = ExAllocatePoolWithTag(
PagedPool,
sizeof(DWORD),
'WDcP');
if(!(*ppValue)) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
*((DWORD *)(*ppValue)) = dwValue;
break;
default:
Status = STATUS_INVALID_PARAMETER ;
goto exit;
}
exit:
if (pRegistryValueTable) {
ExFreePool(pRegistryValueTable);
}
return(Status);
}
ULONG
GetUlongFromRegistry(
PWSTR pwstrRegistryPath,
PWSTR pwstrRegistryValue,
ULONG DefaultValue
)
{
PVOID pulValue ;
ULONG ulValue ;
NTSTATUS Status ;
Status = QueryRegistryValueEx(RTL_REGISTRY_ABSOLUTE,
pwstrRegistryPath,
pwstrRegistryValue,
REG_DWORD,
&pulValue,
&DefaultValue,
sizeof(DWORD));
if (NT_SUCCESS(Status)) {
ulValue = *((PULONG)pulValue);
ExFreePool(pulValue);
}
else {
ulValue = DefaultValue;
}
return ( ulValue ) ;
}
/*****************************************************************************
* DriverEntry()
*****************************************************************************
* Never called. All drivers must have one of these, so...
*/
extern "C"
NTSTATUS
DriverEntry
(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
PAGED_CODE();
ASSERT(! "Port Class DriverEntry was called");
//
// Should never be called, but timebombing is added here for completeness.
//
#ifdef TIME_BOMB
if (HasEvaluationTimeExpired())
{
_DbgPrintF(DEBUGLVL_TERSE,("This evaluation copy of PortCls has expired!!"));
return STATUS_EVALUATION_EXPIRATION;
}
#endif
return STATUS_SUCCESS;
}
/*****************************************************************************
* DllInitialize()
*****************************************************************************
* Entry point for export library drivers.
*/
extern "C"
NTSTATUS DllInitialize(PVOID foo)
{
PAGED_CODE();
_DbgPrintF(DEBUGLVL_VERBOSE,("DllInitialize"));
#ifdef TIME_BOMB
if (HasEvaluationTimeExpired())
{
_DbgPrintF(DEBUGLVL_TERSE,("This evaluation copy of PortCls has expired!!"));
return STATUS_EVALUATION_EXPIRATION;
}
#endif
// Query the registry for the default audio buffer duration.
gBufferDuration = GetUlongFromRegistry( CORE_AUDIO_BUFFER_DURATION_PATH,
CORE_AUDIO_BUFFER_DURATION_VALUE,
DEFAULT_CORE_AUDIO_BUFFER_DURATION );
gInterruptAffinity = GetUlongFromRegistry( CORE_AUDIO_BUFFER_DURATION_PATH,
L"InterruptAffinity",
0 );
// Limit duration maximum.
if ( gBufferDuration > MAX_CORE_AUDIO_BUFFER_DURATION ) {
gBufferDuration = MAX_CORE_AUDIO_BUFFER_DURATION;
}
// Limit duration minimum.
if ( gBufferDuration < MIN_CORE_AUDIO_BUFFER_DURATION ) {
gBufferDuration = MIN_CORE_AUDIO_BUFFER_DURATION;
}
#if !(MIN_CORE_AUDIO_BUFFER_DURATION/1000)
#error MIN_CORE_AUDIO_BUFFER_DURATION less than 1ms not yet supported in portcls!
#endif
gBufferDuration /= 1000;
#if kEnableDebugLogging
if (!gPcDebugLog)
{
gPcDebugLog = (ULONG_PTR *)ExAllocatePoolWithTag(NonPagedPool,(kNumDebugLogEntries * kNumULONG_PTRsPerEntry * sizeof(ULONG_PTR)),'lDcP'); // 'PcDl'
if (gPcDebugLog)
{
RtlZeroMemory(PVOID(gPcDebugLog),kNumDebugLogEntries * kNumULONG_PTRsPerEntry * sizeof(ULONG_PTR));
}
gPcDebugLogIndex = 0;
}
DebugLog(1,0,0,0);
#endif // kEnableDebugLogging
return STATUS_SUCCESS;
}
/*****************************************************************************
* DllUnload()
*****************************************************************************
* Allow unload.
*/
extern "C"
NTSTATUS
DllUnload
( void
)
{
PAGED_CODE();
_DbgPrintF(DEBUGLVL_VERBOSE,("DllUnload"));
#if kEnableDebugLogging
if (gPcDebugLog)
{
ExFreePool(gPcDebugLog);
gPcDebugLog = NULL;
}
#endif // kEnableDebugLogging
return STATUS_SUCCESS;
}
#if kEnableDebugLogging
ULONG_PTR *gPcDebugLog = NULL;
DWORD gPcDebugLogIndex = 0;
void PcDebugLog(ULONG_PTR param1,ULONG_PTR param2,ULONG_PTR param3,ULONG_PTR param4)
{
if (gPcDebugLog)
{
gPcDebugLog[(gPcDebugLogIndex * kNumULONG_PTRsPerEntry)] = param1;
gPcDebugLog[(gPcDebugLogIndex * kNumULONG_PTRsPerEntry) + 1] = param2;
gPcDebugLog[(gPcDebugLogIndex * kNumULONG_PTRsPerEntry) + 2] = param3;
gPcDebugLog[(gPcDebugLogIndex * kNumULONG_PTRsPerEntry) + 3] = param4;
if (InterlockedIncrement(PLONG(&gPcDebugLogIndex)) >= kNumDebugLogEntries)
{
InterlockedExchange(PLONG(&gPcDebugLogIndex), 0);
}
}
}
#endif // kEnableDebugLogging
/*****************************************************************************
* DupUnicodeString()
*****************************************************************************
* Duplicates a unicode string.
*/
NTSTATUS
DupUnicodeString
(
OUT PUNICODE_STRING * ppUnicodeString,
IN PUNICODE_STRING pUnicodeString OPTIONAL
)
{
PAGED_CODE();
ASSERT(ppUnicodeString);
NTSTATUS ntStatus = STATUS_SUCCESS;
if (pUnicodeString)
{
PUNICODE_STRING pUnicodeStringNew =
new(PagedPool,'sUcP') UNICODE_STRING;
if (pUnicodeStringNew)
{
pUnicodeStringNew->Length = pUnicodeString->Length;
pUnicodeStringNew->MaximumLength = pUnicodeString->MaximumLength;
if (pUnicodeString->Buffer)
{
pUnicodeStringNew->Buffer =
new(PagedPool,'sUcP')
WCHAR[pUnicodeString->MaximumLength / sizeof(WCHAR)];
if (pUnicodeStringNew->Buffer)
{
RtlCopyMemory
(
pUnicodeStringNew->Buffer,
pUnicodeString->Buffer,
pUnicodeString->Length
);
*ppUnicodeString = pUnicodeStringNew;
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
delete pUnicodeStringNew;
}
}
else
{
pUnicodeStringNew->Buffer = NULL;
*ppUnicodeString = pUnicodeStringNew;
}
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
*ppUnicodeString = NULL;
}
return ntStatus;
}
/*****************************************************************************
* DelUnicodeString()
*****************************************************************************
* Deletes a unicode string that was allocated using ExAllocatePool().
*/
VOID
DelUnicodeString
(
IN PUNICODE_STRING pUnicodeString OPTIONAL
)
{
if (pUnicodeString)
{
if (pUnicodeString->Buffer)
{
delete [] pUnicodeString->Buffer;
}
delete pUnicodeString;
}
}
VOID
KsoNullDriverUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Default function which drivers can use when they do not have anything to do
in their unload function, but must still allow the device to be unloaded by
its presence.
Arguments:
DriverObject -
Contains the driver object for this device.
Return Values:
Nothing.
--*/
{
_DbgPrintF(DEBUGLVL_VERBOSE,("KsoNullDriverUnload"));
if (DriverObject->DeviceObject)
{
_DbgPrintF(DEBUGLVL_TERSE,("KsoNullDriverUnload DEVICES EXIST"));
}
}
/*****************************************************************************
* PcInitializeAdapterDriver()
*****************************************************************************
* Initializes an adapter driver.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcInitializeAdapterDriver
(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPathName,
IN PDRIVER_ADD_DEVICE AddDevice
)
{
PAGED_CODE();
ASSERT(DriverObject);
ASSERT(RegistryPathName);
ASSERT(AddDevice);
_DbgPrintF(DEBUGLVL_VERBOSE,("PcInitializeAdapterDriver"));
//
// Validate Parameters.
//
if (NULL == DriverObject ||
NULL == RegistryPathName ||
NULL == AddDevice)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcInitializeAdapterDriver : Invalid Parameter."));
return STATUS_INVALID_PARAMETER;
}
DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->DriverUnload = KsoNullDriverUnload;
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PerfWmiDispatch;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
KsSetMajorFunctionHandler(DriverObject,IRP_MJ_DEVICE_CONTROL);
KsSetMajorFunctionHandler(DriverObject,IRP_MJ_READ);
KsSetMajorFunctionHandler(DriverObject,IRP_MJ_WRITE);
KsSetMajorFunctionHandler(DriverObject,IRP_MJ_FLUSH_BUFFERS);
KsSetMajorFunctionHandler(DriverObject,IRP_MJ_CLOSE);
KsSetMajorFunctionHandler(DriverObject,IRP_MJ_QUERY_SECURITY);
KsSetMajorFunctionHandler(DriverObject,IRP_MJ_SET_SECURITY);
return STATUS_SUCCESS;
}
/*****************************************************************************
* PcDispatchIrp()
*****************************************************************************
* Dispatch an IRP.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcDispatchIrp
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
ASSERT(pIrp);
NTSTATUS ntStatus;
//
// Validate parameters.
//
if (NULL == pDeviceObject ||
NULL == pIrp)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcDispatchIrp : Invalid Parameter"));
ntStatus = STATUS_INVALID_PARAMETER;
if (pIrp)
{
pIrp->IoStatus.Status = ntStatus;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
}
return ntStatus;
}
switch (IoGetCurrentIrpStackLocation(pIrp)->MajorFunction)
{
case IRP_MJ_PNP:
ntStatus = DispatchPnp(pDeviceObject,pIrp);
break;
case IRP_MJ_POWER:
ntStatus = DispatchPower(pDeviceObject,pIrp);
break;
case IRP_MJ_SYSTEM_CONTROL:
ntStatus = PerfWmiDispatch(pDeviceObject,pIrp);
break;
default:
ntStatus = KsoDispatchIrp(pDeviceObject,pIrp);
break;
}
return ntStatus;
}
#pragma code_seg()
/*****************************************************************************
* AcquireDevice()
*****************************************************************************
* Acquire exclusive access to the device. This function has the semantics of
* a mutex, ie the device must be released on the same thread it was acquired
* from.
*/
VOID
AcquireDevice
(
IN PDEVICE_CONTEXT pDeviceContext
)
{
#ifdef UNDER_NT
KeEnterCriticalRegion();
#endif
KeWaitForSingleObject
(
&pDeviceContext->kEventDevice,
Suspended,
KernelMode,
FALSE,
NULL
);
}
/*****************************************************************************
* ReleaseDevice()
*****************************************************************************
* Release exclusive access to the device.
*/
VOID
ReleaseDevice
(
IN PDEVICE_CONTEXT pDeviceContext
)
{
KeSetEvent(&pDeviceContext->kEventDevice,0,FALSE);
#ifdef UNDER_NT
KeLeaveCriticalRegion();
#endif
}
/*****************************************************************************
* IncrementPendingIrpCount()
*****************************************************************************
* Increment the pending IRP count for the device.
*/
VOID
IncrementPendingIrpCount
(
IN PDEVICE_CONTEXT pDeviceContext
)
{
ASSERT(pDeviceContext);
InterlockedIncrement(PLONG(&pDeviceContext->PendingIrpCount));
}
/*****************************************************************************
* DecrementPendingIrpCount()
*****************************************************************************
* Decrement the pending IRP count for the device.
*/
VOID
DecrementPendingIrpCount
(
IN PDEVICE_CONTEXT pDeviceContext
)
{
ASSERT(pDeviceContext);
ASSERT(pDeviceContext->PendingIrpCount > 0);
if (InterlockedDecrement(PLONG(&pDeviceContext->PendingIrpCount)) == 0)
{
KeSetEvent(&pDeviceContext->kEventRemove,0,FALSE);
}
}
/*****************************************************************************
* CompleteIrp()
*****************************************************************************
* Complete an IRP unless status is STATUS_PENDING.
*/
NTSTATUS
CompleteIrp
(
IN PDEVICE_CONTEXT pDeviceContext,
IN PIRP pIrp,
IN NTSTATUS ntStatus
)
{
ASSERT(pDeviceContext);
ASSERT(pIrp);
if (ntStatus != STATUS_PENDING)
{
pIrp->IoStatus.Status = ntStatus;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
DecrementPendingIrpCount(pDeviceContext);
}
return ntStatus;
}
/*****************************************************************************
* PcCompleteIrp()
*****************************************************************************
* Complete an IRP unless status is STATUS_PENDING.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcCompleteIrp
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN NTSTATUS ntStatus
)
{
ASSERT(pDeviceObject);
ASSERT(pIrp);
if (NULL == pDeviceObject ||
NULL == pIrp ||
NULL == pDeviceObject->DeviceExtension)
{
// don't know what to do, so we'll fail the IRP
ntStatus = STATUS_INVALID_PARAMETER;
pIrp->IoStatus.Status = ntStatus;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return ntStatus;
}
return
CompleteIrp
(
PDEVICE_CONTEXT(pDeviceObject->DeviceExtension),
pIrp,
ntStatus
);
}
#pragma code_seg("PAGE")
// shamelessly stolen from nt\private\ntos\ks\api.c
NTSTATUS QueryReferenceBusInterface(
IN PDEVICE_OBJECT PnpDeviceObject,
OUT PBUS_INTERFACE_REFERENCE BusInterface
)
/*++
Routine Description:
Queries the bus for the standard information interface.
Arguments:
PnpDeviceObject -
Contains the next device object on the Pnp stack.
PhysicalDeviceObject -
Contains the physical device object which was passed to the FDO during
the Add Device.
BusInterface -
The place in which to return the Reference interface.
Return Value:
Returns STATUS_SUCCESS if the interface was retrieved, else an error.
--*/
{
NTSTATUS Status;
KEVENT Event;
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
PIO_STACK_LOCATION IrpStackNext;
PAGED_CODE();
//
// There is no file object associated with this Irp, so the event may be located
// on the stack as a non-object manager object.
//
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoBuildSynchronousFsdRequest(
IRP_MJ_PNP,
PnpDeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatusBlock);
if (Irp)
{
Irp->RequestorMode = KernelMode;
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IrpStackNext = IoGetNextIrpStackLocation(Irp);
//
// Create an interface query out of the Irp.
//
IrpStackNext->MinorFunction = IRP_MN_QUERY_INTERFACE;
IrpStackNext->Parameters.QueryInterface.InterfaceType = (GUID*)&REFERENCE_BUS_INTERFACE;
IrpStackNext->Parameters.QueryInterface.Size = sizeof(*BusInterface);
IrpStackNext->Parameters.QueryInterface.Version = BUS_INTERFACE_REFERENCE_VERSION;
IrpStackNext->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
IrpStackNext->Parameters.QueryInterface.InterfaceSpecificData = NULL;
Status = IoCallDriver(PnpDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
//
// This waits using KernelMode, so that the stack, and therefore the
// event on that stack, is not paged out.
//
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
return Status;
}
#pragma code_seg()
/*****************************************************************************
* IoTimeoutRoutine()
*****************************************************************************
* Called by IoTimer for timeout purposes
*/
VOID
IoTimeoutRoutine
(
IN PDEVICE_OBJECT pDeviceObject,
IN PVOID pContext
)
{
ASSERT(pDeviceObject);
ASSERT(pContext);
KIRQL OldIrql;
PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pContext);
// grab the list spinlock
KeAcquireSpinLock( &(pDeviceContext->TimeoutLock), &OldIrql );
// walk the list if it's not empty
if( !IsListEmpty( &(pDeviceContext->TimeoutList) ) )
{
PLIST_ENTRY ListEntry;
PTIMEOUTCALLBACK pCallback;
for( ListEntry = pDeviceContext->TimeoutList.Flink;
ListEntry != &(pDeviceContext->TimeoutList);
ListEntry = ListEntry->Flink )
{
pCallback = (PTIMEOUTCALLBACK) CONTAINING_RECORD( ListEntry,
TIMEOUTCALLBACK,
ListEntry );
// call the callback
pCallback->TimerRoutine(pDeviceObject,pCallback->Context);
}
}
// release the spinlock
KeReleaseSpinLock( &(pDeviceContext->TimeoutLock), OldIrql );
}
#pragma code_seg("PAGE")
/*****************************************************************************
* PcAddAdapterDevice()
*****************************************************************************
* Adds an adapter device.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcAddAdapterDevice
(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PCPFNSTARTDEVICE StartDevice,
IN ULONG MaxObjects,
IN ULONG DeviceExtensionSize
)
{
PAGED_CODE();
ASSERT(DriverObject);
ASSERT(PhysicalDeviceObject);
ASSERT(StartDevice);
ASSERT(MaxObjects);
_DbgPrintF(DEBUGLVL_VERBOSE,("PcAddAdapterDevice"));
//
// Validate Parameters.
//
if (NULL == DriverObject ||
NULL == PhysicalDeviceObject ||
NULL == StartDevice ||
0 == MaxObjects)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcAddAdapterDevice : Invalid Parameter"));
return STATUS_INVALID_PARAMETER;
}
//
// Extension size may be zero or >= required size.
//
if (DeviceExtensionSize == 0)
{
DeviceExtensionSize = sizeof(DEVICE_CONTEXT);
}
else
if (DeviceExtensionSize < sizeof(DEVICE_CONTEXT))
{
return STATUS_INVALID_PARAMETER;
}
//
// Create the device object.
//
PDEVICE_OBJECT pDeviceObject;
NTSTATUS ntStatus = IoCreateDevice( DriverObject,
DeviceExtensionSize,
NULL,
FILE_DEVICE_KS,
FILE_DEVICE_SECURE_OPEN |
FILE_AUTOGENERATED_DEVICE_NAME,
FALSE,
&pDeviceObject );
if (NT_SUCCESS(ntStatus))
{
//
// Initialize the device context.
//
PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
RtlZeroMemory(pDeviceContext,DeviceExtensionSize);
pDeviceContext->Signature = PORTCLS_DEVICE_EXTENSION_SIGNATURE;
pDeviceContext->MaxObjects = MaxObjects;
pDeviceContext->PhysicalDeviceObject = PhysicalDeviceObject;
pDeviceContext->CreateItems =
new(NonPagedPool,'iCcP') KSOBJECT_CREATE_ITEM[MaxObjects];
pDeviceContext->SymbolicLinkNames =
new(NonPagedPool,'lScP') UNICODE_STRING[MaxObjects];
pDeviceContext->StartDevice = StartDevice;
// set the current power states
pDeviceContext->CurrentDeviceState = PowerDeviceUnspecified;
pDeviceContext->CurrentSystemState = PowerSystemWorking;
pDeviceContext->SystemStateHandle = NULL;
// set device stop/remove states
pDeviceContext->DeviceStopState = DeviceStartPending;
pDeviceContext->DeviceRemoveState = DeviceAdded;
// Let's pause I/O during rebalance (as opposed to a full teardown)
//
// Blackcomb ISSUE
// Discovery AdriaO 06/29/1999
// We aren't *quite* there yet.
// Commentary MartinP 11/28/2000
// So true. Our problem: PortCls might be restarted
// with different resources, even one less IRQ or DMA channel,
// when rebalance completes. In a way, this would require our
// stack to support dynamic graph changes, which it currently
// does not. AdriaO suggests we implement something along the
// lines of "IsFilterCompatible(RESOURCE_LIST)". It's too late
// for a change like this in Windows XP, let's fix this for
// Blackcomb and PortCls2.
//
pDeviceContext->PauseForRebalance = FALSE;
//
// Initialize list of device interfaces.
//
InitializeListHead(&pDeviceContext->DeviceInterfaceList);
//
// Initialize list of physical connections.
//
InitializeListHead(&pDeviceContext->PhysicalConnectionList);
//
// Initialize list of pended IRPs.
//
InitializeListHead(&pDeviceContext->PendedIrpList);
KeInitializeSpinLock(&pDeviceContext->PendedIrpLock);
//
// Initialize events for device synchronization and removal.
//
KeInitializeEvent(&pDeviceContext->kEventDevice,SynchronizationEvent,TRUE);
KeInitializeEvent(&pDeviceContext->kEventRemove,SynchronizationEvent,FALSE);
//
// Set up the DPC for fast resume
//
KeInitializeDpc(&pDeviceContext->DevicePowerRequestDpc, DevicePowerRequestRoutine, pDeviceContext);
//
// Set the idle timeouts to the defaults. Note that the
// actual value will be read from the registry later.
//
pDeviceContext->ConservationIdleTime = DEFAULT_CONSERVATION_IDLE_TIME;
pDeviceContext->PerformanceIdleTime = DEFAULT_PERFORMANCE_IDLE_TIME;
pDeviceContext->IdleDeviceState = DEFAULT_IDLE_DEVICE_POWER_STATE;
// setup the driver object DMA spinlock
NTSTATUS ntStatus2 = IoAllocateDriverObjectExtension( DriverObject,
PVOID((DWORD_PTR)PORTCLS_DRIVER_EXTENSION_ID),
sizeof(KSPIN_LOCK),
(PVOID *)&pDeviceContext->DriverDmaLock );
if( STATUS_SUCCESS == ntStatus2 )
{
// if we allocated it we need to initialize it
KeInitializeSpinLock( pDeviceContext->DriverDmaLock );
} else if( STATUS_OBJECT_NAME_COLLISION == ntStatus2 )
{
// we had a collision so it was alread allocated, just get the pointer and don't initialize
pDeviceContext->DriverDmaLock = (PKSPIN_LOCK)IoGetDriverObjectExtension( DriverObject,
PVOID((DWORD_PTR)PORTCLS_DRIVER_EXTENSION_ID) );
} else
{
// propagate the failure (STATUS_INSUFFICIENT_RESOURCES)
ntStatus = ntStatus2;
}
if( NT_SUCCESS(ntStatus) )
{
if( ( !pDeviceContext->CreateItems ) || ( !pDeviceContext->SymbolicLinkNames) )
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else
{
//
// When this reaches zero, it'll be time to remove the device.
//
pDeviceContext->PendingIrpCount = 1;
//
// Initialize suspend and stop counts (used for debugging only)
//
pDeviceContext->SuspendCount = 0;
pDeviceContext->StopCount = 0;
//
// Initialize the IoTimer
//
InitializeListHead(&pDeviceContext->TimeoutList);
KeInitializeSpinLock(&pDeviceContext->TimeoutLock);
pDeviceContext->IoTimeoutsOk = FALSE;
if( NT_SUCCESS(IoInitializeTimer(pDeviceObject,IoTimeoutRoutine,pDeviceContext)) )
{
pDeviceContext->IoTimeoutsOk = TRUE;
}
//
// Allocate the KS device header
//
ntStatus = KsAllocateDeviceHeader( &pDeviceContext->pDeviceHeader,
MaxObjects,
pDeviceContext->CreateItems );
if( NT_SUCCESS(ntStatus) )
{
PDEVICE_OBJECT pReturnDevice = IoAttachDeviceToDeviceStack( pDeviceObject,
PhysicalDeviceObject );
if (! pReturnDevice)
{
// free the KS device header
KsFreeDeviceHeader( pDeviceContext->pDeviceHeader );
pDeviceContext->pDeviceHeader = NULL;
ntStatus = STATUS_UNSUCCESSFUL;
}
else
{
BUS_INTERFACE_REFERENCE BusInterface;
KsSetDevicePnpAndBaseObject(pDeviceContext->pDeviceHeader,
pReturnDevice,
pDeviceObject );
pDeviceContext->NextDeviceInStack = pReturnDevice;
//
// Here we try to detect the case where we really aren't
// an audio miniport, but rather helping out an swenum
// dude like dmusic. In the later case, we disallow
// (nonsensical) registration.
//
pDeviceContext->AllowRegisterDeviceInterface=TRUE;
if (NT_SUCCESS(QueryReferenceBusInterface(pReturnDevice,&BusInterface)))
{
BusInterface.Interface.InterfaceDereference( BusInterface.Interface.Context );
pDeviceContext->AllowRegisterDeviceInterface=FALSE;
}
}
pDeviceObject->Flags |= DO_DIRECT_IO;
pDeviceObject->Flags |= DO_POWER_PAGABLE;
pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
}
}
if (!NT_SUCCESS(ntStatus))
{
if (pDeviceContext->CreateItems)
{
delete [] pDeviceContext->CreateItems;
}
if (pDeviceContext->SymbolicLinkNames)
{
delete [] pDeviceContext->SymbolicLinkNames;
}
IoDeleteDevice(pDeviceObject);
}
else
{
PerfRegisterProvider(pDeviceObject);
}
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PcAddAdapterDevice IoCreateDevice failed with status 0x%08x",ntStatus));
}
return ntStatus;
}
#pragma code_seg()
/*****************************************************************************
* ForwardIrpCompletionRoutine()
*****************************************************************************
* Completion routine for ForwardIrp.
*/
static
NTSTATUS
ForwardIrpCompletionRoutine
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
ASSERT(DeviceObject);
ASSERT(Irp);
ASSERT(Context);
KeSetEvent((PKEVENT) Context,0,FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
/*****************************************************************************
* ForwardIrpAsynchronous()
*****************************************************************************
* Forward a PnP IRP to the PDO. The IRP is completed at this level
* regardless of the outcome, this function returns immediately regardless of
* whether the IRP is pending in the lower driver, and
* DecrementPendingIrpCount() is called in all cases.
*/
NTSTATUS
ForwardIrpAsynchronous
(
IN PDEVICE_CONTEXT pDeviceContext,
IN PIRP pIrp
)
{
ASSERT(pDeviceContext);
ASSERT(pIrp);
NTSTATUS ntStatus;
if (pDeviceContext->DeviceRemoveState == DeviceRemoved)
{
_DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpAsynchronous delete pending"));
ntStatus = CompleteIrp(pDeviceContext,pIrp,STATUS_DELETE_PENDING);
}
else
{
_DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpAsynchronous"));
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(pIrp);
IoSkipCurrentIrpStackLocation(pIrp);
if (irpSp->MajorFunction == IRP_MJ_POWER)
{
ntStatus = PoCallDriver(pDeviceContext->NextDeviceInStack,pIrp);
}
else
{
ntStatus = IoCallDriver(pDeviceContext->NextDeviceInStack,pIrp);
}
DecrementPendingIrpCount(pDeviceContext);
}
return ntStatus;
}
/*****************************************************************************
* ForwardIrpSynchronous()
*****************************************************************************
* Forward a PnP IRP to the PDO. The IRP is not completed at this level,
* this function does not return until the lower driver has completed the IRP,
* and DecrementPendingIrpCount() is not called.
*/
NTSTATUS
ForwardIrpSynchronous
(
IN PDEVICE_CONTEXT pDeviceContext,
IN PIRP pIrp
)
{
ASSERT(pDeviceContext);
ASSERT(pIrp);
NTSTATUS ntStatus;
if (pDeviceContext->DeviceRemoveState == DeviceRemoved)
{
ntStatus = STATUS_DELETE_PENDING;
_DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpSynchronous delete pending"));
}
else
{
_DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpSynchronous"));
PIO_STACK_LOCATION irpStackPointer = IoGetCurrentIrpStackLocation(pIrp);
// setup next stack location
IoCopyCurrentIrpStackLocationToNext( pIrp );
KEVENT kEvent;
KeInitializeEvent(&kEvent,NotificationEvent,FALSE);
IoSetCompletionRoutine
(
pIrp,
ForwardIrpCompletionRoutine,
&kEvent, // Context
TRUE, // InvokeOnSuccess
TRUE, // InvokeOnError
TRUE // InvokeOnCancel
);
if (irpStackPointer->MajorFunction == IRP_MJ_POWER)
{
ntStatus = PoCallDriver(pDeviceContext->NextDeviceInStack,pIrp);
}
else
{
ntStatus = IoCallDriver(pDeviceContext->NextDeviceInStack,pIrp);
}
if (ntStatus == STATUS_PENDING)
{
LARGE_INTEGER Timeout = RtlConvertLongToLargeInteger( 0L );
_DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpSynchronous pending..."));
KeWaitForSingleObject
(
&kEvent,
Suspended,
KernelMode,
FALSE,
(KeGetCurrentIrql() < DISPATCH_LEVEL) ? NULL : &Timeout
);
ntStatus = pIrp->IoStatus.Status;
_DbgPrintF(DEBUGLVL_VERBOSE,("ForwardIrpSynchronous complete"));
}
}
ASSERT(ntStatus != STATUS_PENDING);
return ntStatus;
}
#pragma code_seg("PAGE")
/*****************************************************************************
* PcForwardIrpSynchronous()
*****************************************************************************
* Forward a PnP IRP to the PDO. The IRP is not completed at this level,
* this function does not return until the lower driver has completed the IRP,
* and DecrementPendingIrpCount() is not called.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcForwardIrpSynchronous
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
ASSERT(DeviceObject);
ASSERT(Irp);
PAGED_CODE();
//
// Validate Parameters.
//
if (NULL == DeviceObject ||
NULL == Irp)
{
// don't know what to do, so we'll fail the IRP
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_INVALID_PARAMETER;
}
return
ForwardIrpSynchronous
(
PDEVICE_CONTEXT(DeviceObject->DeviceExtension),
Irp
);
}
/*****************************************************************************
* DispatchSystemControl()
*****************************************************************************
* Device objects that do not handle this IRP should leave it untouched.
*/
NTSTATUS
PcDispatchSystemControl
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
ASSERT(pDeviceObject);
ASSERT(pIrp);
PAGED_CODE();
_DbgPrintF(DEBUGLVL_VERBOSE,("DispatchSystemControl"));
PDEVICE_CONTEXT pDeviceContext =
PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
NTSTATUS ntStatus = PcValidateDeviceContext(pDeviceContext, pIrp);
if (!NT_SUCCESS(ntStatus))
{
// Don't know what to do, but this is probably a PDO.
// We'll try to make this right by completing the IRP
// untouched (per PnP, WMI, and Power rules). Note
// that if this isn't a PDO, and isn't a portcls FDO, then
// the driver messed up by using Portcls as a filter (huh?)
// In this case the verifier will fail us, WHQL will catch
// them, and the driver will be fixed. We'd be very surprised
// to see such a case.
// Assume FDO, no PoStartNextPowerIrp as this isn't IRP_MJ_POWER
ntStatus = pIrp->IoStatus.Status;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return ntStatus;
}
IncrementPendingIrpCount(pDeviceContext);
return ForwardIrpAsynchronous(pDeviceContext,pIrp);
}
/*****************************************************************************
* PnpStopDevice()
*****************************************************************************
* Stop the device.
*/
NTSTATUS
PnpStopDevice
(
IN PDEVICE_OBJECT pDeviceObject,
IN PNPSTOP_STYLE StopStyle
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpStopDevice stopping"));
PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
ASSERT(pDeviceContext);
ASSERT(pDeviceContext->StartDevice);
ASSERT(pDeviceContext->DeviceStopState != DeviceStopped);
pDeviceContext->PendCreates = TRUE;
pDeviceContext->StopCount++;
if (StopStyle == STOPSTYLE_PAUSE_FOR_REBALANCE)
{
//
// Blackcomb ISSUE
// Discovery AdriaO 06/29/1999
// We don't support this quite yet (see above, in
// PcAddAdapterDevice, where PauseForRebalance is set false).
// Commentary MartinP 11/28/2000
// So true. Our problem: PortCls might be restarted
// with different resources, even one less IRQ or DMA channel,
// when rebalance completes. In a way, this would require our
// stack to support dynamic graph changes, which it currently
// does not. AdriaO suggests we implement something along the
// lines of "IsFilterCompatible(RESOURCE_LIST)". It's too late
// for a change like this in Windows XP, let's fix this for
// Blackcomb and PortCls2.
//
ASSERT(0);
pDeviceContext->DeviceStopState = DevicePausedForRebalance;
}
else
{
pDeviceContext->DeviceStopState = DeviceStopped;
}
// stop the IoTimeout timer
if( pDeviceContext->IoTimeoutsOk )
{
IoStopTimer( pDeviceObject );
}
POWER_STATE newPowerState;
newPowerState.DeviceState = PowerDeviceD3;
PoSetPowerState(pDeviceObject,
DevicePowerState,
newPowerState
);
pDeviceContext->CurrentDeviceState = PowerDeviceD3;
//
// Delete all physical connections.
//
while (! IsListEmpty(&pDeviceContext->PhysicalConnectionList))
{
PPHYSICALCONNECTION pPhysicalConnection =
(PPHYSICALCONNECTION)RemoveHeadList(&pDeviceContext->PhysicalConnectionList);
ASSERT(pPhysicalConnection);
ASSERT(pPhysicalConnection->FromSubdevice);
ASSERT(pPhysicalConnection->ToSubdevice);
if (pPhysicalConnection->FromSubdevice)
{
pPhysicalConnection->FromSubdevice->Release();
}
if (pPhysicalConnection->ToSubdevice)
{
pPhysicalConnection->ToSubdevice->Release();
}
if (pPhysicalConnection->FromString)
{
DelUnicodeString(pPhysicalConnection->FromString);
}
if (pPhysicalConnection->ToString)
{
DelUnicodeString(pPhysicalConnection->ToString);
}
delete pPhysicalConnection;
}
//
// Disable and delete all the device interfaces.
//
while (! IsListEmpty(&pDeviceContext->DeviceInterfaceList))
{
PDEVICEINTERFACE pDeviceInterface =
(PDEVICEINTERFACE)
RemoveHeadList(&pDeviceContext->DeviceInterfaceList);
ASSERT(pDeviceInterface);
ASSERT(pDeviceInterface->SymbolicLinkName.Buffer);
NTSTATUS ntStatus = STATUS_SUCCESS;
if (pDeviceContext->AllowRegisterDeviceInterface)
{
ntStatus = IoSetDeviceInterfaceState(&pDeviceInterface->SymbolicLinkName,FALSE);
}
#if DBG
if (NT_SUCCESS(ntStatus))
{
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpStopDevice disabled device interface %S",pDeviceInterface->SymbolicLinkName.Buffer));
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PnpStopDevice failed to disable device interface %S (0x%08x)",pDeviceInterface->SymbolicLinkName.Buffer,ntStatus));
}
#endif
RtlFreeUnicodeString(&pDeviceInterface->SymbolicLinkName);
delete pDeviceInterface;
}
//
// Clear the symbolic link names table.
//
RtlZeroMemory
( pDeviceContext->SymbolicLinkNames
, sizeof(UNICODE_STRING) * pDeviceContext->MaxObjects
);
//
// Unload each subdevice for this device.
//
PKSOBJECT_CREATE_ITEM pKsObjectCreateItem =
pDeviceContext->CreateItems;
for
( ULONG ul = pDeviceContext->MaxObjects;
ul--;
pKsObjectCreateItem++
)
{
if (pKsObjectCreateItem->Create)
{
//
// Zero the create function so we won't get creates.
//
pKsObjectCreateItem->Create = NULL;
//
// Release the subdevice referenced by this create item.
//
ASSERT(pKsObjectCreateItem->Context);
PSUBDEVICE(pKsObjectCreateItem->Context)->ReleaseChildren();
PSUBDEVICE(pKsObjectCreateItem->Context)->Release();
}
}
//
// If the Adapter registered a Power Management interface
//
if( NULL != pDeviceContext->pAdapterPower )
{
// Release it
pDeviceContext->pAdapterPower->Release();
pDeviceContext->pAdapterPower = NULL;
}
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpStopDevice exiting"));
return STATUS_SUCCESS;
}
/*****************************************************************************
* PnpStartDevice()
*****************************************************************************
* Start the device in the PnP style.
*/
QUEUED_CALLBACK_RETURN
PnpStartDevice
(
IN PDEVICE_OBJECT pDeviceObject,
IN PVOID pNotUsed
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpStartDevice starting (0x%X)",pDeviceObject));
PDEVICE_CONTEXT pDeviceContext =
PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
ASSERT(pDeviceContext);
ASSERT(pDeviceContext->StartDevice);
ASSERT(pDeviceContext->DeviceStopState != DeviceStarted);
ASSERT(pDeviceContext->DeviceRemoveState == DeviceAdded);
pDeviceContext->DeviceStopState = DeviceStartPending;
PIRP pIrp = pDeviceContext->IrpStart;
ASSERT(pIrp);
PIO_STACK_LOCATION pIrpStack =
IoGetCurrentIrpStackLocation(pIrp);
//
// Encapsulate the resource lists.
//
PRESOURCELIST pResourceList;
NTSTATUS ntStatus;
BOOL bCompletePendedIrps=FALSE;
// in case there is no resource list in IO_STACK_LOCATION, PcNewResourceList
// just creates an empty resource list.
ntStatus = PcNewResourceList
(
&pResourceList,
NULL,
PagedPool,
pIrpStack->Parameters.StartDevice.AllocatedResourcesTranslated,
pIrpStack->Parameters.StartDevice.AllocatedResources
);
if (NT_SUCCESS(ntStatus))
{
ASSERT(pResourceList);
//
// Acquire the device to prevent creates during interface registration.
//
AcquireDevice(pDeviceContext);
//
// Start the adapter.
//
ntStatus = pDeviceContext->StartDevice(pDeviceObject,
pIrp,
pResourceList);
ASSERT(ntStatus != STATUS_PENDING);
pResourceList->Release();
pDeviceContext->DeviceStopState = DeviceStarted;
if (NT_SUCCESS(ntStatus))
{
// Start is always an implicit power up
POWER_STATE newPowerState;
pDeviceContext->CurrentDeviceState = PowerDeviceD0;
newPowerState.DeviceState = PowerDeviceD0;
PoSetPowerState(pDeviceObject,
DevicePowerState,
newPowerState
);
// start the IoTimeout timer
if( pDeviceContext->IoTimeoutsOk )
{
IoStartTimer( pDeviceObject );
}
// allow create
pDeviceContext->PendCreates = FALSE;
// Can't actually complete pended irps until we call ReleaseDevice, or we might deadlock
bCompletePendedIrps=TRUE;
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PnpStartDevice adapter failed to start (0x%08x)",ntStatus));
// stop the device (note: this will set DeviceStopState back to DeviceStopped)
PnpStopDevice(pDeviceObject, STOPSTYLE_DISABLE);
}
//
// Release the device to allow creates.
//
ReleaseDevice(pDeviceContext);
// Now we can complete pended irps
if (bCompletePendedIrps)
{
CompletePendedIrps( pDeviceObject,
pDeviceContext,
EMPTY_QUEUE_AND_PROCESS );
}
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PnpStartDevice failed to create resource list object (0x%08x)",ntStatus));
}
CompleteIrp(pDeviceContext,pIrp,ntStatus);
_DbgPrintF(DEBUGLVL_VERBOSE,("PnPStartDevice completing with 0x%X status for 0x%X",ntStatus,pDeviceObject));
return QUEUED_CALLBACK_FREE;
}
/*****************************************************************************
* PnpRemoveDevice()
*****************************************************************************
* Dispatch IRP_MJ_PNP/IRP_MN_REMOVE_DEVICE.
*/
NTSTATUS
PnpRemoveDevice
(
IN PDEVICE_OBJECT pDeviceObject
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice"));
PDEVICE_CONTEXT pDeviceContext =
PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
ASSERT( pDeviceContext );
pDeviceContext->DeviceRemoveState = DeviceRemoved;
if (InterlockedDecrement(PLONG(&pDeviceContext->PendingIrpCount)) != 0)
{
// setup for 15 second timeout (PASSIVE_LEVEL only!!)
LARGE_INTEGER Timeout = RtlConvertLongToLargeInteger( -15L * 10000000L );
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice pending irp count is %d, waiting up to 15 seconds",pDeviceContext->PendingIrpCount));
KeWaitForSingleObject( &pDeviceContext->kEventRemove,
Executive,
KernelMode,
FALSE,
(PASSIVE_LEVEL == KeGetCurrentIrql()) ? &Timeout : NULL );
}
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice pending irp count is 0"));
IoDetachDevice(pDeviceContext->NextDeviceInStack);
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice detached"));
if (pDeviceContext->CreateItems)
{
delete [] pDeviceContext->CreateItems;
}
if (pDeviceContext->SymbolicLinkNames)
{
delete [] pDeviceContext->SymbolicLinkNames;
}
PDRIVER_OBJECT pDriverObject = pDeviceObject->DriverObject;
if (pDeviceObject->NextDevice)
{
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice there is a next device"));
}
if (pDriverObject->DeviceObject != pDeviceObject)
{
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice there is a previous device"));
}
IoDeleteDevice(pDeviceObject);
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice device deleted"));
PerfUnregisterProvider(pDeviceObject);
if (pDriverObject->DeviceObject)
{
if (pDriverObject->DeviceObject != pDeviceObject)
{
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice driver object still has some other device object"));
}
else
{
_DbgPrintF(DEBUGLVL_VERBOSE,("PnpRemoveDevice driver object still has this device object"));
}
}
return STATUS_SUCCESS;
}
/*****************************************************************************
* DispatchPnp()
*****************************************************************************
* Supplying your PnP needs for over 20 min
*/
NTSTATUS
DispatchPnp
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
ASSERT(pIrp);
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION pIrpStack =
IoGetCurrentIrpStackLocation(pIrp);
PDEVICE_CONTEXT pDeviceContext =
PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
#if (DBG)
static PCHAR aszMnNames[] =
{
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
"IRP_MN_REMOVE_DEVICE",
"IRP_MN_CANCEL_REMOVE_DEVICE",
"IRP_MN_STOP_DEVICE",
"IRP_MN_QUERY_STOP_DEVICE",
"IRP_MN_CANCEL_STOP_DEVICE",
"IRP_MN_QUERY_DEVICE_RELATIONS",
"IRP_MN_QUERY_INTERFACE",
"IRP_MN_QUERY_CAPABILITIES",
"IRP_MN_QUERY_RESOURCES",
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
"IRP_MN_UNKNOWN_0x0e",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
"IRP_MN_SET_LOCK",
"IRP_MN_QUERY_ID",
"IRP_MN_QUERY_PNP_DEVICE_STATE",
"IRP_MN_QUERY_BUS_INFORMATION",
"IRP_MN_PAGING_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL"
};
if (pIrpStack->MinorFunction >= SIZEOF_ARRAY(aszMnNames))
{
_DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp function 0x%02x",pIrpStack->MinorFunction));
}
else
{
_DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp function %s",aszMnNames[pIrpStack->MinorFunction]));
}
#endif
ntStatus = PcValidateDeviceContext(pDeviceContext, pIrp);
if (!NT_SUCCESS(ntStatus))
{
// Don't know what to do, but this is probably a PDO.
// We'll try to make this right by completing the IRP
// untouched (per PnP, WMI, and Power rules). Note
// that if this isn't a PDO, and isn't a portcls FDO, then
// the driver messed up by using Portcls as a filter (huh?)
// In this case the verifier will fail us, WHQL will catch
// them, and the driver will be fixed. We'd be very surprised
// to see such a case.
// Assume FDO, no PoStartNextPowerIrp as this isn't IRP_MJ_POWER
ntStatus = pIrp->IoStatus.Status;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return ntStatus;
}
IncrementPendingIrpCount(pDeviceContext);
switch (pIrpStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
// if we are already started, something wrong happened
if( pDeviceContext->DeviceStopState == DeviceStarted )
{
//
// In theory, this is the path that would be exercized by non-stop
// rebalance. As it's the Fdo's choice to do so via
// IoInvalidateDeviceState(...), and as we don't do this, we should
// never ever be here unless something really strange happened...
//
// ASSERT(0);
// ntStatus = STATUS_INVALID_DEVICE_REQUEST;
_DbgPrintF(DEBUGLVL_TERSE,("DispatchPnP IRP_MN_START_DEVICE received when already started"));
//CompleteIrp( pDeviceContext, pIrp, ntStatus );
ntStatus = ForwardIrpSynchronous(pDeviceContext,pIrp); // for some reason we get nested starts
CompleteIrp( pDeviceContext, pIrp, ntStatus );
} else {
//
// Forward request and start.
//
ntStatus = ForwardIrpSynchronous(pDeviceContext,pIrp);
if (NT_SUCCESS(ntStatus))
{
// Do a real start. Begin by pending the irp
IoMarkIrpPending(pIrp);
pDeviceContext->IrpStart = pIrp;
// queue the start work item
_DbgPrintF(DEBUGLVL_VERBOSE,("Queueing WorkQueueItemStart for 0x%X",pDeviceObject));
ntStatus = CallbackEnqueue(
&pDeviceContext->pWorkQueueItemStart,
PnpStartDevice,
pDeviceObject,
NULL,
PASSIVE_LEVEL,
EQCF_DIFFERENT_THREAD_REQUIRED
);
if (!NT_SUCCESS(ntStatus)) {
_DbgPrintF(DEBUGLVL_TERSE,("DispatchPnp failed to queue callback (%08x)",ntStatus));
CompleteIrp( pDeviceContext, pIrp, ntStatus );
}
ntStatus = STATUS_PENDING;
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("DispatchPnp parent failed to start (%08x)",ntStatus));
CompleteIrp(pDeviceContext,pIrp,ntStatus);
}
}
break;
case IRP_MN_QUERY_STOP_DEVICE:
//
// Acquire the device to avoid race condition with Create
//
AcquireDevice( pDeviceContext );
LONG handleCount;
ntStatus = STATUS_SUCCESS;
//
// If we are tearing everything down, we must check for open handles,
// otherwise we do a quick activity check.
//
handleCount = (pDeviceContext->PauseForRebalance) ?
pDeviceContext->ActivePinCount :
pDeviceContext->ExistingObjectCount;
if ( handleCount != 0 ) {
//
// Sorry Joe User, we must fail this QUERY_STOP_DEVICE request
//
ntStatus = STATUS_DEVICE_BUSY;
CompleteIrp( pDeviceContext, pIrp, ntStatus );
}
else {
//
// Pass down the query.
//
pIrp->IoStatus.Status = STATUS_SUCCESS;
ntStatus = ForwardIrpSynchronous(pDeviceContext,pIrp);
if (NT_SUCCESS(ntStatus)) {
//
// pend new creates, this'll keep the active counts from changing.
//
pDeviceContext->PendCreates = TRUE;
_DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp query STOP succeeded",ntStatus));
pDeviceContext->DeviceStopState = DeviceStopPending;
}
else {
_DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp parent failed query STOP (0x%08x)",ntStatus));
}
CompleteIrp( pDeviceContext, pIrp, ntStatus );
}
ReleaseDevice( pDeviceContext );
break ;
case IRP_MN_CANCEL_STOP_DEVICE:
//ASSERT( DeviceStopPending == pDeviceContext->DeviceStopState );
if (pDeviceContext->DeviceStopState == DeviceStopPending)
{
pDeviceContext->DeviceStopState = DeviceStarted;
}
//
// allow creates if in D0
//
if( NT_SUCCESS(CheckCurrentPowerState(pDeviceObject)) )
{
pDeviceContext->PendCreates = FALSE;
//
// Pull any pended irps off the pended irp list and
// pass them back to PcDispatchIrp
//
CompletePendedIrps( pDeviceObject,
pDeviceContext,
EMPTY_QUEUE_AND_PROCESS );
}
// forward the irp
pIrp->IoStatus.Status = STATUS_SUCCESS;
ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
break ;
case IRP_MN_STOP_DEVICE:
if (pDeviceContext->PauseForRebalance &&
(pDeviceContext->DeviceStopState == DeviceStopPending))
{
ntStatus = PnpStopDevice(pDeviceObject, STOPSTYLE_PAUSE_FOR_REBALANCE);
}
else
{
//
// Either we've decided not to pause during rebalance, or this is
// a "naked" stop on Win9x, which occurs when the OS wishes to
// disable us.
//
//
// Stopping us will change our state and tear everything down
//
if (pDeviceContext->DeviceStopState != DeviceStopped)
{
ntStatus = PnpStopDevice(pDeviceObject, STOPSTYLE_DISABLE);
}
else
{
_DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp stop received in unstarted state"));
}
//
// Now fail any pended irps.
//
CompletePendedIrps( pDeviceObject,
pDeviceContext,
EMPTY_QUEUE_AND_FAIL );
}
if (NT_SUCCESS(ntStatus))
{
// forward the irp
pIrp->IoStatus.Status = STATUS_SUCCESS;
ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
}
else
{
CompleteIrp(pDeviceContext,pIrp,ntStatus);
}
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
//
// Acquire the device because we don't want to race with creates.
//
AcquireDevice(pDeviceContext);
if ( pDeviceContext->ExistingObjectCount != 0 ) {
//
// Somebody has open handles on us, so fail the QUERY_REMOVE_DEVICE
// request.
//
ntStatus = STATUS_DEVICE_BUSY;
} else {
//
// Lookin good, pass down the query.
//
pIrp->IoStatus.Status = STATUS_SUCCESS;
ntStatus = ForwardIrpSynchronous(pDeviceContext,pIrp);
if (NT_SUCCESS(ntStatus))
{
//
// Pend future creates.
//
pDeviceContext->PendCreates = TRUE;
_DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp query REMOVE succeeded",ntStatus));
pDeviceContext->DeviceRemoveState = DeviceRemovePending;
}
else
{
_DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp parent failed query REMOVE (0x%08x)",ntStatus));
}
}
ReleaseDevice(pDeviceContext);
CompleteIrp(pDeviceContext,pIrp,ntStatus);
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
//ASSERT( DeviceRemovePending == pDeviceContext->DeviceRemoveState );
pDeviceContext->DeviceRemoveState = DeviceAdded;
//
// allow creates if in D0
//
if( NT_SUCCESS(CheckCurrentPowerState(pDeviceObject)) )
{
pDeviceContext->PendCreates = FALSE;
//
// Pull any pended irps off the pended irp list and
// pass them back to PcDispatchIrp
//
CompletePendedIrps( pDeviceObject,
pDeviceContext,
EMPTY_QUEUE_AND_PROCESS );
}
// forward the irp
pIrp->IoStatus.Status = STATUS_SUCCESS;
ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
break;
case IRP_MN_SURPRISE_REMOVAL:
//
// Acquire the device
//
AcquireDevice(pDeviceContext);
pDeviceContext->DeviceRemoveState = DeviceSurpriseRemoved;
//
// Release the device
//
ReleaseDevice(pDeviceContext);
//
// Fail any pended irps.
//
CompletePendedIrps( pDeviceObject,
pDeviceContext,
EMPTY_QUEUE_AND_FAIL );
if (pDeviceContext->DeviceStopState != DeviceStopped)
{
PnpStopDevice(pDeviceObject, STOPSTYLE_DISABLE);
}
pIrp->IoStatus.Status = STATUS_SUCCESS;
ntStatus = ForwardIrpAsynchronous( pDeviceContext, pIrp );
break;
case IRP_MN_REMOVE_DEVICE:
//
// Perform stop if required.
//
if (pDeviceContext->DeviceStopState != DeviceStopped)
{
_DbgPrintF(DEBUGLVL_VERBOSE,("DispatchPnp remove received in started state"));
PnpStopDevice(pDeviceObject, STOPSTYLE_DISABLE);
}
//
// Fail any pended irps.
//
CompletePendedIrps( pDeviceObject,
pDeviceContext,
EMPTY_QUEUE_AND_FAIL );
//
// Free device header, must be done before forwarding irp
//
if( pDeviceContext->pDeviceHeader )
{
KsFreeDeviceHeader(pDeviceContext->pDeviceHeader);
}
//
// Forward the request.
//
pIrp->IoStatus.Status = STATUS_SUCCESS;
ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
//
// Remove the device.
//
PnpRemoveDevice(pDeviceObject);
break;
case IRP_MN_QUERY_CAPABILITIES:
//
// Fill out power management / ACPI stuff
// for this device.
//
ntStatus = GetDeviceACPIInfo( pIrp, pDeviceObject );
break;
case IRP_MN_READ_CONFIG:
case IRP_MN_WRITE_CONFIG:
case IRP_MN_QUERY_DEVICE_RELATIONS:
case IRP_MN_QUERY_INTERFACE:
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
//
// TODO: Make sure functions listed below are ok left unhandled.
//
case IRP_MN_QUERY_RESOURCES:
case IRP_MN_QUERY_DEVICE_TEXT:
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
case IRP_MN_EJECT:
case IRP_MN_SET_LOCK:
case IRP_MN_QUERY_ID:
case IRP_MN_QUERY_PNP_DEVICE_STATE:
case IRP_MN_QUERY_BUS_INFORMATION:
// case IRP_MN_PAGING_NOTIFICATION:
default:
ntStatus = ForwardIrpAsynchronous(pDeviceContext,pIrp);
break;
}
return ntStatus;
}
/*****************************************************************************
* SubdeviceIndex()
*****************************************************************************
* Returns the index of a subdevice in the create items list or ULONG(-1) if
* not found.
*/
ULONG
SubdeviceIndex
(
IN PDEVICE_OBJECT DeviceObject,
IN PSUBDEVICE Subdevice
)
{
ASSERT(DeviceObject);
ASSERT(Subdevice);
PDEVICE_CONTEXT pDeviceContext =
PDEVICE_CONTEXT(DeviceObject->DeviceExtension);
ASSERT(pDeviceContext);
PKSOBJECT_CREATE_ITEM createItem =
pDeviceContext->CreateItems;
for
(
ULONG index = 0;
index < pDeviceContext->MaxObjects;
index++, createItem++
)
{
if (PSUBDEVICE(createItem->Context) == Subdevice)
{
break;
}
}
if (index == pDeviceContext->MaxObjects)
{
index = ULONG(-1);
}
return index;
}
/*****************************************************************************
* PcRegisterSubdevice()
*****************************************************************************
* Registers a subdevice.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcRegisterSubdevice
(
IN PDEVICE_OBJECT DeviceObject,
IN PWCHAR Name,
IN PUNKNOWN Unknown
)
{
PAGED_CODE();
ASSERT(DeviceObject);
ASSERT(Name);
ASSERT(Unknown);
_DbgPrintF(DEBUGLVL_VERBOSE,("PcRegisterSubdevice %S",Name));
//
// Validate Parameters.
//
if (NULL == DeviceObject ||
NULL == Name ||
NULL == Unknown)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterSubDevice : Invalid Parameter."));
return STATUS_INVALID_PARAMETER;
}
PSUBDEVICE pSubdevice;
NTSTATUS ntStatus =
Unknown->QueryInterface
(
IID_ISubdevice,
(PVOID *) &pSubdevice
);
if (NT_SUCCESS(ntStatus))
{
ntStatus =
AddIrpTargetFactoryToDevice
(
DeviceObject,
pSubdevice,
Name,
NULL // TODO: Security.
);
const SUBDEVICE_DESCRIPTOR *pSubdeviceDescriptor;
if (NT_SUCCESS(ntStatus))
{
ntStatus = pSubdevice->GetDescriptor(&pSubdeviceDescriptor);
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PcRegisterSubdevice AddIrpTargetFactoryToDevice failed (0x%08x)",ntStatus));
}
if (NT_SUCCESS(ntStatus) && pSubdeviceDescriptor->Topology->CategoriesCount)
{
PDEVICE_CONTEXT pDeviceContext =
PDEVICE_CONTEXT(DeviceObject->DeviceExtension);
ULONG index = SubdeviceIndex(DeviceObject,pSubdevice);
ASSERT(pSubdeviceDescriptor->Topology->Categories);
ASSERT(pDeviceContext);
UNICODE_STRING referenceString;
RtlInitUnicodeString(&referenceString,Name);
const GUID *pGuidCategories =
pSubdeviceDescriptor->Topology->Categories;
for
( ULONG ul = pSubdeviceDescriptor->Topology->CategoriesCount
; ul--
; pGuidCategories++
)
{
UNICODE_STRING linkName;
if (pDeviceContext->AllowRegisterDeviceInterface)
{
ntStatus
= IoRegisterDeviceInterface
(
pDeviceContext->PhysicalDeviceObject,
pGuidCategories,
&referenceString,
&linkName
);
if (NT_SUCCESS(ntStatus))
{
ntStatus =
IoSetDeviceInterfaceState
(
&linkName,
TRUE
);
if (NT_SUCCESS(ntStatus))
{
_DbgPrintF(DEBUGLVL_VERBOSE,("PcRegisterSubdevice device interface %S set to state TRUE",linkName.Buffer));
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PcRegisterSubdevice IoSetDeviceInterfaceState failed (0x%08x)",ntStatus));
}
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PcRegisterSubdevice IoRegisterDeviceInterface failed (0x%08x)",ntStatus));
}
}
else
{
linkName.Length = wcslen(Name) * sizeof(WCHAR);
linkName.MaximumLength = linkName.Length + sizeof(UNICODE_NULL);
linkName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, linkName.MaximumLength,'NLcP'); // 'PcLN'
if (!linkName.Buffer)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
wcscpy(linkName.Buffer,Name);
}
}
if (NT_SUCCESS(ntStatus))
{
//
// Save the first symbolic link name in the table.
//
if (! pDeviceContext->SymbolicLinkNames[index].Buffer)
{
pDeviceContext->SymbolicLinkNames[index] = linkName;
}
//
// Save the interface in a list for cleanup.
//
PDEVICEINTERFACE pDeviceInterface = new(PagedPool,'iDcP') DEVICEINTERFACE;
if (pDeviceInterface)
{
pDeviceInterface->Interface = *pGuidCategories;
pDeviceInterface->SymbolicLinkName = linkName;
pDeviceInterface->Subdevice = pSubdevice;
InsertTailList
(
&pDeviceContext->DeviceInterfaceList,
&pDeviceInterface->ListEntry
);
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PcRegisterSubdevice failed to allocate device interface structure for later cleanup"));
RtlFreeUnicodeString(&linkName);
}
}
}
}
pSubdevice->Release();
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("QI for IID_ISubdevice failed on UNKNOWN 0x%08x",pSubdevice));
}
return ntStatus;
}
/*****************************************************************************
* RegisterPhysicalConnection_()
*****************************************************************************
* Registers a physical connection between subdevices or external devices.
*/
static
NTSTATUS
RegisterPhysicalConnection_
(
IN PDEVICE_OBJECT pDeviceObject,
IN PUNKNOWN pUnknownFrom OPTIONAL,
IN PUNICODE_STRING pUnicodeStringFrom OPTIONAL,
IN ULONG ulFromPin,
IN PUNKNOWN pUnknownTo OPTIONAL,
IN PUNICODE_STRING pUnicodeStringTo OPTIONAL,
IN ULONG ulToPin
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
ASSERT(pUnknownFrom || pUnicodeStringFrom);
ASSERT(pUnknownTo || pUnicodeStringTo);
ASSERT(! (pUnknownFrom && pUnicodeStringFrom));
ASSERT(! (pUnknownTo && pUnicodeStringTo));
PDEVICE_CONTEXT pDeviceContext =
PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
ASSERT(pDeviceContext);
PSUBDEVICE pSubdeviceFrom = NULL;
PSUBDEVICE pSubdeviceTo = NULL;
NTSTATUS ntStatus = STATUS_SUCCESS;
if (pUnknownFrom)
{
ntStatus =
pUnknownFrom->QueryInterface
(
IID_ISubdevice,
(PVOID *) &pSubdeviceFrom
);
}
else
{
ntStatus =
DupUnicodeString
(
&pUnicodeStringFrom,
pUnicodeStringFrom
);
}
if (NT_SUCCESS(ntStatus))
{
if (pUnknownTo)
{
ntStatus =
pUnknownTo->QueryInterface
(
IID_ISubdevice,
(PVOID *) &pSubdeviceTo
);
}
else
{
ntStatus =
DupUnicodeString
(
&pUnicodeStringTo,
pUnicodeStringTo
);
}
}
else
{
pUnicodeStringTo = NULL;
}
if (NT_SUCCESS(ntStatus))
{
PPHYSICALCONNECTION pPhysicalConnection =
new(PagedPool,'cPcP') PHYSICALCONNECTION;
if (pPhysicalConnection)
{
pPhysicalConnection->FromSubdevice = pSubdeviceFrom;
pPhysicalConnection->FromString = pUnicodeStringFrom;
pPhysicalConnection->FromPin = ulFromPin;
pPhysicalConnection->ToSubdevice = pSubdeviceTo;
pPhysicalConnection->ToString = pUnicodeStringTo;
pPhysicalConnection->ToPin = ulToPin;
if (pPhysicalConnection->FromSubdevice)
{
pPhysicalConnection->FromSubdevice->AddRef();
}
if (pPhysicalConnection->ToSubdevice)
{
pPhysicalConnection->ToSubdevice->AddRef();
}
//
// So they don't get deleted.
//
pUnicodeStringFrom = NULL;
pUnicodeStringTo = NULL;
InsertTailList
(
&pDeviceContext->PhysicalConnectionList,
&pPhysicalConnection->ListEntry
);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (pSubdeviceFrom)
{
pSubdeviceFrom->Release();
}
if (pSubdeviceTo)
{
pSubdeviceTo->Release();
}
if (pUnicodeStringFrom)
{
DelUnicodeString(pUnicodeStringFrom);
}
if (pUnicodeStringTo)
{
DelUnicodeString(pUnicodeStringTo);
}
return ntStatus;
}
/*****************************************************************************
* PcRegisterPhysicalConnection()
*****************************************************************************
* Registers a physical connection between subdevices.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcRegisterPhysicalConnection
(
IN PDEVICE_OBJECT pDeviceObject,
IN PUNKNOWN pUnknownFrom,
IN ULONG ulFromPin,
IN PUNKNOWN pUnknownTo,
IN ULONG ulToPin
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
ASSERT(pUnknownFrom);
ASSERT(pUnknownTo);
//
// Validate Parameters.
//
if (NULL == pDeviceObject ||
NULL == pUnknownFrom ||
NULL == pUnknownTo)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterPhysicalConnection : Invalid Parameter."));
return STATUS_INVALID_PARAMETER;
}
return
RegisterPhysicalConnection_
(
pDeviceObject,
pUnknownFrom,
NULL,
ulFromPin,
pUnknownTo,
NULL,
ulToPin
);
}
/*****************************************************************************
* PcRegisterPhysicalConnectionToExternal()
*****************************************************************************
* Registers a physical connection from a subdevice to an external device.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcRegisterPhysicalConnectionToExternal
(
IN PDEVICE_OBJECT pDeviceObject,
IN PUNKNOWN pUnknownFrom,
IN ULONG ulFromPin,
IN PUNICODE_STRING pUnicodeStringTo,
IN ULONG ulToPin
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
ASSERT(pUnknownFrom);
ASSERT(pUnicodeStringTo);
//
// Validate Parameters.
//
if (NULL == pDeviceObject ||
NULL == pUnknownFrom ||
NULL == pUnicodeStringTo)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterPhysicalConnectionToExternal : Invalid Parameter."));
return STATUS_INVALID_PARAMETER;
}
return
RegisterPhysicalConnection_
(
pDeviceObject,
pUnknownFrom,
NULL,
ulFromPin,
NULL,
pUnicodeStringTo,
ulToPin
);
}
/*****************************************************************************
* PcRegisterPhysicalConnectionFromExternal()
*****************************************************************************
* Registers a physical connection to a subdevice from an external device.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcRegisterPhysicalConnectionFromExternal
(
IN PDEVICE_OBJECT pDeviceObject,
IN PUNICODE_STRING pUnicodeStringFrom,
IN ULONG ulFromPin,
IN PUNKNOWN pUnknownTo,
IN ULONG ulToPin
)
{
PAGED_CODE();
ASSERT(pDeviceObject);
ASSERT(pUnicodeStringFrom);
ASSERT(pUnknownTo);
//
// Validate Parameters.
//
if (NULL == pDeviceObject ||
NULL == pUnicodeStringFrom ||
NULL == pUnknownTo)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterPhysicalConnectionFromExternal : Invalid Parameter."));
return STATUS_INVALID_PARAMETER;
}
return
RegisterPhysicalConnection_
(
pDeviceObject,
NULL,
pUnicodeStringFrom,
ulFromPin,
pUnknownTo,
NULL,
ulToPin
);
}
#pragma code_seg()