mirror of https://github.com/tongzx/nt5src
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.
3971 lines
107 KiB
3971 lines
107 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
DBCLASS.C
|
|
|
|
Abstract:
|
|
|
|
class driver for device bay controllers
|
|
|
|
This module implements the code to function as
|
|
the Device Bay controller class driver
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#include <wdm.h>
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
|
|
#include "dbci.h"
|
|
#include "dbclass.h" //private data strutures
|
|
#include "dbfilter.h"
|
|
#include "usbioctl.h"
|
|
|
|
#include "1394.h"
|
|
|
|
#include <initguid.h>
|
|
#include <wdmguid.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DBCLASS_SyncSubmitDrb)
|
|
#pragma alloc_text(PAGE, DBCLASS_SyncGetSubsystemDescriptor)
|
|
#pragma alloc_text(PAGE, DBCLASS_SyncGetBayDescriptor)
|
|
#pragma alloc_text(PAGE, DBCLASS_SyncGetAllBayDescriptors)
|
|
#pragma alloc_text(PAGE, DBCLASS_SyncBayFeatureRequest)
|
|
#pragma alloc_text(PAGE, DBCLASS_SyncGetBayStatus)
|
|
#endif
|
|
|
|
|
|
/*
|
|
Global Data Structures
|
|
*/
|
|
|
|
PDBC_CONTEXT DBCLASS_ControllerList;
|
|
KSPIN_LOCK DBCLASS_ControllerListSpin;
|
|
|
|
// Internal list of Device PDOs
|
|
LIST_ENTRY DBCLASS_DevicePdoList;
|
|
|
|
//Internal list of Bus filter MDOs
|
|
LIST_ENTRY DBCLASS_BusFilterMdoList;
|
|
|
|
//
|
|
// We currently only allow one USB hub to be associated with
|
|
// an ACPI Device Bay Controller.
|
|
// This hub may be the root hub or a real hub connected to one of
|
|
// the root hub ports (ie Tier 1 only)
|
|
//
|
|
// We use the following global variable (since we only support
|
|
// one ACPI DBC) to indicate the upstream port for the hub
|
|
// 0 indicates the hub is the root hub
|
|
// -1 indicates no ACPI DBC present
|
|
//
|
|
|
|
LONG DBCLASS_AcpiDBCHubParentPort = -1;
|
|
|
|
// set up the debug variables
|
|
|
|
#if DBG
|
|
ULONG DBCLASS_TotalHeapSace = 0;
|
|
ULONG DBCLASS_BreakOn = 0;
|
|
|
|
// #define DEBUG3
|
|
|
|
#ifdef DEBUG1
|
|
ULONG DBCLASS_Debug_Trace_Level = 1;
|
|
#else
|
|
#ifdef DEBUG2
|
|
ULONG DBCLASS_Debug_Trace_Level = 2;
|
|
#else
|
|
#ifdef DEBUG3
|
|
ULONG DBCLASS_Debug_Trace_Level = 3;
|
|
#else
|
|
ULONG DBCLASS_Debug_Trace_Level = 0;
|
|
#endif /* DEBUG 3 */
|
|
#endif /* DEBUG2 */
|
|
#endif /* DEBUG1 */
|
|
|
|
#endif /* DBG */
|
|
|
|
|
|
VOID
|
|
DBCLASS_Wait(
|
|
IN ULONG MilliSeconds
|
|
)
|
|
/* ++
|
|
*
|
|
* Descriptor:
|
|
*
|
|
* This causes the thread execution delayed for MiliSeconds.
|
|
*
|
|
* Argument:
|
|
*
|
|
* Mili-seconds to delay.
|
|
*
|
|
* Return:
|
|
*
|
|
* VOID
|
|
*
|
|
* -- */
|
|
{
|
|
LARGE_INTEGER time;
|
|
ULONG timerIncerent;
|
|
|
|
DBCLASS_KdPrint((2,"'Wait for %d ms\n", MilliSeconds));
|
|
|
|
//
|
|
// work only when LowPart is not overflown.
|
|
//
|
|
DBCLASS_ASSERT(21474 > MilliSeconds);
|
|
|
|
//
|
|
// wait ulMiliSeconds( 10000 100ns unit)
|
|
//
|
|
timerIncerent = KeQueryTimeIncrement() - 1;
|
|
|
|
time.HighPart = -1;
|
|
// round up to the next highest timer increment
|
|
time.LowPart = -1 * (10000 * MilliSeconds + timerIncerent);
|
|
KeDelayExecutionThread(KernelMode, FALSE, &time);
|
|
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsBitSet(
|
|
PVOID Bitmap,
|
|
ULONG BitNumber
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* Check if a bit is set given a string of bytes.
|
|
*
|
|
* Arguments:
|
|
*
|
|
*
|
|
*
|
|
* Return:
|
|
*
|
|
* TRUE - if the corresponding bit is set. FALSE - otherwise
|
|
*
|
|
* -- */
|
|
{
|
|
ULONG dwordOffset;
|
|
ULONG bitOffset;
|
|
PULONG l = (PULONG) Bitmap;
|
|
|
|
|
|
dwordOffset = BitNumber / 32;
|
|
bitOffset = BitNumber % 32;
|
|
|
|
return ((l[dwordOffset] & (1 << bitOffset)) ? TRUE : FALSE);
|
|
}
|
|
|
|
|
|
LONG
|
|
DBCLASS_DecrementIoCount(
|
|
IN PDBC_CONTEXT DbcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
LONG ioCount;
|
|
|
|
ioCount = InterlockedDecrement(&DbcContext->PendingIoCount);
|
|
LOGENTRY(LOG_MISC, 'ioc-', DbcContext->PendingIoCount, ioCount, 0);
|
|
|
|
DBCLASS_KdPrint ((2, "'Dec Pending io count = %x\n", ioCount));
|
|
|
|
if (ioCount==0) {
|
|
LOGENTRY(LOG_MISC, 'wRMe', DbcContext, 0, 0);
|
|
KeSetEvent(&DbcContext->RemoveEvent,
|
|
1,
|
|
FALSE);
|
|
}
|
|
|
|
return ioCount;
|
|
}
|
|
|
|
|
|
VOID
|
|
DBCLASS_IncrementIoCount(
|
|
IN PDBC_CONTEXT DbcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
InterlockedIncrement(&DbcContext->PendingIoCount);
|
|
LOGENTRY(LOG_MISC, 'ioc+', DbcContext->PendingIoCount, 0, 0);
|
|
}
|
|
|
|
#if 0
|
|
VOID
|
|
SetBit(
|
|
PVOID Bitmap,
|
|
ULONG BitNumber
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* Set a bit in a given a string of bytes.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* -- */
|
|
{
|
|
ULONG dwordOffset;
|
|
ULONG bitOffset;
|
|
PULONG l = (PULONG) Bitmap;
|
|
|
|
|
|
dwordOffset = BitNumber / 32;
|
|
bitOffset = BitNumber % 32;
|
|
|
|
l[dwordOffset] | =(1 << bitOffset);
|
|
}
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SyncSubmitDrb(
|
|
IN PDBC_CONTEXT DbcContext,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PDRB Drb
|
|
)
|
|
/* ++
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* Passes a DRB to the DB Port Driver, and waits for return.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* DeviceObject - Device object of the to of the port driver
|
|
* stack
|
|
*
|
|
* Return Value:
|
|
*
|
|
* STATUS_SUCCESS if successful
|
|
*
|
|
* -- */
|
|
{
|
|
NTSTATUS ntStatus, status;
|
|
PIRP irp;
|
|
KEVENT event;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
PIO_STACK_LOCATION nextStack;
|
|
#ifdef DEADMAN_TIMER
|
|
BOOLEAN haveTimer = FALSE;
|
|
KDPC timeoutDpc;
|
|
KTIMER timeoutTimer;
|
|
#endif
|
|
|
|
PAGED_CODE();
|
|
|
|
DBCLASS_BEGIN_SERIALIZED_DRB(DbcContext);
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_DBC_SUBMIT_DRB,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE, // INTERNAL
|
|
&event,
|
|
&ioStatus);
|
|
|
|
if (NULL == irp) {
|
|
DBCLASS_KdPrint((0, "'could not allocate an irp!\n"));
|
|
TRAP();
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Call the port driver to perform the operation. If the returned
|
|
// status
|
|
// is PENDING, wait for the request to complete.
|
|
//
|
|
nextStack = IoGetNextIrpStackLocation(irp);
|
|
|
|
//
|
|
// pass the DRB
|
|
//
|
|
nextStack->Parameters.Others.Argument1 = Drb;
|
|
ntStatus = IoCallDriver(DeviceObject, irp);
|
|
|
|
if (ntStatus == STATUS_PENDING) {
|
|
|
|
#ifdef DEADMAN_TIMER
|
|
LARGE_INTEGER dueTime;
|
|
|
|
KeInitializeTimer(&timeoutTimer);
|
|
KeInitializeDpc(&timeoutDpc,
|
|
UsbhTimeoutDPC,
|
|
irp);
|
|
|
|
dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
|
|
|
|
KeSetTimer(&timeoutTimer,
|
|
dueTime,
|
|
&timeoutDpc);
|
|
|
|
haveTimer = TRUE;
|
|
#endif
|
|
|
|
status = KeWaitForSingleObject(&event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
} else {
|
|
ioStatus.Status = ntStatus;
|
|
}
|
|
|
|
#ifdef DEADMAN_TIMER
|
|
//
|
|
// remove our timeoutDPC from the queue
|
|
//
|
|
if (haveTimer) {
|
|
KeCancelTimer(&timeoutTimer);
|
|
}
|
|
#endif /* DEADMAN_TIMER */
|
|
|
|
DBCLASS_END_SERIALIZED_DRB(DbcContext);
|
|
|
|
ntStatus = ioStatus.Status;
|
|
|
|
DBCLASS_KdPrint((2,"'DBCLASS_SyncSubmitDrb (%x)\n", ntStatus));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_StartController(
|
|
IN PDBC_CONTEXT DbcContext,
|
|
IN PIRP Irp,
|
|
IN PBOOLEAN HandledByClass
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine starts the DBC note that we should never set
|
|
HandledByClass to TRUE because the port driver always completes
|
|
this request (if we get an error we just need to set the
|
|
ntStatus code)
|
|
|
|
Arguments:
|
|
|
|
DbcContext - context for controller
|
|
|
|
Irp -
|
|
|
|
HandledByClass - not used
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
USHORT bay;
|
|
CHAR stackSize;
|
|
BOOLEAN Device1394IsPresent = FALSE;
|
|
|
|
DBCLASS_KdPrint((1, "'Starting DBC\n"));
|
|
BRK_ON_TRAP();
|
|
|
|
LOGENTRY(LOG_MISC, 'STRd', DbcContext, 0, 0);
|
|
|
|
INITIALIZE_DRB_SERIALIZATION(DbcContext);
|
|
KeInitializeSpinLock(&DbcContext->FlagsSpin);
|
|
KeInitializeEvent(&DbcContext->RemoveEvent, NotificationEvent, FALSE);
|
|
DbcContext->PendingIoCount = 0;
|
|
DbcContext->Flags = 0;
|
|
// this will be set when the filter registers
|
|
DbcContext->BusFilterMdo1394 = NULL;
|
|
DbcContext->BusFilterMdoUSB = NULL;
|
|
|
|
stackSize = DbcContext->TopOfStack->StackSize;
|
|
DbcContext->ChangeIrp = IoAllocateIrp(stackSize, FALSE);
|
|
DbcContext->Bus1394PortInfo = NULL;
|
|
DbcContext->LinkDeviceObject = NULL;
|
|
|
|
if (NULL == DbcContext->ChangeIrp ) {
|
|
DBCLASS_KdPrint((0, "'could not allocate an irp!\n"));
|
|
TRAP();
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
// get the susbsystem descriptor
|
|
ntStatus = DBCLASS_SyncGetSubsystemDescriptor(DbcContext);
|
|
}
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
ntStatus = DBCLASS_SyncGetAllBayDescriptors(DbcContext);
|
|
}
|
|
|
|
//
|
|
// if this is a USBDBC then write the approptiate info
|
|
// to the registry
|
|
//
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
if (DbcContext->ControllerSig == DBC_USB_CONTROLLER_SIG) {
|
|
// this will set the registry keys for the hub
|
|
// the USBDBC is attached to -- marking it as a
|
|
// DBC associated hub
|
|
ntStatus = DBCLASS_SetupUSB_DBC(DbcContext);
|
|
|
|
} else {
|
|
|
|
// controller is ACPI therefore the 1394 bus guid is the
|
|
// same as the 1394 guid reported by the DBC -- ie there
|
|
// is no extra Link Phy for an ACPI DBC.
|
|
|
|
// get the ACPIDBC Hub register now from the
|
|
// registry
|
|
|
|
DBCLASS_GetRegistryKeyValueForPdo(DbcContext->ControllerPdo,
|
|
FALSE,
|
|
ACPI_HUB_KEY,
|
|
sizeof(ACPI_HUB_KEY),
|
|
&DBCLASS_AcpiDBCHubParentPort,
|
|
sizeof(DBCLASS_AcpiDBCHubParentPort));
|
|
|
|
DBCLASS_KdPrint((1, "'ACPI USB Parent Port: %d\n",
|
|
DBCLASS_AcpiDBCHubParentPort));
|
|
|
|
#if DBG
|
|
if (DBCLASS_AcpiDBCHubParentPort == -1) {
|
|
DBCLASS_KdPrint((0, "'ACPI USB Parent Port not set!\n"));
|
|
TEST_TRAP();
|
|
}
|
|
#endif
|
|
|
|
RtlCopyMemory(&DbcContext->Guid1394Bus[0],
|
|
&DbcContext->SubsystemDescriptor.guid1394Link[0],
|
|
8);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// initialize per bay structures
|
|
//
|
|
|
|
DbcContext->BayInformation[0].DeviceFilterObject = (PVOID) -1;
|
|
for (bay=1; bay <=NUMBER_OF_BAYS(DbcContext); bay++) {
|
|
|
|
PDBC_BAY_DESCRIPTOR bayDescriptor;
|
|
|
|
bayDescriptor =
|
|
&DbcContext->BayInformation[bay].BayDescriptor;
|
|
|
|
// initilaize current status to 'empty'
|
|
|
|
DbcContext->BayInformation[bay].LastBayStatus.us = 0;
|
|
DbcContext->BayInformation[bay].DeviceFilterObject = NULL;
|
|
|
|
// set the hub port number based on what the
|
|
// controller reported
|
|
DbcContext->BayInformation[bay].UsbHubPort =
|
|
bayDescriptor->bHubPortNumber;
|
|
|
|
|
|
#if DBG
|
|
DBCLASS_KdPrint((1,"'>BAY[%d].BayDescriptor.bBayNumber %d\n",
|
|
bay, bayDescriptor->bBayNumber));
|
|
DBCLASS_KdPrint((1,"'>BAY[%d].BayDescriptor.bHubPortNumber %d\n",
|
|
bay, bayDescriptor->bHubPortNumber));
|
|
DBCLASS_KdPrint((1,"'>BAY[%d].BayDescriptor.bPHYPortNumber %d\n",
|
|
bay, bayDescriptor->bPHYPortNumber));
|
|
DBCLASS_KdPrint((1,"'>BAY[%d].BayDescriptor.bFormFactor %d\n",
|
|
bay, bayDescriptor->bFormFactor));
|
|
#endif
|
|
}
|
|
|
|
// now post a notification
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
DBCLASS_PostChangeRequest(DbcContext);
|
|
}
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
// Bays initialized:
|
|
//
|
|
// Enable change indications for all bays, we post a change irp
|
|
// in case we start getting notifications right away
|
|
//
|
|
|
|
for (bay=1; bay <= NUMBER_OF_BAYS(DbcContext); bay++) {
|
|
DBCLASS_SyncBayFeatureRequest(DbcContext,
|
|
DRB_FUNCTION_SET_BAY_FEATURE,
|
|
bay,
|
|
DEVICE_STATUS_CHANGE_ENABLE);
|
|
|
|
DBCLASS_SyncBayFeatureRequest(DbcContext,
|
|
DRB_FUNCTION_SET_BAY_FEATURE,
|
|
bay,
|
|
REMOVAL_REQUEST_ENABLE);
|
|
}
|
|
|
|
//
|
|
// check the initial state of the bays
|
|
//
|
|
// see if any devices are present
|
|
//
|
|
|
|
DBCLASS_KdPrint((1,"'STARTCONTROLLER: Checking Bays\n"));
|
|
|
|
for (bay=1; bay <= NUMBER_OF_BAYS(DbcContext); bay++) {
|
|
|
|
NTSTATUS status;
|
|
BAY_STATUS bayStatus;
|
|
|
|
status = DBCLASS_SyncGetBayStatus(DbcContext,
|
|
bay,
|
|
&bayStatus);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
DBCLASS_KdPrint((1,"'STARTCONTROLLER: init state - bay[%d] %x\n",
|
|
bay, bayStatus.us));
|
|
|
|
//
|
|
|
|
if (bayStatus.DeviceUsbIsPresent ||
|
|
bayStatus.Device1394IsPresent) {
|
|
|
|
if(bayStatus.Device1394IsPresent)
|
|
Device1394IsPresent = TRUE;
|
|
|
|
// we have a device in the bay
|
|
DBCLASS_KdPrint((1,"'STARTCONTROLLER: detected device in bay[%d] %x\n",
|
|
bay));
|
|
|
|
switch(bayStatus.CurrentBayState) {
|
|
|
|
case BAY_STATE_EMPTY:
|
|
case BAY_STATE_DEVICE_ENABLED:
|
|
// note:
|
|
// on the TI dbc if the bay state is enabled the device does
|
|
// not appear on the native bus
|
|
case BAY_STATE_DEVICE_INSERTED:
|
|
// note:
|
|
// on the TI dbc if the bay state is inserted the device does
|
|
// not appear on the native bus
|
|
|
|
DBCLASS_KdPrint((1,"'STARTCONTROLLER: setting bay %d to inserted state\n", bay));
|
|
|
|
DBCLASS_SyncBayFeatureRequest(DbcContext,
|
|
DRB_FUNCTION_SET_BAY_FEATURE,
|
|
bay,
|
|
REQUEST_DEVICE_INSERTED_STATE);
|
|
|
|
// get the new status and process it
|
|
status = DBCLASS_SyncGetBayStatus(DbcContext,
|
|
bay,
|
|
&bayStatus);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
DBCLASS_ProcessCurrentBayState(DbcContext,
|
|
bayStatus,
|
|
bay,
|
|
NULL);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
} /* switch bayStatus.CurrentBayState */
|
|
}
|
|
}
|
|
}
|
|
} /* nt_success */
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
// get registry controled features
|
|
{
|
|
NTSTATUS status;
|
|
ULONG release_on_shutdown = 0;
|
|
|
|
// check unlock on shutdown, the default is on
|
|
status = DBCLASS_GetRegistryKeyValueForPdo(
|
|
DbcContext->ControllerPdo,
|
|
TRUE,
|
|
RELEASE_ON_SHUTDOWN,
|
|
sizeof(RELEASE_ON_SHUTDOWN),
|
|
&release_on_shutdown,
|
|
sizeof(release_on_shutdown));
|
|
|
|
DBCLASS_KdPrint((1,"'STARTCONTROLLER: release_on_shutdown = %d\n",
|
|
release_on_shutdown));
|
|
if (release_on_shutdown) {
|
|
DbcContext->Flags |= DBCLASS_FLAG_RELEASE_ON_SHUTDOWN;
|
|
}
|
|
}
|
|
|
|
//
|
|
// consider ourselves started
|
|
// note: if we return an error stopcontroller
|
|
// will not be called
|
|
//
|
|
|
|
DbcContext->Stopped = FALSE;
|
|
|
|
// set our current power state to 'D0' ie ON
|
|
DbcContext->CurrentDevicePowerState = PowerDeviceD0;
|
|
|
|
// in order for the DBC to be linked to a 1394 bus
|
|
// we need to do an IoInvalidateDeviceRelations on
|
|
// all 1394 busses
|
|
|
|
if(Device1394IsPresent)
|
|
DBCLASS_Refresh1394();
|
|
|
|
}
|
|
|
|
// transition to zero signals stop/remove
|
|
//
|
|
// since we will get a stop even if we return
|
|
// an error we alaways increment
|
|
DBCLASS_IncrementIoCount(DbcContext);
|
|
|
|
DBCLASS_KdPrint((1,"'STARTCONTROLLER: ntStatus = %x\n", ntStatus));
|
|
LOGENTRY(LOG_MISC, 'STRT', DbcContext, 0, ntStatus);
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_CleanupController(
|
|
IN PDBC_CONTEXT DbcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
cleans up the DBC on stop or remove
|
|
|
|
Arguments:
|
|
|
|
DbcContext - context for controller
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS ntStatus;
|
|
|
|
LOGENTRY(LOG_MISC, 'clUP', DbcContext, 0, 0);
|
|
|
|
ntStatus = STATUS_SUCCESS;
|
|
|
|
return ntStatus;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_StopController(
|
|
IN PDBC_CONTEXT DbcContext,
|
|
IN PIRP Irp,
|
|
IN PBOOLEAN HandledByClass
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stops the DBC
|
|
|
|
Arguments:
|
|
|
|
DbcContext - context for controller
|
|
|
|
Irp -
|
|
|
|
HandledByClass - set to true if we need to complete the Irp
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
KIRQL irql;
|
|
BOOLEAN needCancel;
|
|
|
|
DBCLASS_KdPrint((1, "'Stopping DBC\n"));
|
|
LOGENTRY(LOG_MISC, 'STP>', DbcContext, 0, 0);
|
|
|
|
// disable bay locks here
|
|
if (DbcContext->Flags |= DBCLASS_FLAG_RELEASE_ON_SHUTDOWN)
|
|
{
|
|
USHORT bay;
|
|
|
|
for (bay = 1; bay <= NUMBER_OF_BAYS(DbcContext); bay++)
|
|
{
|
|
PDRB drb;
|
|
|
|
//
|
|
// notify filter of a stop
|
|
// note that the filter may not veto the stop
|
|
//
|
|
drb = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_START_DEVICE_IN_BAY));
|
|
|
|
if (drb)
|
|
{
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_STOP_DEVICE_IN_BAY);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_STOP_DEVICE_IN_BAY;
|
|
drb->DrbHeader.Flags = 0;
|
|
|
|
drb->DrbStartDeviceInBay.BayNumber = bay;
|
|
|
|
// make the request
|
|
ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
|
|
DbcContext->TopOfStack,
|
|
drb);
|
|
DbcExFreePool(drb);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// cancel any pending notification Irps
|
|
KeAcquireSpinLock(&DbcContext->FlagsSpin, &irql);
|
|
|
|
DbcContext->Flags |= DBCLASS_FLAG_STOPPING;
|
|
needCancel = (BOOLEAN) (DbcContext->Flags & DBCLASS_FLAG_REQ_PENDING);
|
|
|
|
KeReleaseSpinLock(&DbcContext->FlagsSpin, irql);
|
|
DBCLASS_DecrementIoCount(DbcContext);
|
|
|
|
if (needCancel) {
|
|
LOGENTRY(LOG_MISC, 'kIRP', DbcContext, DbcContext->ChangeIrp, 0);
|
|
IoCancelIrp(DbcContext->ChangeIrp);
|
|
}
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
// wait for any io request pending in our driver to
|
|
// complete for finishing the remove
|
|
|
|
LOGENTRY(LOG_MISC, 'STwt', DbcContext, 0, 0);
|
|
status = KeWaitForSingleObject(
|
|
&DbcContext->RemoveEvent,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
LOGENTRY(LOG_MISC, 'STwd', DbcContext, 0, 0);
|
|
}
|
|
|
|
|
|
LOGENTRY(LOG_MISC, 'STP<', DbcContext, 0, ntStatus);
|
|
|
|
return ntStatus;
|
|
|
|
}
|
|
|
|
|
|
PDBC_CONTEXT
|
|
DBCLASS_GetDbcContext(
|
|
IN PDEVICE_OBJECT ControllerFdo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stops the DBC
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
|
|
--*/
|
|
{
|
|
PDBC_CONTEXT dbcContext;
|
|
KIRQL irql;
|
|
|
|
// search our list if we find the TopOfStack device
|
|
// object then this must be a filter driver, otherwise
|
|
// allocate a new context structure for this controller
|
|
|
|
KeAcquireSpinLock(&DBCLASS_ControllerListSpin, &irql);
|
|
|
|
dbcContext = DBCLASS_ControllerList;
|
|
|
|
while (dbcContext) {
|
|
|
|
if (dbcContext->ControllerFdo == ControllerFdo) {
|
|
break;
|
|
}
|
|
|
|
dbcContext = dbcContext->Next;
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&DBCLASS_ControllerListSpin, irql);
|
|
|
|
return dbcContext;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SyncGetSubsystemDescriptor(
|
|
IN PDBC_CONTEXT DbcContext
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* fetch the susbsystem descriptor from the port driver, and allocate
|
|
* a structure for the bay information
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* -- */
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDRB drb;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Allocate Drb from the non-paged pool
|
|
//
|
|
|
|
drb = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_GET_SUBSYSTEM_DESCRIPTOR));
|
|
|
|
if (drb) {
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_GET_SUBSYSTEM_DESCRIPTOR);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_GET_SUBSYSTEM_DESCRIPTOR;
|
|
drb->DrbHeader.Flags = 0;
|
|
|
|
// make the request
|
|
ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
|
|
DbcContext->TopOfStack,
|
|
drb);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
RtlCopyMemory(&DbcContext->SubsystemDescriptor,
|
|
&drb->DrbGetSubsystemDescriptor.SubsystemDescriptor,
|
|
sizeof(DbcContext->SubsystemDescriptor));
|
|
|
|
// dump susbsystem descriptor to debugger
|
|
DBCLASS_KdPrint((1, "'DBC Susbsystem Descriptor:\n"));
|
|
DBCLASS_KdPrint((1, "'>bLength = (%08X)\n",
|
|
DbcContext->SubsystemDescriptor.bLength));
|
|
DBCLASS_KdPrint((1, "'>bDescriptorType = (%08X)\n",
|
|
DbcContext->SubsystemDescriptor.bDescriptorType));
|
|
DBCLASS_KdPrint((1, "'>SUBSYSTEM_DESCR = (%08X)\n",
|
|
DbcContext->SubsystemDescriptor.bmAttributes));
|
|
DBCLASS_KdPrint((1, "'>>SUBSYSTEM_DESCR.BayCount = (%08X)\n",
|
|
DbcContext->SubsystemDescriptor.bmAttributes.BayCount));
|
|
DBCLASS_KdPrint((1, "'>>SUBSYSTEM_DESCR.HasSecurityLock = (%08X)\n",
|
|
DbcContext->SubsystemDescriptor.bmAttributes.HasSecurityLock));
|
|
DBCLASS_KdPrint((1, "'>>SUBSYSTEM_DESCR.LinkGuid\n"));
|
|
#if DBG
|
|
DBCLASS_KdPrintGuid(1,
|
|
&DbcContext->SubsystemDescriptor.guid1394Link[0]);
|
|
#endif
|
|
}
|
|
|
|
DbcExFreePool(drb);
|
|
} else {
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SyncGetBayDescriptor(
|
|
IN PDBC_CONTEXT DbcContext,
|
|
IN USHORT BayNumber,
|
|
IN PDBC_BAY_DESCRIPTOR BayDescriptor
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* fetch the bay descriptor from the port driver,
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* -- */
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDRB drb;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Allocate Drb from the non-paged pool
|
|
//
|
|
|
|
drb = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_GET_BAY_DESCRIPTOR));
|
|
|
|
if (drb) {
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_GET_BAY_DESCRIPTOR);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_GET_BAY_DESCRIPTOR;
|
|
drb->DrbHeader.Flags = 0;
|
|
drb->DrbGetBayDescriptor.BayNumber = BayNumber;
|
|
|
|
// make the request
|
|
ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
|
|
DbcContext->TopOfStack,
|
|
drb);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
RtlCopyMemory(BayDescriptor,
|
|
&drb->DrbGetBayDescriptor.BayDescriptor,
|
|
sizeof(*BayDescriptor));
|
|
}
|
|
|
|
DbcExFreePool(drb);
|
|
} else {
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SyncGetControllerStatus(
|
|
IN PDBC_CONTEXT DbcContext
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* -- */
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDRB drb;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Allocate Drb from the non-paged pool
|
|
//
|
|
|
|
drb = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_GET_CONTROLLER_STATUS));
|
|
|
|
if (drb) {
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_GET_CONTROLLER_STATUS);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_GET_CONTROLLER_STATUS;
|
|
|
|
// make the request
|
|
ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
|
|
DbcContext->TopOfStack,
|
|
drb);
|
|
|
|
DbcExFreePool(drb);
|
|
} else {
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SyncGetAllBayDescriptors(
|
|
IN PDBC_CONTEXT DbcContext
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* fetch the susbsystem descriptor from the port driver, and allocate
|
|
* a structure for the bay information
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* -- */
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
USHORT bay;
|
|
|
|
PAGED_CODE();
|
|
|
|
for (bay=1; bay <= NUMBER_OF_BAYS(DbcContext); bay++) {
|
|
ntStatus = DBCLASS_SyncGetBayDescriptor(DbcContext,
|
|
bay,
|
|
&DbcContext->BayInformation[bay].BayDescriptor);
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SyncBayFeatureRequest(
|
|
IN PDBC_CONTEXT DbcContext,
|
|
IN USHORT Op,
|
|
IN USHORT BayNumber,
|
|
IN USHORT FeatureSelector
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* fetch the susbsystem descriptor from the port driver, and allocate
|
|
* a structure for the bay information
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* -- */
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDRB drb;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Allocate Drb from the non-paged pool
|
|
//
|
|
|
|
DBCLASS_ASSERT(BayNumber != 0);
|
|
DBCLASS_ASSERT(BayNumber <= MAX_BAY_NUMBER);
|
|
|
|
drb = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_BAY_FEATURE_REQUEST));
|
|
|
|
if (drb) {
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_BAY_FEATURE_REQUEST);
|
|
drb->DrbHeader.Function = Op;
|
|
drb->DrbHeader.Flags = 0;
|
|
drb->DrbBayFeatureRequest.BayNumber = BayNumber;
|
|
drb->DrbBayFeatureRequest.FeatureSelector = FeatureSelector;
|
|
// make the request
|
|
ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
|
|
DbcContext->TopOfStack,
|
|
drb);
|
|
|
|
DbcExFreePool(drb);
|
|
} else {
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SyncGetBayStatus(
|
|
IN PDBC_CONTEXT DbcContext,
|
|
IN USHORT BayNumber,
|
|
IN PBAY_STATUS BayStatus
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* fetch the susbsystem descriptor from the port driver, and allocate
|
|
* a structure for the bay information
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* -- */
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDRB drb;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Allocate Drb from the non-paged pool
|
|
//
|
|
|
|
DBCLASS_ASSERT(BayNumber != 0);
|
|
DBCLASS_ASSERT(BayNumber <= MAX_BAY_NUMBER);
|
|
|
|
drb = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_GET_BAY_STATUS));
|
|
|
|
if (drb) {
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_GET_BAY_STATUS);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_GET_BAY_STATUS;
|
|
drb->DrbHeader.Flags = 0;
|
|
drb->DrbGetBayStatus.BayNumber = BayNumber;
|
|
|
|
// make the request
|
|
ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
|
|
DbcContext->TopOfStack,
|
|
drb);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
BayStatus->us = drb->DrbGetBayStatus.BayStatus.us;
|
|
// dump status to debugger
|
|
DBCLASS_KdPrint((2, "'status for bay (%d) 0x%0x:\n", BayNumber,
|
|
drb->DrbGetBayStatus.BayStatus.us));
|
|
DBCLASS_KdPrint((2, "'>VidEnabled = (%08X)\n",
|
|
BayStatus->VidEnabled));
|
|
DBCLASS_KdPrint((2, "'>RemovalWakeupEnabled = (%08X)\n",
|
|
BayStatus->RemovalWakeupEnabled));
|
|
DBCLASS_KdPrint((2, "'>DeviceStatusChangeEnabled = (%08X)\n",
|
|
BayStatus->DeviceStatusChangeEnabled));
|
|
DBCLASS_KdPrint((2, "'>RemovalRequestEnabled = (%08X)\n",
|
|
BayStatus->RemovalRequestEnabled));
|
|
DBCLASS_KdPrint((2, "'>LastBayStateRequested = (%08X)\n",
|
|
BayStatus->LastBayStateRequested));
|
|
DBCLASS_KdPrint((2, "'>InterlockEngaged = (%08X)\n",
|
|
BayStatus->InterlockEngaged));
|
|
DBCLASS_KdPrint((2, "'>DeviceUsbIsPresent = (%08X)\n",
|
|
BayStatus->DeviceUsbIsPresent));
|
|
DBCLASS_KdPrint((2, "'>Device1394IsPresent = (%08X)\n",
|
|
BayStatus->Device1394IsPresent));
|
|
DBCLASS_KdPrint((2, "'>DeviceStatusChange = (%08X)\n",
|
|
BayStatus->DeviceStatusChange));
|
|
DBCLASS_KdPrint((2, "'>RemovalRequestChange = (%08X)\n",
|
|
BayStatus->RemovalRequestChange));
|
|
DBCLASS_KdPrint((2, "'>CurrentBayState = (%08X)\n",
|
|
BayStatus->CurrentBayState));
|
|
DBCLASS_KdPrint((2, "'>SecurityLockEngaged = (%08X)\n",
|
|
BayStatus->SecurityLockEngaged));
|
|
}
|
|
|
|
DbcExFreePool(drb);
|
|
} else {
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_ChangeIndication(
|
|
IN PDEVICE_OBJECT PNull,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* -- */
|
|
{
|
|
PDBC_CONTEXT dbcContext = Context;
|
|
KIRQL irql;
|
|
BOOLEAN stopping;
|
|
PDBCLASS_WORKITEM workItem;
|
|
|
|
// status change
|
|
//
|
|
// we should not get here unless something really has
|
|
// changed
|
|
|
|
KeAcquireSpinLock(&dbcContext->FlagsSpin, &irql);
|
|
dbcContext->Flags &= ~DBCLASS_FLAG_REQ_PENDING;
|
|
stopping = (BOOLEAN) (dbcContext->Flags & DBCLASS_FLAG_STOPPING);
|
|
KeReleaseSpinLock(&dbcContext->FlagsSpin, irql);
|
|
|
|
LOGENTRY(LOG_MISC, 'CHid', dbcContext, 0, Irp->IoStatus.Status);
|
|
BRK_ON_TRAP();
|
|
|
|
if (!stopping) {
|
|
|
|
//
|
|
// we have a legitimate change
|
|
//
|
|
|
|
// schedule a workitem to process the change
|
|
LOGENTRY(LOG_MISC, 'QCH>', dbcContext, 0, 0);
|
|
|
|
workItem = DbcExAllocatePool(NonPagedPool, sizeof(DBCLASS_WORKITEM));
|
|
|
|
if (workItem) {
|
|
DBCLASS_KdPrint((1, "'Schedule Workitem for Change Request\n"));
|
|
|
|
LOGENTRY(LOG_MISC, 'qITM', dbcContext,
|
|
workItem, 0);
|
|
|
|
workItem->Sig = DBC_WORKITEM_SIG;
|
|
workItem->DbcContext = dbcContext;
|
|
workItem->IrpStatus = Irp->IoStatus.Status;
|
|
|
|
ExInitializeWorkItem(&workItem->WorkQueueItem,
|
|
DBCLASS_ChangeIndicationWorker,
|
|
workItem);
|
|
|
|
ExQueueWorkItem(&workItem->WorkQueueItem,
|
|
DelayedWorkQueue);
|
|
|
|
} else {
|
|
|
|
DBCLASS_DecrementIoCount(dbcContext);
|
|
DBCLASS_KdPrint((0, "'No Memory for workitem!\n"));
|
|
TRAP();
|
|
|
|
}
|
|
|
|
} else {
|
|
DBCLASS_DecrementIoCount(dbcContext);
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_ProcessCurrentBayState(
|
|
IN PDBC_CONTEXT DbcContext,
|
|
IN BAY_STATUS BayStatus,
|
|
IN USHORT Bay,
|
|
IN PBOOLEAN PostChangeRequest
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* -- */
|
|
{
|
|
ULONG last,current;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
current = BayStatus.CurrentBayState;
|
|
last = DbcContext->BayInformation[Bay].LastBayStatus.CurrentBayState;
|
|
|
|
DBCLASS_KdPrint((0, "'>PBS - current bay state: %x\n", current));
|
|
DBCLASS_KdPrint((0, "'>last bay state: %x\n", last));
|
|
|
|
// figure out what current state of the bay is and deal with it
|
|
|
|
if (current == last) {
|
|
DBCLASS_KdPrint((0, "'>>no changes detected %x\n", current));
|
|
} else {
|
|
switch (current) {
|
|
|
|
case BAY_STATE_DEVICE_INSERTED:
|
|
|
|
LOGENTRY(LOG_MISC, 'byIN', DbcContext, ntStatus, Bay);
|
|
|
|
// engage the interlock, lock that baby in to the bay
|
|
ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
|
|
DRB_FUNCTION_SET_BAY_FEATURE,
|
|
Bay,
|
|
LOCK_CTL);
|
|
DBCLASS_Wait(1000);
|
|
|
|
|
|
// enable Vid so the device will appear on the native bus
|
|
ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
|
|
DRB_FUNCTION_SET_BAY_FEATURE,
|
|
Bay,
|
|
ENABLE_VID_POWER);
|
|
|
|
DBCLASS_Wait(1000);
|
|
|
|
//
|
|
// The device will now appear on the native bus
|
|
// allowing the OS to load appropriate drivers
|
|
//
|
|
DBCLASS_KdPrint((0, "'>>Bay Vid Power Enabled\n"));
|
|
|
|
// *PostChangeRequest = FALSE;
|
|
|
|
/* remove when filter is ready */
|
|
ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
|
|
DRB_FUNCTION_SET_BAY_FEATURE,
|
|
Bay,
|
|
REQUEST_DEVICE_ENABLED_STATE);
|
|
|
|
|
|
DBCLASS_SyncGetBayStatus(DbcContext, Bay, &BayStatus);
|
|
|
|
DbcContext->BayInformation[Bay].LastBayStatus = BayStatus;
|
|
/**/
|
|
|
|
break;
|
|
|
|
case BAY_STATE_DEVICE_REMOVAL_REQUESTED:
|
|
{
|
|
|
|
PIO_STACK_LOCATION nextStack;
|
|
PDRB drb;
|
|
CHAR stackSize;
|
|
PIRP irp;
|
|
PEJECT_CONTEXT ejectContext;
|
|
PUCHAR pch;
|
|
|
|
DBCLASS_KdPrint((0, "'>>Request Device Eject BAY[%d]\n", Bay));
|
|
|
|
// need to OK the eject
|
|
|
|
pch = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_START_DEVICE_IN_BAY) + sizeof(EJECT_CONTEXT));
|
|
|
|
ejectContext = (PEJECT_CONTEXT) pch;
|
|
drb = (PDRB) (pch + sizeof(EJECT_CONTEXT));
|
|
|
|
if (pch) {
|
|
|
|
ejectContext->Bay = Bay;
|
|
ejectContext->DbcContext = DbcContext;
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_EJECT_DEVICE_IN_BAY);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_EJECT_DEVICE_IN_BAY;
|
|
drb->DrbHeader.Flags = 0;
|
|
|
|
drb->DrbEjectDeviceInBay.BayNumber = Bay;
|
|
|
|
// deviceExtensionPdoFilter =
|
|
// DbcContext->BayInformation[Bay].DeviceFilterObject->DeviceExtension;
|
|
|
|
// make the request asynchronously
|
|
//
|
|
// normally this request is just completed by the port
|
|
// driver but we make the request so that the oem filter
|
|
// may intervene in the removal process
|
|
|
|
stackSize = DbcContext->TopOfStack->StackSize;
|
|
irp = IoAllocateIrp(stackSize, FALSE);
|
|
|
|
if (NULL == irp) {
|
|
|
|
DBCLASS_KdPrint((0, "'could not allocate an irp!\n"));
|
|
if (PostChangeRequest) {
|
|
*PostChangeRequest = TRUE;
|
|
}
|
|
TRAP();
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Call the port driver to perform the operation. If the returned
|
|
//
|
|
nextStack = IoGetNextIrpStackLocation(irp);
|
|
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_DBC_SUBMIT_DRB;
|
|
nextStack->Parameters.Others.Argument1 = drb;
|
|
|
|
//
|
|
// pass the DRB
|
|
//
|
|
IoSetCompletionRoutine(irp,
|
|
DBCLASS_EjectBayComplete,
|
|
ejectContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
ntStatus = IoCallDriver(DbcContext->TopOfStack, irp);
|
|
|
|
if (PostChangeRequest) {
|
|
*PostChangeRequest = FALSE;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
// no memory for drb, re-post the change request and
|
|
// try again
|
|
|
|
DBCLASS_KdPrint((0, "'could not allocate an drb!\n"));
|
|
if (PostChangeRequest) {
|
|
*PostChangeRequest = TRUE;
|
|
}
|
|
TRAP();
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case BAY_STATE_EMPTY:
|
|
|
|
//
|
|
// we should have no PDO if the bay is empty
|
|
//
|
|
|
|
// DBCLASS_ASSERT(
|
|
// DbcContext->BayInformation[Bay].DeviceFilterObject == NULL);
|
|
|
|
DBCLASS_KdPrint((0, "'>>Found Bay empty\n"));
|
|
break;
|
|
|
|
case BAY_STATE_DEVICE_ENABLED:
|
|
//
|
|
// we may get here because the bay was enabled at boot
|
|
// in this case we have nothing to do
|
|
//
|
|
|
|
DBCLASS_KdPrint((0, "'>>Found Bay enabled\n"));
|
|
|
|
break;
|
|
|
|
default:
|
|
DBCLASS_KdPrint((0, "'>>Bay State not handled\n"));
|
|
TRAP();
|
|
break;
|
|
|
|
} /* switch */
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
DBCLASS_ChangeIndicationWorker(
|
|
IN PVOID Context
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* NTSTATUS
|
|
*
|
|
* -- */
|
|
{
|
|
PDBCLASS_WORKITEM workItem = Context;
|
|
PDBC_CONTEXT dbcContext = workItem->DbcContext;
|
|
BAY_STATUS bayStatus;
|
|
USHORT bay;
|
|
NTSTATUS ntStatus, irpStatus;
|
|
BOOLEAN found = FALSE;
|
|
BOOLEAN postChangeRequest = TRUE;
|
|
|
|
LOGENTRY(LOG_MISC, 'cWK+', 0, Context, 0);
|
|
|
|
irpStatus = workItem->IrpStatus;
|
|
|
|
DbcExFreePool(workItem);
|
|
|
|
if (!NT_SUCCESS(irpStatus)) {
|
|
// we got an error
|
|
// get the controller status
|
|
NTSTATUS status;
|
|
|
|
status = DBCLASS_SyncGetControllerStatus(dbcContext);
|
|
|
|
LOGENTRY(LOG_MISC, 'cERR', dbcContext, status, irpStatus);
|
|
|
|
if (status == STATUS_DEVICE_NOT_CONNECTED) {
|
|
// controller was removed, don't
|
|
// re-post the request
|
|
postChangeRequest = FALSE;
|
|
}
|
|
|
|
// problem may be temporary
|
|
goto DBCLASS_ChangeIndicationWorker_Done;
|
|
}
|
|
|
|
// find out which bay changed
|
|
// find out what changed
|
|
// clear the change, note that we only
|
|
// clear the change that we process
|
|
|
|
for (bay = 0; bay <= MAX_BAY_NUMBER; bay++) {
|
|
if (IsBitSet(&dbcContext->ChangeDrb.BayChange, bay)) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// no change?
|
|
if (!found) {
|
|
DBCLASS_KdPrint((0, "'no bay indicated! -- bug in port driver\n", bay));
|
|
bay = 0;
|
|
TRAP();
|
|
}
|
|
|
|
DBCLASS_KdPrint((0, "'Process status change, bay = (%d)\n", bay));
|
|
|
|
if (bay > 0) {
|
|
|
|
ntStatus = DBCLASS_SyncGetBayStatus(dbcContext, bay, &bayStatus);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
// acknowlege any status change bits now
|
|
//
|
|
// NOTE that the status change bits are redundent
|
|
// we process the change base on the current state
|
|
// of the bay compared to the last known state
|
|
//
|
|
|
|
if (bayStatus.DeviceStatusChange) {
|
|
|
|
DBCLASS_KdPrint((0, "'>>device status change bit set\n"));
|
|
|
|
DBCLASS_SyncBayFeatureRequest(dbcContext,
|
|
DRB_FUNCTION_CLEAR_BAY_FEATURE,
|
|
bay,
|
|
C_DEVICE_STATUS_CHANGE);
|
|
|
|
DBCLASS_KdPrint((0, "'>>>cleared\n"));
|
|
|
|
}
|
|
|
|
if (bayStatus.RemovalRequestChange) {
|
|
|
|
DBCLASS_KdPrint((0, "'>>remove request change bit set\n"));
|
|
|
|
DBCLASS_SyncBayFeatureRequest(dbcContext,
|
|
DRB_FUNCTION_CLEAR_BAY_FEATURE,
|
|
bay,
|
|
C_REMOVE_REQUEST);
|
|
DBCLASS_KdPrint((0, "'>>>cleared\n"));
|
|
}
|
|
|
|
ntStatus = DBCLASS_ProcessCurrentBayState(dbcContext,
|
|
bayStatus,
|
|
bay,
|
|
&postChangeRequest);
|
|
|
|
}
|
|
} else {
|
|
DBCLASS_KdPrint((0, "'Global status change on DB subsystem\n"));
|
|
TEST_TRAP();
|
|
}
|
|
|
|
DBCLASS_ChangeIndicationWorker_Done:
|
|
|
|
LOGENTRY(LOG_MISC, 'chDN', dbcContext, ntStatus, bay);
|
|
|
|
// finished with this request, dec the count
|
|
DBCLASS_DecrementIoCount(dbcContext);
|
|
|
|
if (postChangeRequest) {
|
|
|
|
LOGENTRY(LOG_MISC, 'chPS', dbcContext, ntStatus, bay);
|
|
DBCLASS_PostChangeRequest(dbcContext);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
DBCLASS_PostChangeRequest(
|
|
IN PDBC_CONTEXT DbcContext
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* fetch the bay descriptor from the port driver,
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
* This routine never fails
|
|
*
|
|
* -- */
|
|
{
|
|
PDRB drb;
|
|
PIRP irp;
|
|
KIRQL irql;
|
|
CHAR stackSize;
|
|
PIO_STACK_LOCATION nextStack;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Drb and irp are pre-allocated
|
|
|
|
drb = (PDRB) &DbcContext->ChangeDrb;
|
|
irp = DbcContext->ChangeIrp;
|
|
|
|
stackSize = DbcContext->TopOfStack->StackSize;
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_CHANGE_REQUEST);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_CHANGE_REQUEST ;
|
|
drb->DrbHeader.Flags = 0;
|
|
drb->DrbChangeRequest.BayChange = 0;
|
|
|
|
|
|
IoInitializeIrp(irp,
|
|
(USHORT) (sizeof(IRP) + stackSize * sizeof(IO_STACK_LOCATION)),
|
|
(CCHAR) stackSize);
|
|
|
|
nextStack = IoGetNextIrpStackLocation(irp);
|
|
nextStack->Parameters.Others.Argument1 = drb;
|
|
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_DBC_SUBMIT_DRB;
|
|
|
|
IoSetCompletionRoutine(irp, // Irp
|
|
DBCLASS_ChangeIndication,
|
|
DbcContext, // context
|
|
TRUE, // invoke on success
|
|
TRUE, // invoke on error
|
|
TRUE); // invoke on cancel
|
|
|
|
//
|
|
// Call the port driver
|
|
//
|
|
|
|
KeAcquireSpinLock(&DbcContext->FlagsSpin, &irql);
|
|
if (DbcContext->Flags & DBCLASS_FLAG_STOPPING) {
|
|
LOGENTRY(LOG_MISC, 'stpX', DbcContext, 0, 0);
|
|
KeReleaseSpinLock(&DbcContext->FlagsSpin, irql);
|
|
} else {
|
|
|
|
DbcContext->Flags |= DBCLASS_FLAG_REQ_PENDING;
|
|
KeReleaseSpinLock(&DbcContext->FlagsSpin, irql);
|
|
DBCLASS_IncrementIoCount(DbcContext);
|
|
|
|
DBCLASS_BEGIN_SERIALIZED_DRB(DbcContext);
|
|
|
|
DBCLASS_KdPrint((1, "'Post Change Request\n"));
|
|
|
|
LOGENTRY(LOG_MISC, 'post', DbcContext, 0, irp);
|
|
// let the completion routine handle any errors
|
|
IoCallDriver(DbcContext->TopOfStack, irp);
|
|
|
|
DBCLASS_END_SERIALIZED_DRB(DbcContext);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
USHORT
|
|
DBCLASS_GetBayNumber(
|
|
IN PDEVICE_OBJECT DeviceFilterObject
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* given a device filter object, find the bay with this device
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
* This routine never fails
|
|
*
|
|
* -- */
|
|
{
|
|
PDBC_CONTEXT dbcContext;
|
|
USHORT bay;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
DBCLASS_ASSERT(DeviceFilterObject);
|
|
|
|
deviceExtension =
|
|
DeviceFilterObject->DeviceExtension;
|
|
|
|
if(deviceExtension)
|
|
{
|
|
dbcContext = deviceExtension->DbcContext;
|
|
|
|
LOGENTRY(LOG_MISC, 'GBNn', dbcContext, DeviceFilterObject, 0);
|
|
|
|
|
|
if(dbcContext)
|
|
{
|
|
for (bay=1; bay <=NUMBER_OF_BAYS(dbcContext); bay++)
|
|
{
|
|
|
|
if (dbcContext->BayInformation[bay].DeviceFilterObject == DeviceFilterObject) {
|
|
LOGENTRY(LOG_MISC, 'GBNr', dbcContext, DeviceFilterObject, bay);
|
|
return bay;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
NTSTATUS
|
|
DBCLASS_EnableDevice(
|
|
IN PDEVICE_OBJECT DeviceFilterObject
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* given a device filter object, eject the device in the bay
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
* This routine never fails
|
|
*
|
|
* -- */
|
|
{
|
|
PDBC_CONTEXT dbcContext;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
USHORT bay;
|
|
BAY_STATUS bayStatus;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
DBCLASS_ASSERT(DeviceFilterObject);
|
|
|
|
deviceExtension =
|
|
DeviceFilterObject->DeviceExtension;
|
|
dbcContext = deviceExtension->DbcContext;
|
|
bay = DBCLASS_GetBayNumber(DeviceFilterObject);
|
|
|
|
DBCLASS_KdPrint((0, "'>>Bay to Enabled state\n"));
|
|
|
|
ntStatus = DBCLASS_SyncBayFeatureRequest(dbcContext,
|
|
DRB_FUNCTION_SET_BAY_FEATURE,
|
|
bay,
|
|
REQUEST_DEVICE_ENABLED_STATE);
|
|
|
|
|
|
DBCLASS_SyncGetBayStatus(dbcContext, bay, &bayStatus);
|
|
|
|
dbcContext->BayInformation[bay].LastBayStatus = bayStatus;
|
|
|
|
DBCLASS_DecrementIoCount(dbcContext);
|
|
|
|
DBCLASS_PostChangeRequest(dbcContext);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_EjectPdo(
|
|
IN PDEVICE_OBJECT DeviceFilterObject
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* given a device filter object, eject the device in the bay by Pdo
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
* This routine never fails
|
|
*
|
|
* -- */
|
|
{
|
|
PDBC_CONTEXT dbcContext;
|
|
PDEVICE_EXTENSION deviceExtension =
|
|
DeviceFilterObject->DeviceExtension;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
dbcContext = deviceExtension->DbcContext;
|
|
|
|
ntStatus = DBCLASS_EjectBay(dbcContext,
|
|
deviceExtension->Bay);
|
|
|
|
DBCLASS_DecrementIoCount(dbcContext);
|
|
|
|
DBCLASS_PostChangeRequest(dbcContext);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_EjectBay(
|
|
IN PDBC_CONTEXT DbcContext,
|
|
IN USHORT Bay
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* given a bay, eject the device in it
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
* This routine never fails
|
|
*
|
|
* -- */
|
|
{
|
|
BAY_STATUS bayStatus;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
DBCLASS_KdPrint((0, "'>EJECT Bay[%d]\n", Bay));
|
|
|
|
// disengage the interlock
|
|
DBCLASS_KdPrint((0, "'>>disable VID\n"));
|
|
|
|
ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
|
|
DRB_FUNCTION_CLEAR_BAY_FEATURE,
|
|
Bay,
|
|
ENABLE_VID_POWER);
|
|
|
|
DBCLASS_KdPrint((0, "'>>disengage interlock\n"));
|
|
|
|
ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
|
|
DRB_FUNCTION_CLEAR_BAY_FEATURE,
|
|
Bay,
|
|
LOCK_CTL);
|
|
|
|
DBCLASS_KdPrint((0, "'>>Bay to Removal allowed state\n"));
|
|
|
|
ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
|
|
DRB_FUNCTION_SET_BAY_FEATURE,
|
|
Bay,
|
|
REQUEST_REMOVAL_ALLOWED_STATE);
|
|
|
|
|
|
|
|
DBCLASS_SyncGetBayStatus(DbcContext, Bay, &bayStatus);
|
|
|
|
DbcContext->BayInformation[Bay].LastBayStatus = bayStatus;
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_AddDevicePDOToList(
|
|
IN PDEVICE_OBJECT FilterDeviceObject,
|
|
IN PDEVICE_OBJECT PdoDeviceObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a bus emumerated PDO to our list of PDOs
|
|
|
|
Currently we only track 1394 PDOs
|
|
|
|
Arguments:
|
|
|
|
FilterDeviceObject - filter MDO for the 1394 bus this device is on
|
|
PdoDeviceObject - 1394 Enumerated PDO
|
|
|
|
Return Value:
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES if a buffer could not be allocated
|
|
STATUS_SUCCESS otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBCLASS_PDO_LIST newEntry;
|
|
|
|
newEntry = ExAllocatePool(NonPagedPool, sizeof(DBCLASS_PDO_LIST));
|
|
|
|
if (newEntry == NULL) {
|
|
TRAP();
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Fill in fields in new entry
|
|
|
|
newEntry->FilterDeviceObject = FilterDeviceObject;
|
|
newEntry->PdoDeviceObject = PdoDeviceObject;
|
|
|
|
// Add new entry to end of list
|
|
InsertTailList(&DBCLASS_DevicePdoList, &newEntry->ListEntry);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
DBCLASS_RemoveDevicePDOFromList(
|
|
IN PDEVICE_OBJECT PdoDeviceObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a 1394 emumerated PDO to our list of 1394 PDOs
|
|
|
|
Arguments:
|
|
|
|
PdoDeviceObject - 1394 Enumerated PDO to remove from list
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBCLASS_PDO_LIST entry;
|
|
PLIST_ENTRY listEntry;
|
|
|
|
listEntry = &DBCLASS_DevicePdoList;
|
|
if (!IsListEmpty(listEntry)) {
|
|
listEntry = DBCLASS_DevicePdoList.Flink;
|
|
}
|
|
|
|
while (listEntry != &DBCLASS_DevicePdoList) {
|
|
|
|
entry = CONTAINING_RECORD(listEntry,
|
|
DBCLASS_PDO_LIST,
|
|
ListEntry);
|
|
|
|
DBCLASS_ASSERT(entry);
|
|
if (entry->PdoDeviceObject == PdoDeviceObject) {
|
|
break;
|
|
}
|
|
|
|
listEntry = entry->ListEntry.Flink;
|
|
|
|
}
|
|
|
|
// we should always find it
|
|
DBCLASS_ASSERT(listEntry != &DBCLASS_DevicePdoList);
|
|
|
|
RemoveEntryList(listEntry);
|
|
ExFreePool(entry);
|
|
|
|
}
|
|
|
|
|
|
PDEVICE_OBJECT
|
|
DBCLASS_FindDevicePdo(
|
|
PDEVICE_OBJECT PdoDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
find a device PDO -- return tru if we know about it
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PDBCLASS_PDO_LIST entry;
|
|
PLIST_ENTRY listEntry;
|
|
// we keep a global list of PDOs we know about
|
|
|
|
listEntry = &DBCLASS_DevicePdoList;
|
|
|
|
if (!IsListEmpty(listEntry)) {
|
|
listEntry = DBCLASS_DevicePdoList.Flink;
|
|
}
|
|
|
|
while (listEntry != &DBCLASS_DevicePdoList) {
|
|
|
|
entry = CONTAINING_RECORD(listEntry,
|
|
DBCLASS_PDO_LIST,
|
|
ListEntry);
|
|
|
|
DBCLASS_ASSERT(entry);
|
|
if (entry->PdoDeviceObject == PdoDeviceObject) {
|
|
return entry->FilterDeviceObject;
|
|
}
|
|
|
|
listEntry = entry->ListEntry.Flink;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PDBC_CONTEXT
|
|
DBCLASS_FindControllerACPI(
|
|
PDRIVER_OBJECT FilterDriverObject,
|
|
PDEVICE_OBJECT FilterMdo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
find the DBC controller in our list for a given Filter MDO
|
|
if found the filter MDO is linked to the controller
|
|
|
|
This routine searches the list for an ACPI DBC
|
|
currently we support only one.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Controller Context
|
|
|
|
--*/
|
|
{
|
|
PDBC_CONTEXT dbcContext = NULL;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = FilterMdo->DeviceExtension;
|
|
dbcContext = DBCLASS_ControllerList;
|
|
|
|
//
|
|
// NOTE: We support only one ACPI DBC controller
|
|
//
|
|
|
|
while (dbcContext) {
|
|
if (dbcContext->ControllerSig == DBC_ACPI_CONTROLLER_SIG) {
|
|
if (deviceExtension->FdoType == DB_FDO_USBHUB_BUS) {
|
|
dbcContext->BusFilterMdoUSB = FilterMdo;
|
|
} else if (deviceExtension->FdoType == DB_FDO_1394_BUS) {
|
|
dbcContext->BusFilterMdo1394 = FilterMdo;
|
|
} else {
|
|
TRAP();
|
|
}
|
|
dbcContext->BusFilterDriverObject = FilterDriverObject;
|
|
|
|
break;
|
|
}
|
|
dbcContext = dbcContext->Next;
|
|
}
|
|
|
|
LOGENTRY(LOG_MISC, 'FIN1', dbcContext, 0, 0);
|
|
|
|
#if DBG
|
|
if (dbcContext == NULL) {
|
|
DBCLASS_KdPrint((0, "'ACPI Controller not Found\n"));
|
|
}
|
|
#endif
|
|
|
|
return dbcContext;
|
|
}
|
|
|
|
|
|
PDBC_CONTEXT
|
|
DBCLASS_FindControllerUSB(
|
|
PDRIVER_OBJECT FilterDriverObject,
|
|
PDEVICE_OBJECT FilterMdo,
|
|
PDEVICE_OBJECT UsbHubPdo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
find the DBC controller in our list for a given Filter MDO
|
|
if found the filter MDO is linked to the controller
|
|
|
|
This routine will query the hub to see if an DBC controller
|
|
is attached.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Controller Context
|
|
|
|
--*/
|
|
{
|
|
UCHAR dbcGuid[8];
|
|
NTSTATUS ntStatus;
|
|
PDBC_CONTEXT dbcContext = NULL;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = FilterMdo->DeviceExtension;
|
|
|
|
// first get the guid for this hub
|
|
ntStatus = DBCLASS_GetHubDBCGuid(FilterMdo,
|
|
dbcGuid);
|
|
|
|
dbcContext = DBCLASS_ControllerList;
|
|
|
|
while (dbcContext) {
|
|
if (RtlCompareMemory(&dbcContext->SubsystemDescriptor.guid1394Link[0],
|
|
&dbcGuid[0], 8) == 8) {
|
|
if (deviceExtension->FdoType == DB_FDO_USBHUB_BUS) {
|
|
dbcContext->BusFilterMdoUSB = FilterMdo;
|
|
} else if (deviceExtension->FdoType == DB_FDO_1394_BUS) {
|
|
dbcContext->BusFilterMdo1394 = FilterMdo;
|
|
} else {
|
|
TRAP();
|
|
}
|
|
dbcContext->BusFilterDriverObject = FilterDriverObject;
|
|
break;
|
|
}
|
|
dbcContext = dbcContext->Next;
|
|
}
|
|
|
|
return dbcContext;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_Find1394DbcLinks(
|
|
PDEVICE_OBJECT DevicePdo1394
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
find the DBC controller in our list for a given Filter MDO
|
|
if found the filter MDO is linked to the controller
|
|
|
|
Given the 1394 device PDO and the bus guid we try to find the
|
|
appropriate controller
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Controller Context
|
|
|
|
--*/
|
|
{
|
|
PDBC_CONTEXT dbcContext;
|
|
|
|
DBCLASS_KdPrint((1, "'Find DBC Links\n"));
|
|
dbcContext = DBCLASS_ControllerList;
|
|
|
|
while (dbcContext) {
|
|
|
|
if (DBCLASS_IsLinkDeviceObject(dbcContext,
|
|
DevicePdo1394)) {
|
|
|
|
DBCLASS_KdPrint((1, "'1394 PDO is DBC Link\n"));
|
|
// set the bus guid for the context
|
|
DBCLASS_1394GetBusGuid(DevicePdo1394,
|
|
&dbcContext->Guid1394Bus[0]);
|
|
}
|
|
|
|
dbcContext = dbcContext->Next;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
PDBC_CONTEXT
|
|
DBCLASS_FindController1394DevicePdo(
|
|
PDRIVER_OBJECT FilterDriverObject,
|
|
PDEVICE_OBJECT FilterMdo,
|
|
PDEVICE_OBJECT DevicePdo1394,
|
|
PUCHAR BusGuid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
find the DBC controller in our list for a given Filter MDO
|
|
if found the filter MDO is linked to the controller
|
|
|
|
Given the 1394 device PDO and the bus guid we try to find the
|
|
appropriate DB controller
|
|
|
|
busguid is the 1394 controller guid for the bus this device is on
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Controller Context
|
|
|
|
--*/
|
|
{
|
|
PDBC_CONTEXT dbcContext = NULL;
|
|
PDBC_CONTEXT foundDbcContext = NULL;
|
|
// if a DBC reports the magic guid then we match on that
|
|
|
|
UCHAR magicGuid[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
|
|
|
|
DBCLASS_KdPrint((1, "'>Find Controller -> 1394 DEV PDO (%x)\n", DevicePdo1394));
|
|
DBCLASS_KdPrint((1, "'>>1394 CONTROLLER (BUS) GUID\n"));
|
|
DBCLASS_KdPrintGuid(1,
|
|
BusGuid);
|
|
|
|
BRK_ON_TRAP();
|
|
|
|
//
|
|
// first loop through controllers
|
|
// checking to see if this is a PDO
|
|
// for a link, if so we mark the context as NULL
|
|
// ie not a DB device
|
|
//
|
|
|
|
dbcContext = DBCLASS_ControllerList;
|
|
|
|
while (dbcContext) {
|
|
|
|
if (DBCLASS_IsLinkDeviceObject(dbcContext,
|
|
DevicePdo1394)) {
|
|
|
|
DBCLASS_KdPrint((1, "'>>>1394 PDO is DBC Link\n"));
|
|
return NULL;
|
|
}
|
|
|
|
dbcContext = dbcContext->Next;
|
|
}
|
|
|
|
//
|
|
// loop through the controllers, checking each one
|
|
// until we have a match
|
|
|
|
dbcContext = DBCLASS_ControllerList;
|
|
|
|
while (dbcContext && foundDbcContext == NULL) {
|
|
NTSTATUS status;
|
|
|
|
DBCLASS_KdPrint((2, "'Checking DBC (%x)\n", dbcContext));
|
|
DBCLASS_KdPrint((2, "'BUS GUID (%x)\n", dbcContext));
|
|
DBCLASS_KdPrintGuid(2,
|
|
&dbcContext->Guid1394Bus[0]);
|
|
|
|
// only look at controllers on the same bus
|
|
if (
|
|
(RtlCompareMemory(&dbcContext->Guid1394Bus[0],
|
|
BusGuid, 8) == 8) ||
|
|
(RtlCompareMemory(&dbcContext->Guid1394Bus[0],
|
|
&magicGuid[0], 8) == 8)
|
|
) {
|
|
|
|
// OK we found a match, now see if this PDO is part of
|
|
// this controller
|
|
status = DBCLASS_Check1394DevicePDO(FilterMdo,
|
|
dbcContext,
|
|
DevicePdo1394);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
foundDbcContext = dbcContext;
|
|
dbcContext->BusFilterMdo1394 = FilterMdo;
|
|
dbcContext->BusFilterDriverObject = FilterDriverObject;
|
|
}
|
|
|
|
}
|
|
dbcContext = dbcContext->Next;
|
|
}
|
|
|
|
#if DBG
|
|
if (foundDbcContext) {
|
|
DBCLASS_KdPrint((1, "'>>>>Found DBC (%x)\n", foundDbcContext));
|
|
} else {
|
|
DBCLASS_KdPrint((1, "'>>>>DBC not found\n"));
|
|
}
|
|
#endif
|
|
|
|
return foundDbcContext;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_PdoSetLockComplete(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the device object
|
|
|
|
Irp - a pointer to the irp
|
|
|
|
Context - NULL ptr
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
LOGENTRY(LOG_MISC, 'LOKc', 0, 0, 0);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
#define IS_1394_DEVICE(de) ((de)->FdoType == DB_FDO_1394_DEVICE)
|
|
|
|
NTSTATUS
|
|
DBCLASS_PdoFilterDispatch(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PBOOLEAN Handled
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Common filter function for both 1394 and USB PDOs
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION deviceExtensionPdoFilter;
|
|
|
|
deviceExtensionPdoFilter = DeviceObject->DeviceExtension;
|
|
ntStatus = Irp->IoStatus.Status;
|
|
*Handled = FALSE;
|
|
irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
LOGENTRY(LOG_MISC, 'pdo>', 0, DeviceObject, Irp);
|
|
|
|
DBCLASS_KdPrint((1, "'(dbfilter)(device)(%x)IRP_MJ_ (%08X) IRP_MN_ (%08X)\n",
|
|
DeviceObject, irpStack->MajorFunction, irpStack->MinorFunction));
|
|
|
|
switch (irpStack->MajorFunction)
|
|
{
|
|
|
|
case IRP_MJ_PNP:
|
|
switch (irpStack->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE:
|
|
{
|
|
PDBC_CONTEXT dbcContext;
|
|
USHORT bay = 0;
|
|
KEVENT event;
|
|
|
|
DBCLASS_KdPrint((1, "'(dbfilter)(device)(%x)IRP_MN_START_DEVICE\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject));
|
|
|
|
*Handled = TRUE;
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp,
|
|
DBCLASS_DeferIrpCompletion,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
|
|
//
|
|
// send the request down the stack before we eject
|
|
//
|
|
|
|
ntStatus = IoCallDriver(deviceExtensionPdoFilter->TopOfStackDeviceObject,
|
|
Irp);
|
|
|
|
if (ntStatus == STATUS_PENDING)
|
|
{
|
|
// wait for irp to complete
|
|
|
|
KeWaitForSingleObject(
|
|
&event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
// started a 1394 device, figure out what bay it is in
|
|
|
|
if (IS_1394_DEVICE(deviceExtensionPdoFilter))
|
|
{
|
|
|
|
DBCLASS_KdPrint((1, "'**> Starting 1394 PDO (%x)\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject));
|
|
|
|
bay = deviceExtensionPdoFilter->Bay;
|
|
dbcContext = deviceExtensionPdoFilter->DbcContext;
|
|
|
|
}
|
|
|
|
// we have no USB device bay devices
|
|
#if 0
|
|
else
|
|
{
|
|
|
|
dbcContext = deviceExtensionPdoFilter->DbcContext;
|
|
|
|
DBCLASS_KdPrint((0, "'**> Starting USB PDO (%08X) Filter DevObj (%08X) DbcContext (%08X)\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject, DeviceObject, dbcContext));
|
|
|
|
|
|
if (dbcContext != NULL)
|
|
{
|
|
bay = DBCLASS_GetBayForUSBPdo(
|
|
dbcContext,
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject);
|
|
|
|
if (bay == 0)
|
|
{
|
|
// ignore this PDO from now on
|
|
deviceExtensionPdoFilter->FdoType = DB_FDO_BUS_IGNORE;
|
|
DBCLASS_KdPrint((1,
|
|
"'>>>> USB PDO(%x) is not a DB device <<<<\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject));
|
|
}
|
|
else
|
|
{
|
|
DBCLASS_KdPrint((1,
|
|
"'>>>> USB PDO(%x) is in BAY[%d] <<<<\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject,
|
|
bay));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// no controller yet -- can't be a device bay device
|
|
bay = 0;
|
|
DBCLASS_KdPrint((1, "'No Controller Available\n"));
|
|
}
|
|
|
|
//TEST_TRAP();
|
|
}
|
|
#endif
|
|
|
|
// keep track of the bay we are in in case
|
|
// we get an eject irp
|
|
deviceExtensionPdoFilter->Bay = bay;
|
|
|
|
if (bay)
|
|
{
|
|
|
|
DBCLASS_KdPrint((1,
|
|
"'**>> PDO is in Bay %d\n", bay));
|
|
|
|
DBCLASS_ASSERT(dbcContext != NULL);
|
|
if(dbcContext)
|
|
{
|
|
dbcContext->BayInformation[bay].DeviceFilterObject =
|
|
DeviceObject;
|
|
if (DeviceObject) {
|
|
// need to OK the start
|
|
PDRB drb;
|
|
|
|
drb = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_START_DEVICE_IN_BAY));
|
|
|
|
if (drb) {
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_START_DEVICE_IN_BAY);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_START_DEVICE_IN_BAY;
|
|
drb->DrbHeader.Flags = 0;
|
|
|
|
drb->DrbStartDeviceInBay.BayNumber = bay;
|
|
|
|
drb->DrbStartDeviceInBay.PdoDeviceObject1394 =
|
|
drb->DrbStartDeviceInBay.PdoDeviceObjectUsb = NULL;
|
|
|
|
if (IS_1394_DEVICE(deviceExtensionPdoFilter)) {
|
|
drb->DrbStartDeviceInBay.PdoDeviceObject1394 =
|
|
DeviceObject;
|
|
} else {
|
|
drb->DrbStartDeviceInBay.PdoDeviceObjectUsb =
|
|
DeviceObject;
|
|
}
|
|
|
|
// make the request
|
|
ntStatus = DBCLASS_SyncSubmitDrb(dbcContext,
|
|
dbcContext->TopOfStack,
|
|
drb);
|
|
} else {
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
|
|
// report that this PDO must be removed it the
|
|
// db controller is removed.
|
|
|
|
// note: we invalidate on the DBC PDO
|
|
// this should trigger a QBR for the device bay controller
|
|
|
|
|
|
} else {
|
|
DBCLASS_KdPrint((1,
|
|
"'**>> PDO is not for a device bay device\n"));
|
|
|
|
// detach and delete our MDO here if possible
|
|
// otherwise mark as ignore
|
|
|
|
BRK_ON_TRAP();
|
|
}
|
|
|
|
Irp->IoStatus.Status = ntStatus;
|
|
|
|
//
|
|
// detach and delete ourselves now
|
|
//
|
|
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
|
|
}
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
if (irpStack->MinorFunction == IRP_MN_STOP_DEVICE) {
|
|
DBCLASS_KdPrint((1,
|
|
"'(dbfilter)(device)(%x)IRP_MN_STOP_DEVICE\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject));
|
|
} else {
|
|
DBCLASS_KdPrint((1,
|
|
"'(dbfilter)(device)(%x)IRP_MN_REMOVE_DEVICE\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject));
|
|
}
|
|
// set the device filter object to NULL
|
|
// this will allow the dbc to eject the device if requested
|
|
{
|
|
USHORT bay = 0;
|
|
PDBC_CONTEXT dbcContext;
|
|
|
|
dbcContext = deviceExtensionPdoFilter->DbcContext;
|
|
// bay = DBCLASS_GetBayNumber(DeviceObject);
|
|
|
|
if (bay) {
|
|
PDRB drb;
|
|
|
|
DBCLASS_KdPrint((1,
|
|
"'(dbfilter)(device)REMOVE/STOP, Bay[%d]\n", bay));
|
|
|
|
//
|
|
// notify filter of a stop
|
|
// note that the filter may not veto the stop
|
|
//
|
|
drb = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_START_DEVICE_IN_BAY));
|
|
|
|
if (drb) {
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_STOP_DEVICE_IN_BAY);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_STOP_DEVICE_IN_BAY;
|
|
drb->DrbHeader.Flags = 0;
|
|
|
|
drb->DrbStartDeviceInBay.BayNumber = bay;
|
|
|
|
// make the request
|
|
ntStatus = DBCLASS_SyncSubmitDrb(dbcContext,
|
|
dbcContext->TopOfStack,
|
|
drb);
|
|
|
|
DBCLASS_KdPrint((1,
|
|
"'OK to stop <%x>\n", ntStatus));
|
|
|
|
DbcExFreePool(drb);
|
|
|
|
} else {
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
dbcContext->BayInformation[bay].DeviceFilterObject = NULL;
|
|
}
|
|
|
|
deviceExtensionPdoFilter->DbcContext = NULL;
|
|
|
|
}
|
|
break;
|
|
#if 0
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
{
|
|
USHORT bay;
|
|
|
|
bay = DBCLASS_GetBayNumber(DeviceObject);
|
|
DBCLASS_KdPrint((1,
|
|
"'(dbfilter)(device)(%x)Q_REMOVE/STOP, Bay[%d]\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject, bay));
|
|
}
|
|
break;
|
|
#endif
|
|
case IRP_MN_EJECT:
|
|
|
|
{
|
|
KEVENT event;
|
|
USHORT bay;
|
|
PDBC_CONTEXT dbcContext;
|
|
|
|
dbcContext = deviceExtensionPdoFilter->DbcContext;
|
|
|
|
DBCLASS_KdPrint((1, "'(dbfilter)(device)(%x)IRP_MN_EJECT, Bay[%d]\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject,
|
|
deviceExtensionPdoFilter->Bay));
|
|
|
|
*Handled = TRUE;
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp,
|
|
DBCLASS_DeferIrpCompletion,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
//
|
|
// send the request down the stack before we eject
|
|
//
|
|
|
|
ntStatus = IoCallDriver(deviceExtensionPdoFilter->TopOfStackDeviceObject,
|
|
Irp);
|
|
|
|
if (ntStatus == STATUS_PENDING) {
|
|
// wait for irp to complete
|
|
|
|
// TEST_TRAP(); // first time we hit this
|
|
|
|
KeWaitForSingleObject(
|
|
&event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
IoDetachDevice(deviceExtensionPdoFilter->TopOfStackDeviceObject);
|
|
|
|
//
|
|
// ounce we eject the device will disappear from the
|
|
// native bus.
|
|
//
|
|
|
|
ntStatus = Irp->IoStatus.Status;
|
|
|
|
// TEST_TRAP();
|
|
// if (NT_SUCCESS(ntStatus)) {
|
|
bay = deviceExtensionPdoFilter->Bay;
|
|
|
|
if (bay) {
|
|
ntStatus = DBCLASS_EjectPdo(DeviceObject);
|
|
|
|
DBCLASS_ASSERT(dbcContext->BayInformation[bay].DeviceFilterObject
|
|
== NULL);
|
|
}
|
|
#if DBG
|
|
else {
|
|
DBCLASS_KdPrint((1, "'No Bay to EJECT (%x)\n", ntStatus));
|
|
// TEST_TRAP();
|
|
ntStatus = STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
// }
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// delete ourselves now
|
|
//
|
|
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
|
|
deviceExtensionPdoFilter->DbcContext = NULL;
|
|
|
|
// remove PDO from our internal list
|
|
DBCLASS_RemoveDevicePDOFromList(
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject);
|
|
|
|
// free our device object
|
|
IoDeleteDevice (DeviceObject);
|
|
}
|
|
|
|
break;
|
|
|
|
case IRP_MN_SET_LOCK:
|
|
|
|
DBCLASS_KdPrint((1, "'(dbfilter)(device)IRP_MN_SET_LOCK, Bay[%x]\n",
|
|
deviceExtensionPdoFilter->Bay));
|
|
|
|
if (irpStack->Parameters.SetLock.Lock) {
|
|
DBCLASS_KdPrint((1, "'Request to LOCK device\n"));
|
|
DBCLASS_KdPrint((1, "'NOT ENABLING BAY ON LOCK!\n"));
|
|
LOGENTRY(LOG_MISC, 'LOCK', 0, 0, 0);
|
|
//ntStatus = DBCLASS_EnableDevice(DeviceObject);
|
|
} else {
|
|
|
|
//
|
|
// cancel the eject timeout
|
|
// if we get here no one vetoed the remove
|
|
//
|
|
|
|
DBCLASS_CancelEjectTimeout(DeviceObject);
|
|
|
|
DBCLASS_KdPrint((1, "' Request to UNLOCK device\n"));
|
|
LOGENTRY(LOG_MISC, 'ULOC', 0, 0, 0);
|
|
}
|
|
|
|
*Handled = TRUE;
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
// Set up a completion routine to handle marking the IRP.
|
|
IoSetCompletionRoutine(Irp,
|
|
DBCLASS_PdoSetLockComplete,
|
|
DeviceObject,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
// Now Pass down the IRP
|
|
|
|
ntStatus = IoCallDriver(deviceExtensionPdoFilter->TopOfStackDeviceObject, Irp);
|
|
LOGENTRY(LOG_MISC, 'sLOC', ntStatus, 0, 0);
|
|
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
DBCLASS_KdPrint((1, "'(dbfilter)(device)IRP_MN_CANCEL_REMOVE_DEVICE\n"));
|
|
// TEST_TRAP();
|
|
break;
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
DBCLASS_KdPrint((1,
|
|
"'(dbfilter)(device)(%x)IRP_MN_QUERY_CAPABILITIES\n",
|
|
deviceExtensionPdoFilter->PhysicalDeviceObject));
|
|
//
|
|
// Do this for all 1394 PDOs regardless of if they are device bay
|
|
// PDOs
|
|
// if (deviceExtensionPdoFilter->DbcContext &&
|
|
// deviceExtensionPdoFilter->Bay) {
|
|
*Handled = TRUE;
|
|
|
|
DBCLASS_KdPrint((1,"'>>QCAPS 1394/USB Device Bay PDO\n"));
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
// Set up a completion routine to handle marking the IRP.
|
|
IoSetCompletionRoutine(Irp,
|
|
DBCLASS_DevicePdoQCapsComplete,
|
|
DeviceObject,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
// Now Pass down the IRP
|
|
|
|
ntStatus = IoCallDriver(deviceExtensionPdoFilter->TopOfStackDeviceObject, Irp);
|
|
// }
|
|
break;
|
|
} /* irpStack->MinorFunction */
|
|
break;
|
|
} /* irpStack->MajorFunction */
|
|
|
|
LOGENTRY(LOG_MISC, 'pdo<', 0, DeviceObject, ntStatus);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SyncGetFdoType(
|
|
IN PDEVICE_OBJECT FilterDeviceObject,
|
|
IN PULONG FdoType
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
This gets the bus type for this PDO (1394 or USB)
|
|
|
|
The goal of this function is to identify the stack the
|
|
filter is sitting on.
|
|
|
|
It is either:
|
|
1. The USB root bus
|
|
2. The 1394 HC
|
|
3. A USB hub (bus)
|
|
4. A USB Device
|
|
5. A 1394 Device
|
|
|
|
The filter sits above the FDO (upperfilter) for the
|
|
respective PDO -- it is loaded as a class filter for
|
|
USB and 1394.
|
|
|
|
We do not need to identify USB devices and 1394 devices (4,5)
|
|
since we attach sapartely to these when we hook QBRelations.
|
|
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Physical DeviceObject for the bus.
|
|
|
|
FdoType - set to DB_FDO_USBHUB_FILTER or
|
|
DB_FDO_1394_FILTER or
|
|
0 if bus type is neither
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION nextStack;
|
|
PIRP irp;
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
KEVENT event;
|
|
PPNP_BUS_INFORMATION busInfo;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PDEVICE_OBJECT pdoDeviceObject;
|
|
PDEVICE_OBJECT topDeviceObject;
|
|
PULONG Tag;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = FilterDeviceObject->DeviceExtension;
|
|
|
|
pdoDeviceObject = deviceExtension->PhysicalDeviceObject;
|
|
topDeviceObject = deviceExtension->TopOfStackDeviceObject;
|
|
|
|
DBCLASS_KdPrint((1, "'*>Filter -> QUERY BUS TYPE filter do %x\n",
|
|
FilterDeviceObject));
|
|
DBCLASS_KdPrint((1, "'*>Filter -> QUERY BUS TYPE pdo %x\n",
|
|
pdoDeviceObject));
|
|
DBCLASS_KdPrint((1, "'*>Filter -> QUERY BUS TYPE top %x\n",
|
|
topDeviceObject));
|
|
|
|
irp = IoAllocateIrp(FilterDeviceObject->StackSize, FALSE);
|
|
|
|
if (!irp) {
|
|
TRAP(); //"failed to allocate Irp
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
nextStack = IoGetNextIrpStackLocation(irp);
|
|
ASSERT(nextStack != NULL);
|
|
nextStack->MajorFunction= IRP_MJ_PNP;
|
|
nextStack->MinorFunction= IRP_MN_QUERY_BUS_INFORMATION;
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
irp->IoStatus.Information = 0;
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
IoSetCompletionRoutine(irp,
|
|
DBCLASS_DeferIrpCompletion,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
ntStatus = IoCallDriver(FilterDeviceObject,
|
|
irp);
|
|
|
|
if (ntStatus == STATUS_PENDING) {
|
|
// wait for irp to complete
|
|
|
|
KeWaitForSingleObject(
|
|
&event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
busInfo = (PPNP_BUS_INFORMATION) irp->IoStatus.Information;
|
|
|
|
*FdoType = DB_FDO_BUS_UNKNOWN;
|
|
|
|
Tag = (PULONG) topDeviceObject->DeviceExtension;
|
|
|
|
// see if this is a 1394 bus
|
|
if(*Tag == PORT_EXTENSION_TAG)
|
|
{
|
|
DBCLASS_KdPrint((1, "'1394 Device\n"));
|
|
*FdoType = DB_FDO_1394_BUS;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
DBCLASS_KdPrint((1, "'Tag (%08X) DevExt (%08X) DevObj(%08X)\n", *Tag, Tag, topDeviceObject));
|
|
DBCLASS_KdPrint((1, "'Status (%08X) Information (%08X)\n", irp->IoStatus.Status, irp->IoStatus.Information));
|
|
|
|
|
|
if (busInfo) {
|
|
#if DBG
|
|
DBCLASS_KdPrint((1, "'USB GUID\n"));
|
|
DBCLASS_KdPrintGuid(1, (PUCHAR) &GUID_BUS_TYPE_USB);
|
|
|
|
DBCLASS_KdPrint((1, "'RETURNED GUID\n"));
|
|
DBCLASS_KdPrintGuid(1, (PUCHAR) &busInfo->BusTypeGuid);
|
|
#endif
|
|
if (RtlCompareMemory(&busInfo->BusTypeGuid,
|
|
&GUID_BUS_TYPE_USB,
|
|
sizeof(GUID)) == sizeof(GUID)) {
|
|
|
|
*FdoType = DB_FDO_USBHUB_BUS;
|
|
|
|
DBCLASS_KdPrint((1, "'*>>Filter is for USB HUB\n"));
|
|
}
|
|
|
|
ExFreePool(busInfo);
|
|
} else {
|
|
DBCLASS_KdPrint((2, "'no busInfo returned\n"));
|
|
|
|
// this is either the 1394 or USB root bus
|
|
// send down an private IOCTL to see if it is USB
|
|
|
|
nextStack = IoGetNextIrpStackLocation(irp);
|
|
ASSERT(nextStack != NULL);
|
|
|
|
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode =
|
|
IOCTL_INTERNAL_USB_GET_BUSGUID_INFO;
|
|
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
irp->IoStatus.Information = 0;
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
IoSetCompletionRoutine(irp,
|
|
DBCLASS_DeferIrpCompletion,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
ntStatus = IoCallDriver(FilterDeviceObject,
|
|
irp);
|
|
|
|
if (ntStatus == STATUS_PENDING) {
|
|
// wait for irp to complete
|
|
|
|
KeWaitForSingleObject(
|
|
&event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
busInfo = (PPNP_BUS_INFORMATION) irp->IoStatus.Information;
|
|
|
|
DBCLASS_KdPrint((1, "'Status (%08X) Information (%08X)\n", irp->IoStatus.Status, irp->IoStatus.Information));
|
|
|
|
if (busInfo) {
|
|
#if DBG
|
|
DBCLASS_KdPrint((1, "'USB GUID\n"));
|
|
DBCLASS_KdPrintGuid(1, (PUCHAR) &GUID_BUS_TYPE_USB);
|
|
|
|
DBCLASS_KdPrint((1, "'RETURNED GUID\n"));
|
|
DBCLASS_KdPrintGuid(1, (PUCHAR) &busInfo->BusTypeGuid);
|
|
#endif
|
|
if (RtlCompareMemory(&busInfo->BusTypeGuid,
|
|
&GUID_BUS_TYPE_USB,
|
|
sizeof(GUID)) == sizeof(GUID)) {
|
|
|
|
*FdoType = DB_FDO_BUS_IGNORE;
|
|
DBCLASS_KdPrint((1, "'*>>Filter is for USB HC\n"));
|
|
}
|
|
|
|
ExFreePool(busInfo);
|
|
}
|
|
else{
|
|
// see if this is a 1394 bus
|
|
if(*Tag == PORT_EXTENSION_TAG){
|
|
DBCLASS_KdPrint((1, "'1394 Device\n"));
|
|
*FdoType = DB_FDO_1394_BUS;
|
|
}
|
|
}
|
|
}
|
|
|
|
ntStatus = STATUS_SUCCESS;
|
|
|
|
IoFreeIrp(irp);
|
|
|
|
#if DBG
|
|
switch(*FdoType) {
|
|
case DB_FDO_BUS_IGNORE:
|
|
DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_BUS_IGNORE\n"));
|
|
break;
|
|
case DB_FDO_BUS_UNKNOWN:
|
|
DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_BUS_UNKNOWN\n"));
|
|
break;
|
|
case DB_FDO_USB_DEVICE:
|
|
DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_USB_DEVICE\n"));
|
|
break;
|
|
case DB_FDO_USBHUB_BUS:
|
|
DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_USBHUB_BUS\n"));
|
|
break;
|
|
case DB_FDO_1394_BUS:
|
|
DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_1394_BUS\n"));
|
|
break;
|
|
case DB_FDO_1394_DEVICE:
|
|
DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_1394_DEVICE\n"));
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
BRK_ON_TRAP();
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_BusFilterDispatch(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PBOOLEAN Handled
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Device bay Filter FDO
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
ntStatus = Irp->IoStatus.Status;
|
|
*Handled = FALSE;
|
|
irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
LOGENTRY(LOG_MISC, 'dbf>', 0, DeviceObject, Irp);
|
|
|
|
DBCLASS_KdPrint((1, "'(dbfilter)(bus)(%08X)IRP_MJ_ (%08X) IRP_MN_ (%08X)\n",
|
|
DeviceObject, irpStack->MajorFunction, irpStack->MinorFunction));
|
|
|
|
switch (irpStack->MajorFunction) {
|
|
|
|
case IRP_MJ_PNP:
|
|
switch (irpStack->MinorFunction) {
|
|
case IRP_MN_START_DEVICE:
|
|
// see if we can id the bus we are on
|
|
|
|
ntStatus =
|
|
DBCLASS_SyncGetFdoType(DeviceObject,
|
|
&deviceExtension->FdoType);
|
|
|
|
if (deviceExtension->FdoType == DB_FDO_USBHUB_BUS) {
|
|
// filter is sitting on a USB HUB
|
|
|
|
// null context indicates that this hub is not
|
|
// part of a DBC
|
|
deviceExtension->DbcContext = NULL;
|
|
|
|
if (DBCLASS_IsHubPartOfACPI_DBC(DeviceObject)) {
|
|
|
|
deviceExtension->DbcContext =
|
|
DBCLASS_FindControllerACPI(deviceExtension->DriverObject,
|
|
DeviceObject);
|
|
|
|
if (deviceExtension->DbcContext) {
|
|
USHORT bay;
|
|
// set the dbContext to point at this
|
|
// hub
|
|
|
|
// may need to handle multiple hubs
|
|
// currently we do not
|
|
|
|
DBCLASS_KdPrint(
|
|
(1, "'** Found ACPI DBC controller, linked to USBHUB\n"));
|
|
|
|
for (bay=1; bay <=NUMBER_OF_BAYS(deviceExtension->DbcContext); bay++) {
|
|
deviceExtension->DbcContext->BayInformation[bay].UsbHubPdo =
|
|
deviceExtension->PhysicalDeviceObject;
|
|
}
|
|
}
|
|
#if DBG
|
|
else {
|
|
DBCLASS_KdPrint(
|
|
(0, "'** Could not find an ACPI DBC controller\n"));
|
|
}
|
|
#endif
|
|
|
|
} else {
|
|
// hub is not part of DBC (for now)
|
|
// if is part of USB dbc we will need to
|
|
// wait for Q_BUS_RELATIONS
|
|
deviceExtension->DbcContext = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
DBCLASS_KdPrint((1, "'(dbfilter)(bus)(%08X)IRP_MN_START_DEVICE\n", DeviceObject));
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
|
|
DBCLASS_KdPrint((1, "'(dbfilter)(bus)(%08X)IRP_MN_STOP_DEVICE\n", DeviceObject));
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
|
|
DBCLASS_KdPrint((1, "'(dbfilter)(bus)(%08X)IRP_MN_REMOVE_DEVICE\n", DeviceObject));
|
|
|
|
DBCLASS_RemoveBusFilterMDOFromList(DeviceObject);
|
|
|
|
IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
|
|
|
|
IoDeleteDevice(DeviceObject);
|
|
break;
|
|
|
|
break;
|
|
} /* irpStack->MinorFunction */
|
|
} /* irpStack->MajorFunction */
|
|
|
|
LOGENTRY(LOG_MISC, 'dbf<', 0, DeviceObject, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_GetRegistryKeyValueForPdo(
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
IN BOOLEAN SoftwareBranch,
|
|
IN PWCHAR KeyNameString,
|
|
IN ULONG KeyNameStringLength,
|
|
IN PVOID Data,
|
|
IN ULONG DataLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
UNICODE_STRING keyNameUnicodeString;
|
|
ULONG length;
|
|
PKEY_VALUE_FULL_INFORMATION fullInfo;
|
|
HANDLE handle;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (SoftwareBranch) {
|
|
ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DRIVER,
|
|
STANDARD_RIGHTS_ALL,
|
|
&handle);
|
|
} else {
|
|
ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_ALL,
|
|
&handle);
|
|
}
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
RtlInitUnicodeString(&keyNameUnicodeString, KeyNameString);
|
|
|
|
length = sizeof(KEY_VALUE_FULL_INFORMATION) +
|
|
KeyNameStringLength + DataLength;
|
|
|
|
fullInfo = ExAllocatePoolWithTag(PagedPool, length, DBC_TAG);
|
|
|
|
DBCLASS_KdPrint((2,"' DBCLASS_GetRegistryKeyValueForPdo buffer = (%08X)\n", fullInfo));
|
|
|
|
if (fullInfo) {
|
|
ntStatus = ZwQueryValueKey(handle,
|
|
&keyNameUnicodeString,
|
|
KeyValueFullInformation,
|
|
fullInfo,
|
|
length,
|
|
&length);
|
|
|
|
if (NT_SUCCESS(ntStatus)){
|
|
DBCLASS_ASSERT(DataLength == fullInfo->DataLength);
|
|
RtlCopyMemory(Data, ((PUCHAR) fullInfo) + fullInfo->DataOffset, DataLength);
|
|
}
|
|
|
|
ExFreePool(fullInfo);
|
|
}
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SetRegistryKeyValueForPdo(
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
IN BOOLEAN SoftwareBranch,
|
|
IN ULONG Type,
|
|
IN PWCHAR KeyNameString,
|
|
IN ULONG KeyNameStringLength,
|
|
IN PVOID Data,
|
|
IN ULONG DataLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
UNICODE_STRING keyNameUnicodeString;
|
|
HANDLE handle;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (SoftwareBranch) {
|
|
ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DRIVER,
|
|
STANDARD_RIGHTS_ALL,
|
|
&handle);
|
|
} else {
|
|
ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_ALL,
|
|
&handle);
|
|
}
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
RtlInitUnicodeString(&keyNameUnicodeString, KeyNameString);
|
|
|
|
ntStatus = ZwSetValueKey(handle,
|
|
&keyNameUnicodeString,
|
|
0,
|
|
Type,
|
|
Data,
|
|
DataLength);
|
|
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_DevicePdoQCapsComplete(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the device object
|
|
|
|
Irp - a pointer to the irp
|
|
|
|
Context - NULL ptr
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_OBJECT deviceFilterObject = Context;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PDBC_CONTEXT dbcContext;
|
|
PDEVICE_CAPABILITIES deviceCapabilities;
|
|
PIO_STACK_LOCATION ioStack;
|
|
BOOLEAN linkDeviceObject = FALSE;
|
|
|
|
deviceExtension = deviceFilterObject->DeviceExtension;
|
|
dbcContext = deviceExtension->DbcContext;
|
|
ioStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
|
|
#if DBG
|
|
if (deviceExtension->Bay)
|
|
{
|
|
DBCLASS_KdPrint((1, "'>QCAPS cmplt 1394/USB PDO %x -- Bay[%d]\n",
|
|
deviceExtension->PhysicalDeviceObject,
|
|
deviceExtension->Bay));
|
|
}
|
|
else
|
|
{
|
|
DBCLASS_KdPrint((1, "'>QCAPS cmplt 1394/USB PDO %x -- No Bay\n",
|
|
deviceExtension->PhysicalDeviceObject));
|
|
}
|
|
#endif
|
|
|
|
deviceCapabilities = ioStack->
|
|
Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
|
|
dbcContext = DBCLASS_ControllerList;
|
|
|
|
while(dbcContext)
|
|
{
|
|
|
|
if (DBCLASS_IsLinkDeviceObject(dbcContext,
|
|
deviceExtension->PhysicalDeviceObject))
|
|
{
|
|
|
|
DBCLASS_KdPrint((1, "'>>>1394 PDO is DBC Link, set suprise remove\n"));
|
|
linkDeviceObject = TRUE;
|
|
break;
|
|
}
|
|
|
|
dbcContext = dbcContext->Next;
|
|
}
|
|
|
|
|
|
if(linkDeviceObject)
|
|
{
|
|
// set surprise remove O.K. for device bay phy/link
|
|
deviceCapabilities->SurpriseRemovalOK = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// indicate eject is supported for regular devices
|
|
deviceCapabilities->EjectSupported = 1;
|
|
deviceCapabilities->LockSupported = 1;
|
|
}
|
|
|
|
#if DBG
|
|
{
|
|
ULONG i;
|
|
|
|
DBCLASS_KdPrint((1, "'DEVICE PDO: Device Caps\n"));
|
|
DBCLASS_KdPrint(
|
|
(1, "'>>\n LockSupported = %d\n EjectSupported = %d \n Removable = %d \n DockDevice = %x\n",
|
|
deviceCapabilities->LockSupported,
|
|
deviceCapabilities->EjectSupported,
|
|
deviceCapabilities->Removable,
|
|
deviceCapabilities->DockDevice));
|
|
|
|
DBCLASS_KdPrint(
|
|
(1, "'>>\n UniqueId = %d\n SilentInstall = %d \n RawDeviceOK = %d \n SurpriseRemovalOK = %x\n",
|
|
deviceCapabilities->UniqueID,
|
|
deviceCapabilities->SilentInstall,
|
|
deviceCapabilities->RawDeviceOK,
|
|
deviceCapabilities->SurpriseRemovalOK));
|
|
|
|
DBCLASS_KdPrint((1, "'Device State Map:\n"));
|
|
|
|
for (i=0; i< PowerSystemHibernate; i++) {
|
|
DBCLASS_KdPrint((1, "'-->S%d = D%d\n", i-1,
|
|
deviceCapabilities->DeviceState[i]-1));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
DBCLASS_EjectCancelWorker(
|
|
IN PVOID Context
|
|
)
|
|
/* ++
|
|
*
|
|
* Description:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Return:
|
|
*
|
|
* NTSTATUS
|
|
*
|
|
* -- */
|
|
{
|
|
PDBCLASS_WORKITEM workItem = Context;
|
|
PDBC_CONTEXT dbcContext = workItem->DbcContext;
|
|
PDBC_EJECT_TIMEOUT_CONTEXT timeoutContext =
|
|
workItem->TimeoutContext;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
LOGENTRY(LOG_MISC, 'eWK+', dbcContext, Context, timeoutContext);
|
|
|
|
DbcExFreePool(workItem);
|
|
|
|
// make sure the bay was mapped correctly before setting time out context
|
|
if(dbcContext->BayInformation[timeoutContext->BayNumber].DeviceFilterObject)
|
|
{
|
|
|
|
deviceExtension =
|
|
dbcContext->BayInformation[
|
|
timeoutContext->BayNumber].DeviceFilterObject->DeviceExtension;
|
|
|
|
deviceExtension->TimeoutContext = NULL;
|
|
|
|
}
|
|
|
|
DBCLASS_SyncBayFeatureRequest(dbcContext,
|
|
DRB_FUNCTION_SET_BAY_FEATURE,
|
|
timeoutContext->BayNumber,
|
|
REQUEST_DEVICE_ENABLED_STATE);
|
|
|
|
DBCLASS_DecrementIoCount(dbcContext);
|
|
DBCLASS_PostChangeRequest(dbcContext);
|
|
|
|
DbcExFreePool(timeoutContext);
|
|
LOGENTRY(LOG_MISC, 'eWK-', 0, Context, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
DBCLASS_EjectTimeoutDPC(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine runs at DISPATCH_LEVEL IRQL.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
Dpc - Pointer to the DPC object.
|
|
|
|
DeferredContext -
|
|
|
|
SystemArgument1 - not used.
|
|
|
|
SystemArgument2 - not used.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PDBC_EJECT_TIMEOUT_CONTEXT
|
|
timeoutContext = DeferredContext;
|
|
PDBCLASS_WORKITEM workItem;
|
|
|
|
LOGENTRY(LOG_MISC, 'EJCo', 0, 0, timeoutContext);
|
|
|
|
DBCLASS_KdPrint((1, "'**>Eject Timeout for Bay[%d]\n",
|
|
timeoutContext->BayNumber));
|
|
|
|
workItem = DbcExAllocatePool(NonPagedPool, sizeof(DBCLASS_WORKITEM));
|
|
|
|
if (workItem) {
|
|
LOGENTRY(LOG_MISC, 'qETM', 0,
|
|
workItem, 0);
|
|
|
|
workItem->Sig = DBC_WORKITEM_SIG;
|
|
workItem->DbcContext = timeoutContext->DbcContext;
|
|
workItem->TimeoutContext = timeoutContext;
|
|
//workItem->IrpStatus = Irp->IoStatus.Status;
|
|
|
|
ExInitializeWorkItem(&workItem->WorkQueueItem,
|
|
DBCLASS_EjectCancelWorker,
|
|
workItem);
|
|
|
|
DBCLASS_IncrementIoCount(timeoutContext->DbcContext);
|
|
ExQueueWorkItem(&workItem->WorkQueueItem,
|
|
DelayedWorkQueue);
|
|
|
|
} else {
|
|
TRAP();
|
|
DbcExFreePool(timeoutContext);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_SetEjectTimeout(
|
|
PDEVICE_OBJECT DeviceFilterMDO
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
for a given device PDO set the eject timeout for it
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PDBC_EJECT_TIMEOUT_CONTEXT timeoutContext;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
timeoutContext = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(DBC_EJECT_TIMEOUT_CONTEXT));
|
|
|
|
// extension for the device filter PDO
|
|
deviceExtension = DeviceFilterMDO->DeviceExtension;
|
|
|
|
if (timeoutContext) {
|
|
LARGE_INTEGER dueTime;
|
|
|
|
LOGENTRY(LOG_MISC, 'EJCs', deviceExtension->Bay, 0, timeoutContext);
|
|
|
|
timeoutContext->BayNumber =
|
|
deviceExtension->Bay;
|
|
timeoutContext->DbcContext =
|
|
deviceExtension->DbcContext;
|
|
DBCLASS_KdPrint((1, "'**>Set Eject Timeout for Bay[%d]\n",
|
|
timeoutContext->BayNumber));
|
|
|
|
// DBCLASS_ASSERT(deviceExtension->TimeoutContext == NULL);
|
|
deviceExtension->TimeoutContext =
|
|
timeoutContext;
|
|
|
|
KeInitializeTimer(&timeoutContext->TimeoutTimer);
|
|
KeInitializeDpc(&timeoutContext->TimeoutDpc,
|
|
DBCLASS_EjectTimeoutDPC,
|
|
timeoutContext);
|
|
|
|
dueTime.QuadPart = -10000 * DBCLASS_EJECT_TIMEOUT;
|
|
|
|
KeSetTimer(&timeoutContext->TimeoutTimer,
|
|
dueTime,
|
|
&timeoutContext->TimeoutDpc);
|
|
|
|
} else {
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_CancelEjectTimeout(
|
|
PDEVICE_OBJECT DeviceFilterMDO
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
for a given device PDO set the eject timeout for it
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PDBC_EJECT_TIMEOUT_CONTEXT timeoutContext;
|
|
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = DeviceFilterMDO->DeviceExtension;
|
|
timeoutContext = deviceExtension->TimeoutContext;
|
|
deviceExtension->TimeoutContext = NULL;
|
|
|
|
LOGENTRY(LOG_MISC, 'EJCc', 0, 0, timeoutContext);
|
|
|
|
if (timeoutContext) {
|
|
if (KeCancelTimer(&timeoutContext->TimeoutTimer)) {
|
|
// timer was pulled out of the queue
|
|
|
|
DBCLASS_KdPrint((1, "'**>Canceled Eject Timeout for Bay[%d]\n",
|
|
timeoutContext->BayNumber));
|
|
LOGENTRY(LOG_MISC, 'EJCk', 0, 0, timeoutContext);
|
|
DbcExFreePool(timeoutContext);
|
|
}
|
|
} else {
|
|
DBCLASS_KdPrint((1, "'**>Cancel Eject Timeout, No Timeout\n"));
|
|
|
|
}
|
|
|
|
ntStatus = STATUS_SUCCESS;
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_CheckPhyLink(
|
|
PDEVICE_OBJECT DevicePdo1394
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a 1394 PDO see if it is the phy/link for any of our DBC
|
|
controllers
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
PDBC_CONTEXT dbcContext;
|
|
|
|
dbcContext = DBCLASS_ControllerList;
|
|
|
|
while (dbcContext) {
|
|
|
|
LOGENTRY(LOG_MISC, 'FINl', dbcContext, 0, DevicePdo1394);
|
|
|
|
if (DBCLASS_IsLinkDeviceObject(dbcContext, DevicePdo1394))
|
|
{
|
|
dbcContext->LinkDeviceObject = DevicePdo1394;
|
|
DBCLASS_KdPrint((1, "'>PDO is DBC Link \n"));
|
|
DBCLASS_KdPrint((1, "'>LinkDevObj (%08x) \n", dbcContext->LinkDeviceObject));
|
|
|
|
}
|
|
|
|
dbcContext = dbcContext->Next;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_GetConfigValue(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a callback routine for RtlQueryRegistryValues
|
|
It is called for each entry in the Parameters
|
|
node to set the config values. The table is set up
|
|
so that this function will be called with correct default
|
|
values for keys that are not present.
|
|
|
|
Arguments:
|
|
|
|
ValueName - The name of the value (ignored).
|
|
ValueType - The type of the value
|
|
ValueData - The data for the value.
|
|
ValueLength - The length of ValueData.
|
|
Context - A pointer to the CONFIG structure.
|
|
EntryContext - The index in Config->Parameters to save the value.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
DBCLASS_KdPrint((2, "'Type (%08X), Length (%08X)\n", ValueType, ValueLength));
|
|
|
|
switch (ValueType) {
|
|
case REG_DWORD:
|
|
*(PVOID*)EntryContext = *(PVOID*)ValueData;
|
|
break;
|
|
case REG_BINARY:
|
|
// we are only set up to read a byte
|
|
RtlCopyMemory(EntryContext, ValueData, 1);
|
|
break;
|
|
default:
|
|
ntStatus = STATUS_INVALID_PARAMETER;
|
|
}
|
|
return ntStatus;
|
|
}
|
|
|
|
#if 0
|
|
|
|
NTSTATUS
|
|
DBCLASS_GetClassGlobalRegistryParameters(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
PWCHAR usb = L"class\\dbc";
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Set up QueryTable to do the following:
|
|
//
|
|
|
|
// spew level
|
|
QueryTable[0].QueryRoutine = DBCLASS_GetConfigValue;
|
|
QueryTable[0].Flags = 0;
|
|
QueryTable[0].Name = ACPI_HUB_KEY;
|
|
QueryTable[0].EntryContext = &DBCLASS_AcpiDBCHubParentPort;
|
|
QueryTable[0].DefaultType = REG_DWORD;
|
|
QueryTable[0].DefaultData = &DBCLASS_AcpiDBCHubParentPort;
|
|
QueryTable[0].DefaultLength = sizeof(DBCLASS_AcpiDBCHubParentPort);
|
|
|
|
//
|
|
// Stop
|
|
//
|
|
QueryTable[1].QueryRoutine = NULL;
|
|
QueryTable[1].Flags = 0;
|
|
QueryTable[1].Name = NULL;
|
|
|
|
ntStatus = RtlQueryRegistryValues(
|
|
RTL_REGISTRY_SERVICES,
|
|
usb,
|
|
QueryTable, // QueryTable
|
|
NULL, // Context
|
|
NULL); // Environment
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
DBCLASS_KdPrint((1, "'AcpiDBCHubParentPort Set: (%d)\n",
|
|
DBCLASS_AcpiDBCHubParentPort));
|
|
|
|
}
|
|
|
|
if ( STATUS_OBJECT_NAME_NOT_FOUND == ntStatus ) {
|
|
ntStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_EjectBayComplete(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the device object
|
|
|
|
Irp - a pointer to the irp
|
|
|
|
Context - NULL ptr
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PEJECT_CONTEXT ejectContext = Context;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PDBC_CONTEXT dbcContext;
|
|
USHORT bay;
|
|
NTSTATUS ntStatus;
|
|
|
|
bay = ejectContext->Bay;
|
|
dbcContext = ejectContext->DbcContext;
|
|
DbcExFreePool(ejectContext);
|
|
|
|
ntStatus = Irp->IoStatus.Status;
|
|
|
|
DBCLASS_KdPrint((0, "'>>Request Device Eject BAY[%d] complete Status (%08X)\n",
|
|
bay, ntStatus));
|
|
|
|
// set a timeout for the eject
|
|
// if the request failed the timeout will kick in and
|
|
// re-post the chage request for us
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
// check and see if the bay is locked
|
|
|
|
if((!dbcContext->SubsystemDescriptor.bmAttributes.HasSecurityLock) ||
|
|
(dbcContext->SubsystemDescriptor.bmAttributes.HasSecurityLock &&
|
|
!dbcContext->BayInformation[bay].LastBayStatus.SecurityLockEngaged))
|
|
{
|
|
#if 0
|
|
if (dbcContext->BayInformation[bay].DeviceFilterObject) {
|
|
|
|
DBCLASS_ASSERT(dbcContext->BayInformation[bay].DeviceFilterObject);
|
|
|
|
DBCLASS_SetEjectTimeout(dbcContext->BayInformation[bay].DeviceFilterObject);
|
|
|
|
deviceExtension =
|
|
dbcContext->BayInformation[bay].DeviceFilterObject->DeviceExtension;
|
|
|
|
DBCLASS_KdPrint((0, "'>>>Ejecting Filter %x PDO %x\n",
|
|
dbcContext->BayInformation[bay].DeviceFilterObject,
|
|
deviceExtension->PhysicalDeviceObject));
|
|
LOGENTRY(LOG_MISC, 'EJE+', 0, 0, deviceExtension->PhysicalDeviceObject);
|
|
|
|
IoRequestDeviceEject(deviceExtension->PhysicalDeviceObject);
|
|
|
|
} else {
|
|
|
|
#endif
|
|
DBCLASS_KdPrint((0, "'>>>No PDO for this bay\n"));
|
|
#if 0
|
|
|
|
if (dbcContext->BusFilterMdo1394 != NULL ||
|
|
dbcContext->BusFilterMdoUSB != NULL)
|
|
#endif
|
|
{
|
|
PDRB drb;
|
|
|
|
//
|
|
// notify filter of a stop
|
|
// note that the filter may not veto the stop
|
|
//
|
|
drb = DbcExAllocatePool(NonPagedPool,
|
|
sizeof(struct _DRB_START_DEVICE_IN_BAY));
|
|
|
|
if (drb)
|
|
{
|
|
|
|
drb->DrbHeader.Length = sizeof(struct _DRB_STOP_DEVICE_IN_BAY);
|
|
drb->DrbHeader.Function = DRB_FUNCTION_STOP_DEVICE_IN_BAY;
|
|
drb->DrbHeader.Flags = 0;
|
|
|
|
drb->DrbStartDeviceInBay.BayNumber = bay;
|
|
|
|
// make the request
|
|
ntStatus = DBCLASS_SyncSubmitDrb(dbcContext,
|
|
dbcContext->TopOfStack,
|
|
drb);
|
|
DbcExFreePool(drb);
|
|
}
|
|
|
|
// just pop out the device --
|
|
// surprise remove is OK at this point
|
|
DBCLASS_EjectBay(dbcContext, bay);
|
|
|
|
DBCLASS_PostChangeRequest(dbcContext);
|
|
|
|
}
|
|
#if 0
|
|
#if DBG
|
|
else {
|
|
DBCLASS_KdPrint((0, "'>>Filter has not registered\n"));
|
|
TRAP();
|
|
}
|
|
#endif
|
|
#endif
|
|
#if 0
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
IoFreeIrp(Irp);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|