Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

522 lines
14 KiB

//----------------- Original Sig ------------------------
/*++
Copyright (c) 1991-1999 Microsoft Corporation
Module Name:
fpfilter.c
--*/
#define INITGUID
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
#include "usbdi.h"
#include "usbdlib.h"
//
// Bit Flag Macros
//
#define SET_FLAG(Flags, Bit) ((Flags) |= (Bit))
#define CLEAR_FLAG(Flags, Bit) ((Flags) &= ~(Bit))
#define TEST_FLAG(Flags, Bit) (((Flags) & (Bit)) != 0)
//
// Remove lock
//
#define REMLOCK_TAG 'QV2K'
#define REMLOCK_MAXIMUM 1 // Max minutes system allows lock to be held
#define REMLOCK_HIGHWATER 250 // Max number of irps holding lock at one time
//
// Device Extension
//
typedef struct _FDO_EXTENSION {
ULONG Signature;
PDEVICE_OBJECT Fdo; // Back pointer to Fdo
PDEVICE_OBJECT Pdo; // Not Used
PDEVICE_OBJECT Ldo; // Lower Device Object
PDEVICE_OBJECT PhysicalDeviceObject; // Not Used
KEVENT SyncEvent; // for ForwardIrpSynchronous
} FDO_EXTENSION, *PFDO_EXTENSION;
#define FDO_EXTENSION_SIZE sizeof(FDO_EXTENSION)
//
// Function declarations
//
NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
NTSTATUS QV2KUX_AddDevice ( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);
VOID QV2KUX_Unload ( IN PDRIVER_OBJECT DriverObject );
NTSTATUS QV2KUX_ForwardIrpSynchronous( IN PDEVICE_OBJECT Fdo, IN PIRP Irp);
NTSTATUS QV2KUX_DispatchPnp ( IN PDEVICE_OBJECT Fdo, IN PIRP Irp);
NTSTATUS QV2KUX_DispatchPower ( IN PDEVICE_OBJECT Fdo, IN PIRP Irp);
NTSTATUS QV2KUX_StartDevice ( IN PDEVICE_OBJECT Fdo, IN PIRP Irp);
NTSTATUS QV2KUX_RemoveDevice ( IN PDEVICE_OBJECT Fdo, IN PIRP Irp);
NTSTATUS QV2KUX_SendToNextDriver ( IN PDEVICE_OBJECT Fdo, IN PIRP Irp);
NTSTATUS QV2KUX_Internal_IOCTL ( IN PDEVICE_OBJECT Fdo, IN PIRP Irp);
NTSTATUS QV2KUX_IrpCompletion ( IN PDEVICE_OBJECT Fdo, IN PIRP Irp, IN PVOID Context);
VOID QV2KUX_SyncFilterWithLdo ( IN PDEVICE_OBJECT Fdo, IN PDEVICE_OBJECT Ldo);
#if DBG
#define DEBUG_BUFFER_LENGTH 256
ULONG QV2KUX_Debug = 0;
UCHAR QV2KUX_DebugBuffer[DEBUG_BUFFER_LENGTH];
VOID QV2KUX_DebugPrint( ULONG DebugPrintLevel, PCCHAR DebugMessage, ...);
#define DebugPrint(x) QV2KUX_DebugPrint x
#else
#define DebugPrint(x)
#endif
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
/*++
Routine Description:
ここではエントリーポイントの設定だけをする
Arguments:
DriverObject - The disk performance driver object.
RegistryPath - pointer to a unicode string representing the path,
to driver-specific key in the registry.
Return Value:
STATUS_SUCCESS
--*/
{
ULONG ulIndex;
PDRIVER_DISPATCH * dispatch;
// とりあえず全てバイパスするように設定
for (ulIndex = 0, dispatch = DriverObject->MajorFunction;
ulIndex <= IRP_MJ_MAXIMUM_FUNCTION;
ulIndex++, dispatch++) {
*dispatch = QV2KUX_SendToNextDriver;
}
// 上記の設定ではまずい部分の変更
DriverObject->MajorFunction[IRP_MJ_POWER] = QV2KUX_DispatchPower;
DriverObject->DriverUnload = QV2KUX_Unload;
//最低限必要なこと
DriverObject->MajorFunction[IRP_MJ_PNP] = QV2KUX_DispatchPnp;
DriverObject->DriverExtension->AddDevice = QV2KUX_AddDevice;
// 実質的にやりたかった部分
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = QV2KUX_Internal_IOCTL;
return(STATUS_SUCCESS);
} // end DriverEntry()
#define FILTER_DEVICE_PROPOGATE_FLAGS 0
#define FILTER_DEVICE_PROPOGATE_CHARACTERISTICS (FILE_REMOVABLE_MEDIA | \
FILE_READ_ONLY_DEVICE | \
FILE_FLOPPY_DISKETTE \
)
VOID QV2KUX_SyncFilterWithLdo( IN PDEVICE_OBJECT Fdo, IN PDEVICE_OBJECT Ldo)
{
ULONG propFlags;
//
// Propogate all useful flags from target to QV2KUX_. MountMgr will look
// at the QV2KUX_ object capabilities to figure out if the disk is
// a removable and perhaps other things.
//
propFlags = Ldo->Flags & FILTER_DEVICE_PROPOGATE_FLAGS;
SET_FLAG(Fdo->Flags, propFlags);
propFlags = Ldo->Characteristics & FILTER_DEVICE_PROPOGATE_CHARACTERISTICS;
SET_FLAG(Fdo->Characteristics, propFlags);
}
NTSTATUS QV2KUX_AddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)
/*++
Routine Description:
DeviceObjectの作製とそのDeviceExtensionの初期化
このプログラムでは、PDOは作製しないでFDOのみ使用する
Arguments:
DriverObject - Disk performance driver object.
PhysicalDeviceObject - Physical Device Object from the underlying layered driver
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PDEVICE_OBJECT Fdo;
PFDO_EXTENSION fdoExtension;
PIRP irp;
// Create a filter device object for this device (partition).
DebugPrint((2, "QV2KUX_AddDevice: Driver %p Device %p\n", DriverObject, PhysicalDeviceObject));
status = IoCreateDevice(DriverObject, FDO_EXTENSION_SIZE, NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &Fdo);
if (!NT_SUCCESS(status)) {
DebugPrint((1, "QV2KUX_AddDevice: Cannot create Fdo\n"));
return status;
}
SET_FLAG(Fdo->Flags, DO_DIRECT_IO);
fdoExtension = Fdo->DeviceExtension;
RtlZeroMemory(fdoExtension, FDO_EXTENSION_SIZE);
fdoExtension->Signature = 'QV2K';
fdoExtension->Fdo = Fdo;
fdoExtension->PhysicalDeviceObject = PhysicalDeviceObject;
// 下位ドライバに接続
fdoExtension->Ldo = IoAttachDeviceToDeviceStack(Fdo, PhysicalDeviceObject);
if (fdoExtension->Ldo == NULL) {
IoDeleteDevice(Fdo);
DebugPrint((1, "QV2KUX_AddDevice: Unable to attach %X to target %X\n", Fdo, PhysicalDeviceObject));
return STATUS_NO_SUCH_DEVICE;
}
// ForwardIrpSynchronousで使用する
KeInitializeEvent(&fdoExtension->SyncEvent, NotificationEvent, FALSE);
// default to DO_POWER_PAGABLE
SET_FLAG(Fdo->Flags, DO_POWER_PAGABLE);
// Clear the DO_DEVICE_INITIALIZING flag
CLEAR_FLAG(Fdo->Flags, DO_DEVICE_INITIALIZING);
return STATUS_SUCCESS;
} // end QV2KUX_AddDevice()
NTSTATUS QV2KUX_DispatchPnp(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
/*++
Routine Description:
Dispatch for PNP
Arguments:
Fdo - Supplies the device object.
Irp - Supplies the I/O request packet.
Return Value:
NTSTATUS
--*/
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status;
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
BOOLEAN lockHeld;
BOOLEAN irpCompleted;
DebugPrint((2, "QV2KUX_DispatchPnp: Device %X Irp %X\n", Fdo, Irp));
irpCompleted = FALSE;
switch(irpSp->MinorFunction) {
case IRP_MN_START_DEVICE: status = QV2KUX_StartDevice(Fdo, Irp); break;
case IRP_MN_REMOVE_DEVICE: status = QV2KUX_RemoveDevice(Fdo, Irp); break;
default: status = QV2KUX_SendToNextDriver(Fdo, Irp); irpCompleted = TRUE; break;
}
if (! irpCompleted) {
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return status;
} // end QV2KUX_DispatchPnp()
NTSTATUS QV2KUX_IrpCompletion( IN PDEVICE_OBJECT Fdo, IN PIRP Irp, IN PVOID Context)
/*++
Routine Description:
Forwarded IRP completion routine. Set an event and return
STATUS_MORE_PROCESSING_REQUIRED. Irp forwarder will wait on this
event and then re-complete the irp after cleaning up.
Arguments:
Fdo is the device object of the WMI driver
Irp is the WMI irp that was just completed
Context is a PKEVENT that forwarder will wait on
Return Value:
STATUS_MORE_PORCESSING_REQUIRED
--*/
{
PKEVENT Event = (PKEVENT) Context;
UNREFERENCED_PARAMETER(Fdo);
UNREFERENCED_PARAMETER(Irp);
KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
// Irpをまだ使い、上にはCompletionをまだ知らせない
return(STATUS_MORE_PROCESSING_REQUIRED);
} // end QV2KUX_IrpCompletion()
NTSTATUS QV2KUX_StartDevice( IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
/*++
Routine Description:
This routine is called when a Pnp Start Irp is received.
It will schedule a completion routine to initialize and register with WMI.
Arguments:
Fdo - a pointer to the device object
Irp - a pointer to the irp
Return Value:
Status of processing the Start Irp
--*/
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
KEVENT event;
NTSTATUS status;
status = QV2KUX_ForwardIrpSynchronous(Fdo, Irp);
QV2KUX_SyncFilterWithLdo(Fdo, fdoExtension->Ldo);
return status;
}
NTSTATUS QV2KUX_RemoveDevice( IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
/*++
Routine Description:
This routine is called when the device is to be removed.
It will de-register itself from WMI first, detach itself from the
stack before deleting itself.
Arguments:
Fdo - a pointer to the device object
Irp - a pointer to the irp
Return Value:
Status of removing the device
--*/
{
NTSTATUS status;
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
status = QV2KUX_ForwardIrpSynchronous(Fdo, Irp);
IoDetachDevice(fdoExtension->Ldo);
IoDeleteDevice(Fdo);
return status;
}
NTSTATUS QV2KUX_SendToNextDriver( IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
/*++
Routine Description:
This routine sends the Irp to the next driver in line
when the Irp is not processed by this driver.
Arguments:
Fdo
Irp
Return Value:
NTSTATUS
--*/
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(fdoExtension->Ldo, Irp);
} // end QV2KUX_SendToNextDriver()
NTSTATUS QV2KUX_DispatchPower( IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(fdoExtension->Ldo, Irp);
} // end QV2KUX_DispatchPower
NTSTATUS QV2KUX_ForwardIrpSynchronous( IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
/*++
Routine Description:
This routine sends the Irp to the next driver in line
when the Irp needs to be processed by the lower drivers
prior to being processed by this one.
Arguments:
Fdo
Irp
Return Value:
NTSTATUS
--*/
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
NTSTATUS status;
//イベントのクリア
KeClearEvent(&fdoExtension->SyncEvent);
//IrpStackのコピー
IoCopyCurrentIrpStackLocationToNext(Irp);
// IrpCompletionの設定
IoSetCompletionRoutine(Irp, QV2KUX_IrpCompletion, &fdoExtension->SyncEvent, TRUE, TRUE, TRUE);
// call the next lower device
status = IoCallDriver(fdoExtension->Ldo, Irp);
// wait for the actual completion
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&fdoExtension->SyncEvent, Executive, KernelMode, FALSE, NULL);
status = Irp->IoStatus.Status;
}
return status;
} // end QV2KUX_ForwardIrpSynchronous()
VOID QV2KUX_Unload( IN PDRIVER_OBJECT DriverObject)
/*++
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object.
Return Value:
VOID.
--*/
{
return;
}
NTSTATUS QV2KUX_Internal_IOCTL(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
NTSTATUS ntStatus;
PIO_STACK_LOCATION IrpSp;
PURB urb;
PUCHAR IoBuffer;
USHORT length;
UCHAR subclass;
if (fdoExtension->Signature != 'QV2K') return QV2KUX_SendToNextDriver(Fdo,Irp);
IrpSp = IoGetCurrentIrpStackLocation(Irp);
urb = IrpSp->Parameters.Others.Argument1;
if (!urb) return QV2KUX_SendToNextDriver(Fdo,Irp);
if (urb->UrbHeader.Function != URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
return QV2KUX_SendToNextDriver(Fdo,Irp);
// 1回目は USB_DEVICE_DESCRIPTOR_TYPE Length = 0x12;
// 2回目は USB_CONFIGURATION_DESCRIPTOR_TYPE LENGHT = 0x9
// 3回目は USB_CONFIGURATION_DESCRIPTOR_TYPE LENGHT = interface,endpoint descriptorを含めた長さ
if (urb->UrbControlDescriptorRequest.TransferBufferLength <= 0x12)
return QV2KUX_SendToNextDriver(Fdo,Irp);
// 3回目だけが通過する
DebugPrint((0,"URB Get All of Configuration Descriptor \n"));
ntStatus = QV2KUX_ForwardIrpSynchronous(Fdo,Irp);
if (NT_SUCCESS(ntStatus)) {
IoBuffer = (UCHAR *)urb->UrbControlDescriptorRequest.TransferBuffer;
length = (USHORT)urb->UrbControlDescriptorRequest.TransferBufferLength;
while(length >= 9) {
//InterfaceDescriptorを切り分ける
if (*(IoBuffer+1) == 4) {
subclass = *(IoBuffer+6);
DebugPrint((0,"QV2K_IntIoctl: SubCrass = %d \n",subclass));
if (*(IoBuffer+6) == 6) *(IoBuffer+6) = 5;
}
length -= *IoBuffer;
IoBuffer += *IoBuffer;
}
}
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return ntStatus;
}
#if DBG
VOID
QV2KUX_DebugPrint(
ULONG DebugPrintLevel,
PCCHAR DebugMessage,
...
)
/*++
Routine Description:
Debug print for all QV2KUX_
Arguments:
Debug print level between 0 and 3, with 3 being the most verbose.
Return Value:
None
--*/
{
va_list ap;
va_start(ap, DebugMessage);
if ((DebugPrintLevel <= (QV2KUX_Debug & 0x0000ffff)) ||
((1 << (DebugPrintLevel + 15)) & QV2KUX_Debug)) {
_vsnprintf(QV2KUX_DebugBuffer, DEBUG_BUFFER_LENGTH, DebugMessage, ap);
DbgPrint(QV2KUX_DebugBuffer);
}
va_end(ap);
}
#endif