|
|
// @doc
/**********************************************************************
* * @module SwUsbFltShell.c | * * Basic driver entry points for SwUsbFlt.sys * * History * ---------------------------------------------------------- * Matthew L Coill Original * * (c) 1986-1998 Microsoft Corporation. All right reserved. * * @topic SwUsbFltShell | * Contains the most basic driver entry points (that any WDM driver * would have) for SwUsbFlt.sys. * **********************************************************************/ #define __DEBUG_MODULE_IN_USE__ SWUSBFLTSHELL_C
#include <wdm.h>
#include <usbdi.h>
#include <usbdlib.h>
#include "SwUsbFltShell.h"
typedef unsigned char BYTE;
// Some Local defines for HID
#define HID_REQUEST_TYPE 0x22
#define HID_REPORT_REQUEST 0xA
#define USB_INTERFACE_CLASS_HID 0x03
#define DESCRIPTOR_TYPE_CONFIGURATION 0x22
// Memory TAG
#define SWFILTER_TAG (ULONG)'lfWS'
// Forward Definitions
NTSTATUS SWUSB_AddDevice(IN PDRIVER_OBJECT, IN PDEVICE_OBJECT); NTSTATUS SWUSB_Power(IN PDEVICE_OBJECT, IN PIRP); VOID SWUSB_Unload(IN PDRIVER_OBJECT);
//
// Mark the pageable routines as such
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, SWUSB_AddDevice)
#pragma alloc_text (PAGE, SWUSB_Unload)
#pragma alloc_text (PAGE, SWUSB_Power)
#pragma alloc_text (PAGE, SWUSB_PnP)
#endif
/***********************************************************************************
** ** NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) ** ** @func Standard DriverEntry routine ** ** @rdesc STATUS_SUCCESS or various errors ** *************************************************************************************/ NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, // @parm Driver Object
IN PUNICODE_STRING puniRegistryPath // @parm Path to driver specific registry section.
) { int i; UNREFERENCED_PARAMETER (puniRegistryPath); PAGED_CODE(); KdPrint(("Built %s at %s\n", __DATE__, __TIME__)); KdPrint(("Entering DriverEntry, pDriverObject = 0x%0.8x\n", pDriverObject)); // Hook all IRPs so we can pass them on.
for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { pDriverObject->MajorFunction[i] = SWUSB_Pass; }
// Define entries for IRPs we expect to handle
pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = SWUSB_Ioctl_Internal; pDriverObject->MajorFunction[IRP_MJ_PNP] = SWUSB_PnP; pDriverObject->MajorFunction[IRP_MJ_POWER] = SWUSB_Power; pDriverObject->DriverExtension->AddDevice = SWUSB_AddDevice; pDriverObject->DriverUnload = SWUSB_Unload;
return STATUS_SUCCESS; }
/***********************************************************************************
** ** VOID SWUSB_Unload(IN PDRIVER_OBJECT pDriverObject) ** ** @func Called to unload driver deallocate any memory here ** *************************************************************************************/ VOID SWUSB_Unload ( IN PDRIVER_OBJECT pDriverObject //@parm Driver Object for our driver
) { PAGED_CODE(); UNREFERENCED_PARAMETER(pDriverObject);
KdPrint(("SWUsbFlt.sys unloading\n"));
return; }
/***********************************************************************************
** ** NTSTATUS SWUSB_AddDevice(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pPhysicalDeviceObject) ** ** @func Handles AddDevice calls from PnP system, create filter device and ** attach to top of stack. ** @rdesc STATUS_SUCCES, or various errors ** *************************************************************************************/ NTSTATUS SWUSB_AddDevice ( IN PDRIVER_OBJECT pDriverObject, // @parm Driver object to create filter device for
IN PDEVICE_OBJECT pPhysicalDeviceObject // @parm PDO for device to create
) { NTSTATUS NtStatus = STATUS_SUCCESS; PDEVICE_OBJECT pDeviceObject = NULL; PSWUSB_FILTER_EXT pFilterExt = NULL; PAGED_CODE(); KdPrint(("Entering SWUSB_AddDevice, pDriverObject = 0x%0.8x, pPDO = 0x%0.8x\n", pDriverObject, pPhysicalDeviceObject)); // Create a filter device object.
NtStatus = IoCreateDevice(pDriverObject, sizeof (SWUSB_FILTER_EXT), NULL, // No Name
FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
if (!NT_SUCCESS (NtStatus)) { //
// returning failure here prevents the entire stack from functioning,
// but most likely the rest of the stack will not be able to create
// device objects either, so it is still OK.
//
KdPrint(("Failed to create filter device object\n")); KdPrint(("Exiting AddDevice(prematurely) Status: 0x%0.8x\n", NtStatus)); return NtStatus; }
// Initialize the the device extension.
pFilterExt = (PSWUSB_FILTER_EXT)pDeviceObject->DeviceExtension; // Get pointer to extension
pFilterExt->pPDO = pPhysicalDeviceObject; // Remember our PDO
pFilterExt->pTopOfStack = NULL; //We are not attached to stack yet
// We don't have the pipe information until PNP StartDevice
RtlZeroMemory(&(pFilterExt->outputPipeInfo), sizeof(USBD_PIPE_INFORMATION));
//we use the same IO method as hidclass.sys, which DO_DIRECT_IO
pDeviceObject->StackSize = pPhysicalDeviceObject->StackSize + 1; pDeviceObject->Flags |= (DO_DIRECT_IO | DO_POWER_PAGABLE); pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
// Attach our filter driver to the device stack.
// the return value of IoAttachDeviceToDeviceStack is the top of the
// attachment chain. This is where all the IRPs should be routed.
//
// Our filter will send IRPs to the top of the stack and use the PDO
// for all PlugPlay functions.
pFilterExt->pTopOfStack = IoAttachDeviceToDeviceStack (pDeviceObject, pPhysicalDeviceObject); // if this attachment fails then top of stack will be null.
// failure for attachment is an indication of a broken plug play system.
ASSERT (NULL != pFilterExt->pTopOfStack);
KdPrint(("Exiting SWUSB_AddDevice with STATUS_SUCCESS\n")); return STATUS_SUCCESS; }
NTSTATUS SWUSB_SubmitUrb ( IN PDEVICE_OBJECT pDeviceObject, //@parm [OUT] Device Object to submit URB on
IN PURB pUrb //@parm [OUT] URB to submit
) { NTSTATUS NtStatus; PSWUSB_FILTER_EXT pFilterExt; PIRP pIrp; KEVENT event; IO_STATUS_BLOCK ioStatus; PIO_STACK_LOCATION pNextStack;
KdPrint(("Entering SWUSB_SubmitUrb\n")); pFilterExt = (PSWUSB_FILTER_EXT)pDeviceObject->DeviceExtension;
// issue a synchronous request to read the UTB
KeInitializeEvent(&event, NotificationEvent, FALSE);
pIrp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, pFilterExt->pTopOfStack, NULL, 0, NULL, 0, TRUE, /* INTERNAL */ &event, &ioStatus);
if (pIrp) { // pass the URB to the USB 'class driver'
pNextStack = IoGetNextIrpStackLocation(pIrp); ASSERT(pNextStack != NULL); pNextStack->Parameters.Others.Argument1 = pUrb;
NtStatus = IoCallDriver(pFilterExt->pTopOfStack, pIrp); if (NtStatus == STATUS_PENDING) { NTSTATUS waitStatus;
// Specify a timeout of 5 seconds for this call to complete.
LARGE_INTEGER timeout = {(ULONG) -50000000, 0xFFFFFFFF };
waitStatus = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, &timeout); if (waitStatus == STATUS_TIMEOUT) { // Cancel the Irp we just sent.
IoCancelIrp(pIrp);
// Now wait for the Irp to be cancelled/completed below
waitStatus = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
/*
* Note - Return STATUS_IO_TIMEOUT, not STATUS_TIMEOUT. * STATUS_IO_TIMEOUT is an NT error status, STATUS_TIMEOUT is not. */ ioStatus.Status = STATUS_IO_TIMEOUT; }
// USBD maps the error code for us
NtStatus = ioStatus.Status; } } else { NtStatus = STATUS_INSUFFICIENT_RESOURCES; }
KdPrint(("Exiting SWUSB_SubmitUrb\n")); return NtStatus; }
/***********************************************************************************
** ** NTSTATUS SWUSB_GetConfigurationDescriptor(IN PDEVICE_OBJECT pDeviceObject, OUT USB_CONFIGURATION_DESCRIPTOR** ppUCD) ** ** @func Retreive the Full Configuration Descriptor from the device ** ** @rdesc STATUS_SUCCES, or various errors ** *************************************************************************************/ NTSTATUS SWUSB_GetConfigurationDescriptor ( IN PDEVICE_OBJECT pDeviceObject, // @parm [IN] Pointer to our DeviceObject
OUT USB_CONFIGURATION_DESCRIPTOR** ppUCD // @parm [OUT] Usb Configuration Descriptor (allocated here)
) { NTSTATUS NtStatus; PURB pDescriptorRequestUrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), SWFILTER_TAG); USB_CONFIGURATION_DESCRIPTOR sizingUCD;
// Null out incase of error
*ppUCD = NULL; KdPrint(("Entering SWUSB_GetConfigurationDescriptor\n")); if (pDescriptorRequestUrb == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
// Create and send a size gathering descriptor
UsbBuildGetDescriptorRequest( pDescriptorRequestUrb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 1, 0, &sizingUCD, NULL, sizeof(USB_CONFIGURATION_DESCRIPTOR), NULL ); NtStatus = SWUSB_SubmitUrb(pDeviceObject, pDescriptorRequestUrb);
if (NT_SUCCESS(NtStatus)) { // Allocate the UCD, Create and send an URB to retreive the information
*ppUCD = ExAllocatePoolWithTag(NonPagedPool, sizingUCD.wTotalLength, SWFILTER_TAG); if (*ppUCD == NULL) { NtStatus = STATUS_INSUFFICIENT_RESOURCES; } else { UsbBuildGetDescriptorRequest( pDescriptorRequestUrb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 1, 0, *ppUCD, NULL, sizingUCD.wTotalLength, NULL ); NtStatus = SWUSB_SubmitUrb(pDeviceObject, pDescriptorRequestUrb); } }
// Deallocate the URB
ExFreePool(pDescriptorRequestUrb); KdPrint(("Exiting SWUSB_GetConfigurationDescriptor\n")); return NtStatus; }
/***********************************************************************************
** ** NTSTATUS StartDeviceComplete(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, PVOID pvContext) ** ** @func StartDeviceComplete ** ** @rdesc STATUS_SUCCESS always ** *************************************************************************************/ NTSTATUS StartDeviceComplete ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, PVOID pvContext // @parm Actually a pointer to an event to signal
) { PKEVENT pNotifyEvent; UNREFERENCED_PARAMETER(pDeviceObject);
UNREFERENCED_PARAMETER(pIrp);
// Cast context to device extension
pNotifyEvent = (PKEVENT)pvContext; KeSetEvent(pNotifyEvent, IO_NO_INCREMENT, FALSE); // Done with this IRP let the system finish with it
return STATUS_MORE_PROCESSING_REQUIRED; }
/***********************************************************************************
** ** NTSTATUS SWUSB_PnP(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) ** ** @func Handles IRP_MJ_PnP ** ** @rdesc STATUS_SUCCESS, or various errors ** *************************************************************************************/ NTSTATUS SWUSB_PnP ( IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object for our context
IN PIRP pIrp // @parm IRP to handle
) { NTSTATUS NtStatus = STATUS_SUCCESS; PSWUSB_FILTER_EXT pFilterExt; PIO_STACK_LOCATION pIrpStack; PDEVICE_OBJECT *ppPrevDeviceObjectPtr; PDEVICE_OBJECT pCurDeviceObject; BOOLEAN fRemovedFromList; BOOLEAN fFoundOne;
PAGED_CODE(); //cast device extension to proper type
pFilterExt = (PSWUSB_FILTER_EXT) pDeviceObject->DeviceExtension; pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
switch (pIrpStack->MinorFunction) {
case IRP_MN_REMOVE_DEVICE: { KdPrint(("IRP_MN_REMOVE_DEVICE\n"));
// Send on the remove IRP
IoSkipCurrentIrpStackLocation (pIrp); NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
// Clean up
IoDetachDevice (pFilterExt->pTopOfStack); //Detach from top of stack
IoDeleteDevice (pDeviceObject); //Delete ourselves
// Must succeed this (???)
return STATUS_SUCCESS; }; case IRP_MN_START_DEVICE: case IRP_MN_QUERY_DEVICE_RELATIONS: case IRP_MN_QUERY_STOP_DEVICE: case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_SURPRISE_REMOVAL: case IRP_MN_STOP_DEVICE: case IRP_MN_CANCEL_STOP_DEVICE: case IRP_MN_CANCEL_REMOVE_DEVICE: case IRP_MN_QUERY_INTERFACE: case IRP_MN_QUERY_CAPABILITIES: case IRP_MN_QUERY_RESOURCES: case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: case IRP_MN_READ_CONFIG: case IRP_MN_WRITE_CONFIG: case IRP_MN_EJECT: case IRP_MN_SET_LOCK: case IRP_MN_QUERY_ID: case IRP_MN_QUERY_PNP_DEVICE_STATE: default: IoSkipCurrentIrpStackLocation (pIrp); NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp); break; } return NtStatus; }
/***********************************************************************************
** ** NTSTATUS ReportDescriptorComplete(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, PVOID pvContext) ** ** @func ReportDescriptorComplete ** ** @rdesc STATUS_SUCCESS always ** *************************************************************************************/ NTSTATUS ReportDescriptorComplete ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, PVOID pvContext // @parm Actually a pointer to an event to signal
) { PKEVENT pNotifyEvent;
UNREFERENCED_PARAMETER(pDeviceObject); UNREFERENCED_PARAMETER(pIrp);
// Cast context to device extension
pNotifyEvent = (PKEVENT)pvContext; KeSetEvent(pNotifyEvent, IO_NO_INCREMENT, FALSE); // Done with this IRP let the system finish with it
return STATUS_MORE_PROCESSING_REQUIRED; }
/***********************************************************************************
** ** NTSTATUS SelectConfigComplete(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, PVOID pvContext) ** ** @func SelectConfigComplete ** ** @rdesc STATUS_SUCCESS always ** *************************************************************************************/ NTSTATUS SelectConfigComplete ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, PVOID pvContext // @parm Actually a pointer to an event to signal
) { PKEVENT pNotifyEvent; USBD_INTERFACE_INFORMATION* pUsbInterfaceInformation; PSWUSB_FILTER_EXT pFilterExt; PURB pUrb = URB_FROM_IRP(pIrp); ULONG pipeIndex; pFilterExt = pDeviceObject->DeviceExtension; if (pIrp->IoStatus.Status == STATUS_SUCCESS) { pUsbInterfaceInformation = &(pUrb->UrbSelectConfiguration.Interface); for (pipeIndex = 0; pipeIndex < pUsbInterfaceInformation->NumberOfPipes; pipeIndex++){ if ((pUsbInterfaceInformation->Pipes[pipeIndex].EndpointAddress & USB_ENDPOINT_DIRECTION_MASK) == 0) { if (pUsbInterfaceInformation->Pipes[pipeIndex].PipeType == UsbdPipeTypeInterrupt) { pFilterExt->outputPipeInfo = pUsbInterfaceInformation->Pipes[pipeIndex]; break; } } } } //If the IRP failed somehow, make sure outputPipeInfo stays NULL
else RtlZeroMemory(&(pFilterExt->outputPipeInfo), sizeof(USBD_PIPE_INFORMATION));
// Cast context to device extension
pNotifyEvent = (PKEVENT)pvContext; KeSetEvent(pNotifyEvent, IO_NO_INCREMENT, FALSE); // Done with this IRP let the system finish with it
return STATUS_MORE_PROCESSING_REQUIRED; }
/***********************************************************************************
** ** NTSTATUS SWUSB_Ioctl_Internal(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) ** ** @func IRP_MJ_INTERNAL_IOCTL ** ** @rdesc STATUS_SUCCES, or various errors ** *************************************************************************************/ NTSTATUS SWUSB_Ioctl_Internal ( IN PDEVICE_OBJECT pDeviceObject, // @parm pointer to Device Object
IN PIRP pIrp // @parm pointer to IRP
) { NTSTATUS NtStatus; NTSTATUS NTStatus2; ULONG uIoctl; PSWUSB_FILTER_EXT pFilterExt; uIoctl = IoGetCurrentIrpStackLocation(pIrp)->Parameters.DeviceIoControl.IoControlCode; pFilterExt = (PSWUSB_FILTER_EXT)pDeviceObject->DeviceExtension;
switch (uIoctl) { case IOCTL_INTERNAL_USB_SUBMIT_URB: { PURB pUrb = URB_FROM_IRP(pIrp); //Only handle this if it's a HID descriptor request and we have a pipe handle
if (pUrb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE && pUrb->UrbControlDescriptorRequest.DescriptorType == DESCRIPTOR_TYPE_CONFIGURATION && pFilterExt->outputPipeInfo.PipeHandle != NULL) {
BYTE* pOutData = NULL; KEVENT irpCompleteEvent; PURB pInterruptUrb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), SWFILTER_TAG); KdPrint(("IOCTL_INTERNAL_USB_SUBMIT_URB\n")); if (pInterruptUrb == NULL) { pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(pIrp, IO_NO_INCREMENT); KdPrint(("IOCTL_INTERNAL_USB_SUBMIT_URB -- STATUS_INSUFFICIENT_RESOURCES\n")); return STATUS_INSUFFICIENT_RESOURCES; } pOutData = ExAllocatePoolWithTag(NonPagedPool, sizeof(BYTE)*2, SWFILTER_TAG); if (pOutData == NULL) { ExFreePool(pInterruptUrb); pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(pIrp, IO_NO_INCREMENT); KdPrint(("IOCTL_INTERNAL_USB_SUBMIT_URB (1) -- STATUS_INSUFFICIENT_RESOURCES\n")); return STATUS_INSUFFICIENT_RESOURCES; } pOutData[0] = 0x0D; pOutData[1] = 0xFF; UsbBuildInterruptOrBulkTransferRequest( pInterruptUrb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), pFilterExt->outputPipeInfo.PipeHandle, pOutData, NULL, 2, USBD_SHORT_TRANSFER_OK, NULL );
KeInitializeEvent(&irpCompleteEvent, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(pIrp); IoSetCompletionRoutine(pIrp, ReportDescriptorComplete, (PVOID)(&irpCompleteEvent), TRUE, TRUE, TRUE); NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp); if (NtStatus == STATUS_PENDING) { KeWaitForSingleObject(&irpCompleteEvent, Executive, KernelMode, FALSE, 0); } NtStatus = pIrp->IoStatus.Status;
NTStatus2 = SWUSB_SubmitUrb(pDeviceObject, pInterruptUrb); ExFreePool(pOutData); ExFreePool(pInterruptUrb); IoCompleteRequest(pIrp, IO_NO_INCREMENT); return NtStatus; } if ((pUrb->UrbHeader.Function == URB_FUNCTION_SELECT_CONFIGURATION)) { KEVENT irpCompleteEvent; KeInitializeEvent(&irpCompleteEvent, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(pIrp); IoSetCompletionRoutine(pIrp, SelectConfigComplete, (PVOID)(&irpCompleteEvent), TRUE, TRUE, TRUE); NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp); if (NtStatus == STATUS_PENDING) { KeWaitForSingleObject(&irpCompleteEvent, Executive, KernelMode, FALSE, 0); } NtStatus = pIrp->IoStatus.Status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return NtStatus; } } }
IoSkipCurrentIrpStackLocation (pIrp); NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp); return NtStatus; }
/***********************************************************************************
** ** NTSTATUS SWUSB_Power(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) ** ** @func Passes on power IRPs to lower drivers ** ** @rdesc Status from lower level driver ** *************************************************************************************/ NTSTATUS SWUSB_Power ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { NTSTATUS NtStatus; PSWUSB_FILTER_EXT pFilterExt = (PSWUSB_FILTER_EXT)pDeviceObject->DeviceExtension;
PAGED_CODE();
KdPrint(("SWUSB_Power() - Entering\n")); PoStartNextPowerIrp(pIrp); IoSkipCurrentIrpStackLocation(pIrp); NtStatus = PoCallDriver(pFilterExt->pTopOfStack, pIrp); KdPrint(("SWUSB_Power() - Exiting\n")); return NtStatus; }
/***********************************************************************************
** ** NTSTATUS SWUSB_Pass (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) ** ** @func Passes on unhandled IRPs to lower drivers DEBUG version trace out info ** Cannot be pageable since we have no idea what IRPs we're getting. ** ** @rdesc STATUS_SUCCESS, various errors ** *************************************************************************************/ NTSTATUS SWUSB_Pass ( IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object as our context
IN PIRP pIrp // @parm IRP to pass on
) { NTSTATUS NtStatus; PSWUSB_FILTER_EXT pFilterExt; KdPrint(("SWUSB_Pass() - Entering\n")); pFilterExt = (PSWUSB_FILTER_EXT)pDeviceObject->DeviceExtension; IoSkipCurrentIrpStackLocation (pIrp); NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
//return
return NtStatus; }
|