Windows2003-3790/drivers/ksfilter/swenum/swenum.c
2020-09-30 16:53:55 +02:00

703 lines
16 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (C) Microsoft Corporation, 1997 - 2001
Module Name:
swenum.c
Abstract:
Demand load software device enumerator.
Author:
Bryan A. Woodruff (bryanw) 20-Feb-1997
--*/
#define KSDEBUG_INIT
#include "private.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, AddDevice )
#pragma alloc_text( PAGE, DispatchCreate )
#pragma alloc_text( PAGE, DispatchClose )
#pragma alloc_text( PAGE, DispatchIoControl )
#pragma alloc_text( PAGE, DispatchPnP )
#pragma alloc_text( INIT, DriverEntry )
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Main driver entry, sets up the bus device object and performs
first enumeration.
Arguments:
IN PDRIVER_OBJECT DriverObject -
pointer to driver object
IN PUNICODE_STRING RegistryPath -
pointer to registry path
Return:
STATUS_SUCCESS else an appropriate error code
--*/
{
//
// win98gold ntkern does not fill in the Service name in our
// driver extension. but we depend on the name to have correct
// KsCreateBusEnumObject. Try to add the Service name here.
// Since we are statically loaded, freeing the memory is rarely
// necessary.
//
#ifdef WIN98GOLD
if ( NULL == DriverObject->DriverExtension->ServiceKeyName.Buffer ) {
UNICODE_STRING ServiceNameU;
ULONG cb;
cb = RegistryPath->Length;
ServiceNameU.Buffer = ExAllocatePool( NonPagedPool, cb );
if ( NULL == ServiceNameU.Buffer ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory( ServiceNameU.Buffer, RegistryPath->Buffer, cb );
ServiceNameU.MaximumLength = ServiceNameU.Length = (USHORT)cb;
DriverObject->DriverExtension->ServiceKeyName = ServiceNameU;
}
#endif
_DbgPrintF(
DEBUGLVL_VERBOSE,
("DriverEntry, registry path = %S", RegistryPath->Buffer) );
//
// Fill in the driver object
//
DriverObject->MajorFunction[ IRP_MJ_PNP ] = DispatchPnP;
DriverObject->MajorFunction[ IRP_MJ_POWER ] = DispatchPower;
DriverObject->MajorFunction[ IRP_MJ_CREATE ] = DispatchCreate;
DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] = DispatchIoControl;
DriverObject->MajorFunction[ IRP_MJ_SYSTEM_CONTROL ] = DispatchSystemControl;
DriverObject->MajorFunction[ IRP_MJ_CLOSE ] = DispatchClose;
DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This is the driver unload routine for SWENUM. It does nothing.
Arguments:
IN PDRIVER_OBJECT DriverObject -
pointer to the driver object
Return:
Nothing.
--*/
{
return;
}
NTSTATUS
AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
Called by the PnP manager when a new device is instantiated.
Arguments:
IN PDRIVER_OBJECT DriverObject -
pointer to the driver object
IN PDEVICE_OBJECT PhysicalDeviceObject -
pointer to the physical device object
Return:
STATUS_SUCCESS else an appropriate error code
--*/
{
PDEVICE_OBJECT FunctionalDeviceObject;
NTSTATUS Status;
PAGED_CODE();
//
// On AddDevice, we are given the physical device object (PDO)
// for the bus. Create the associcated functional device object (FDO).
//
_DbgPrintF( DEBUGLVL_VERBOSE, ("AddDevice") );
//
// Note, there is only one instance of this device allowed. The
// static device name will guarantee an object name collision if
// another instance is already installed.
//
Status = IoCreateDevice(
DriverObject, // our driver object
sizeof( PVOID ), // size of our extension
NULL, // our name for the FDO
FILE_DEVICE_BUS_EXTENDER, // device type
0, // device characteristics
FALSE, // not exclusive
&FunctionalDeviceObject // store new device object here
);
if(!NT_SUCCESS( Status )) {
_DbgPrintF(
DEBUGLVL_ERROR,
("failed to create FDO, status = %x.", Status) );
return Status;
}
//
// Clear the device extension
//
*(PVOID *)FunctionalDeviceObject->DeviceExtension = NULL;
//
// Create the bus enumerator object
//
Status =
KsCreateBusEnumObject(
L"SW",
FunctionalDeviceObject,
PhysicalDeviceObject,
NULL, // PDEVICE_OBJECT PnpDeviceObject
&BUSID_SoftwareDeviceEnumerator,
L"Devices" );
if (!NT_SUCCESS( Status )) {
_DbgPrintF(
DEBUGLVL_ERROR,
("failed KsCreateBusEnumObject: %08x", Status) );
IoDeleteDevice( FunctionalDeviceObject );
return Status;
}
FunctionalDeviceObject->Flags |= DO_POWER_PAGABLE;
FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
NTSTATUS
DispatchPnP(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
/*++
Routine Description:
This is the main entry point for the IRP_MJ_PNP dispatch, the exported
service is used for processing.
Arguments:
IN PDEVICE_OBJECT DeviceObject -
pointer to the device object
IN OUT PIRP Irp -
pointer to the associated Irp
Return:
NTSTATUS code
--*/
{
BOOLEAN ChildDevice;
PIO_STACK_LOCATION irpSp;
NTSTATUS Status;
PDEVICE_OBJECT PnpDeviceObject;
irpSp = IoGetCurrentIrpStackLocation( Irp );
//
// Get the PnpDeviceObject and determine FDO/PDO.
//
Status = KsIsBusEnumChildDevice( DeviceObject, &ChildDevice );
//
// If we're unable to obtain any of this information, fail now.
//
if (!NT_SUCCESS( Status )) {
return CompleteIrp( Irp, Status, IO_NO_INCREMENT );
}
Status = KsServiceBusEnumPnpRequest( DeviceObject, Irp );
//
// FDO processing may return STATUS_NOT_SUPPORTED or may require
// overrides.
//
if (!ChildDevice) {
NTSTATUS tempStatus;
//
// FDO case
//
// First retrieve the DO we will forward everything to...
//
tempStatus = KsGetBusEnumPnpDeviceObject( DeviceObject, &PnpDeviceObject );
if (!NT_SUCCESS( tempStatus )) {
//
// No DO to forward to. Actually a fatal error, but just complete
// with an error status.
//
return CompleteIrp( Irp, tempStatus, IO_NO_INCREMENT );
}
switch (irpSp->MinorFunction) {
case IRP_MN_QUERY_RESOURCES:
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
//
// This is normally passed on to the PDO, but since this is a
// software only device, resources are not required.
//
Irp->IoStatus.Information = (ULONG_PTR)NULL;
Status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
{
//
// Mark the device as not disableable.
//
PPNP_DEVICE_STATE DeviceState;
DeviceState = (PPNP_DEVICE_STATE) &Irp->IoStatus.Information;
*DeviceState |= PNP_DEVICE_NOT_DISABLEABLE;
Status = STATUS_SUCCESS;
}
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
//
// Forward everything...
//
break;
case IRP_MN_REMOVE_DEVICE:
//
// The KsBusEnum services cleaned up attachments, etc. However,
// we must remove our own FDO.
//
Status = STATUS_SUCCESS;
IoDeleteDevice( DeviceObject );
break;
}
if (Status != STATUS_NOT_SUPPORTED) {
//
// Set the Irp status only if we have something to add.
//
Irp->IoStatus.Status = Status;
}
//
// Forward this IRP down the stack only if we are successful or
// we don't know how to handle this Irp.
//
if (NT_SUCCESS( Status ) || (Status == STATUS_NOT_SUPPORTED)) {
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver( PnpDeviceObject, Irp );
}
//
// On error, fall through and complete the IRP with the status.
//
}
//
// KsServiceBusEnumPnpRequest() handles all other child PDO requests.
//
if (Status != STATUS_NOT_SUPPORTED) {
Irp->IoStatus.Status = Status;
} else {
Status = Irp->IoStatus.Status;
}
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return Status;
}
NTSTATUS
DispatchSystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Handler for system control IRPs.
Arguments:
IN PDEVICE_OBJECT DeviceObject -
pointer to the device object
IN PIRP Irp -
pointer to the I/O request packet for IRP_MJ_SYSTEM_CONTROL
Return:
NTSTATUS code
--*/
{
BOOLEAN ChildDevice;
PIO_STACK_LOCATION irpSp;
NTSTATUS Status;
PDEVICE_OBJECT PnpDeviceObject;
//
// Get the PnpDeviceObject and determine FDO/PDO.
//
Status = KsIsBusEnumChildDevice( DeviceObject, &ChildDevice );
//
// If we're unable to obtain any of this information, fail now.
//
if (!NT_SUCCESS( Status )) {
return CompleteIrp( Irp, Status, IO_NO_INCREMENT );
}
if (!ChildDevice) {
//
// FDO case
//
// We will need the DO we will forward everything to...
//
Status = KsGetBusEnumPnpDeviceObject( DeviceObject, &PnpDeviceObject );
if (!NT_SUCCESS( Status )) {
//
// No DO to forward to. Actually a fatal error, but just complete
// with an error status.
//
return CompleteIrp( Irp, Status, IO_NO_INCREMENT );
}
//
// Forward this IRP down the stack.
//
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver( PnpDeviceObject, Irp );
}
Status = Irp->IoStatus.Status;
return CompleteIrp( Irp, Status, IO_NO_INCREMENT );
}
NTSTATUS
DispatchPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Dispatch handler for IRP_MJ_POWER
Arguments:
IN PDEVICE_OBJECT DeviceObject -
pointer to the device object
IN PIRP Irp -
pointer to the I/O request packet
Return:
NTSTATUS code
--*/
{
BOOLEAN ChildDevice;
PIO_STACK_LOCATION irpSp;
NTSTATUS Status;
PDEVICE_OBJECT PnpDeviceObject;
irpSp = IoGetCurrentIrpStackLocation( Irp );
//
// Get the PnpDeviceObject and determine FDO/PDO.
//
Status = KsIsBusEnumChildDevice( DeviceObject, &ChildDevice );
//
// If we're unable to obtain any of this information, fail now.
//
if (!NT_SUCCESS( Status )) {
PoStartNextPowerIrp(Irp);
return CompleteIrp( Irp, Status, IO_NO_INCREMENT );
}
if (!ChildDevice) {
NTSTATUS tempStatus;
//
// FDO case
//
// We will need the DO we will forward everything to...
//
tempStatus = KsGetBusEnumPnpDeviceObject( DeviceObject, &PnpDeviceObject );
if (!NT_SUCCESS( tempStatus )) {
//
// No DO to forward to. Actually a fatal error, but just complete
// with an error status.
//
PoStartNextPowerIrp(Irp);
return CompleteIrp( Irp, tempStatus, IO_NO_INCREMENT );
}
}
switch (irpSp->MinorFunction) {
case IRP_MN_QUERY_POWER:
case IRP_MN_SET_POWER:
switch (irpSp->Parameters.Power.Type) {
case DevicePowerState:
case SystemPowerState:
Status = STATUS_SUCCESS;
break;
default:
Status = STATUS_NOT_SUPPORTED;
break;
}
break;
default:
Status = STATUS_NOT_SUPPORTED;
break;
}
if (Status != STATUS_NOT_SUPPORTED) {
Irp->IoStatus.Status = Status;
}
if ((!ChildDevice) && (NT_SUCCESS(Status) || (Status == STATUS_NOT_SUPPORTED))) {
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver( PnpDeviceObject, Irp );
} else {
Status = Irp->IoStatus.Status;
PoStartNextPowerIrp( Irp );
return CompleteIrp( Irp, Status, IO_NO_INCREMENT );
}
}
NTSTATUS
DispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
/*++
Routine Description:
Processes the create request for the SWENUM device.
Arguments:
IN PDEVICE_OBJECT DeviceObject -
pointer to the device object
IN OUT PIRP Irp -
pointer to the I/O request packet
Return:
NTSTATUS code
--*/
{
BOOLEAN ChildDevice;
NTSTATUS Status;
PIO_STACK_LOCATION irpSp;
PAGED_CODE();
Status = KsIsBusEnumChildDevice( DeviceObject, &ChildDevice );
if (NT_SUCCESS( Status )) {
irpSp = IoGetCurrentIrpStackLocation( Irp );
if (!ChildDevice) {
if (!irpSp->FileObject->FileName.Length) {
//
// This is a request for the bus, if and only if there
// is no filename specified.
//
Status = STATUS_SUCCESS;
} else {
//
// Redirection to the child PDO.
//
Status = KsServiceBusEnumCreateRequest( DeviceObject, Irp );
}
} else {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
}
}
if (Status != STATUS_PENDING) {
Irp->IoStatus.Status = Status;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
}
return Status;
}
NTSTATUS
DispatchIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
/*++
Routine Description:
Process I/O control requests for the SWENUM device.
Arguments:
IN PDEVICE_OBJECT DeviceObject -
pointer to the device object
IN OUT PIRP Irp -
pointer to the I/O request packet
Return:
STATUS_SUCCESS or STATUS_INVALID_DEVICE_REQUEST
--*/
{
NTSTATUS Status;
PIO_STACK_LOCATION irpSp;
PAGED_CODE();
irpSp = IoGetCurrentIrpStackLocation( Irp );
_DbgPrintF( DEBUGLVL_BLAB, ("DispatchIoControl") );
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_SWENUM_INSTALL_INTERFACE:
Status = KsInstallBusEnumInterface( Irp );
break;
case IOCTL_SWENUM_GET_BUS_ID:
Status = KsGetBusEnumIdentifier( Irp );
break;
case IOCTL_SWENUM_REMOVE_INTERFACE:
Status = KsRemoveBusEnumInterface( Irp );
break;
default:
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
return CompleteIrp( Irp, Status, IO_NO_INCREMENT );
}
NTSTATUS
DispatchClose(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
/*++
Routine Description:
Processes the close request for the SWENUM device.
Arguments:
IN PDEVICE_OBJECT DeviceObject -
pointer to the device object
IN OUT PIRP Irp -
pointer to the I/O request packet
Return:
STATUS_SUCCESS
--*/
{
PAGED_CODE();
_DbgPrintF( DEBUGLVL_BLAB, ("DispatchClose") );
return CompleteIrp( Irp, STATUS_SUCCESS, IO_NO_INCREMENT );
}