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.
3196 lines
95 KiB
3196 lines
95 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
|
|
Module Name:
|
|
|
|
usbscn9x.c
|
|
|
|
Abstract:
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <wdm.h>
|
|
#include <stdio.h>
|
|
#include <usbscan.h>
|
|
#include <usbd_api.h>
|
|
#include "private.h"
|
|
|
|
#include <initguid.h>
|
|
#include <wiaintfc.h>
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DriverEntry)
|
|
#pragma alloc_text(PAGE, USPnpAddDevice)
|
|
#pragma alloc_text(PAGE, USPnp)
|
|
#pragma alloc_text(PAGE, USCreateSymbolicLink)
|
|
#pragma alloc_text(PAGE, USDestroySymbolicLink)
|
|
#pragma alloc_text(PAGE, USGetUSBDeviceDescriptor)
|
|
#pragma alloc_text(PAGE, USConfigureDevice)
|
|
#pragma alloc_text(PAGE, USUnConfigureDevice)
|
|
#pragma alloc_text(PAGE, USUnload)
|
|
#endif
|
|
|
|
// Globals
|
|
|
|
ULONG NextDeviceInstance = 0;
|
|
|
|
#if DBG
|
|
ULONG USBSCAN_DebugTraceLevel = MIN_TRACE;
|
|
ULONG USBSCAN_PnPTest = 0;
|
|
#endif
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT pDriverObject,
|
|
IN PUNICODE_STRING pRegistryPath
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
Installable driver initialization entry point.
|
|
This is where the driver is called when the driver is being loaded
|
|
by the I/O system.
|
|
|
|
Arguments:
|
|
DriverObject - pointer to the driver object
|
|
RegistryPath - pointer to a unicode string representing the path
|
|
to driver-specific key in the registry
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
-- */
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace((MIN_TRACE | TRACE_FLAG_PROC),("DriverEntry called. Driver reg=%wZ\n",pRegistryPath));
|
|
|
|
#if DBG
|
|
MyDebugInit(pRegistryPath);
|
|
#endif // DBG
|
|
|
|
pDriverObject -> MajorFunction[IRP_MJ_READ] = USRead;
|
|
pDriverObject -> MajorFunction[IRP_MJ_WRITE] = USWrite;
|
|
pDriverObject -> MajorFunction[IRP_MJ_DEVICE_CONTROL] = USDeviceControl;
|
|
pDriverObject -> MajorFunction[IRP_MJ_CREATE] = USOpen;
|
|
pDriverObject -> MajorFunction[IRP_MJ_CLOSE] = USClose;
|
|
pDriverObject -> MajorFunction[IRP_MJ_PNP_POWER] = USPnp;
|
|
pDriverObject -> MajorFunction[IRP_MJ_FLUSH_BUFFERS] = USFlush;
|
|
pDriverObject -> MajorFunction[IRP_MJ_POWER] = USPower;
|
|
pDriverObject -> MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USPnp;
|
|
pDriverObject -> DriverExtension -> AddDevice = USPnpAddDevice;
|
|
pDriverObject -> DriverUnload = USUnload;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USPnpAddDevice(
|
|
IN PDRIVER_OBJECT pDriverObject,
|
|
IN OUT PDEVICE_OBJECT pPhysicalDeviceObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to create a new instance of the device.
|
|
|
|
Arguments:
|
|
|
|
pDriverObject - pointer to the driver object for this instance of SS
|
|
pPhysicalDeviceObject - pointer to the device object that represents the scanner
|
|
on the scsi bus.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
UCHAR aName[64];
|
|
ANSI_STRING ansiName;
|
|
UNICODE_STRING uName;
|
|
PDEVICE_OBJECT pDeviceObject = NULL;
|
|
NTSTATUS Status;
|
|
PUSBSCAN_DEVICE_EXTENSION pde;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USPnpAddDevice: Enter..\n"));
|
|
|
|
//
|
|
// Create the Functional Device Object (FDO) for this device.
|
|
//
|
|
|
|
sprintf(aName,"\\Device\\Usbscan%d",NextDeviceInstance);
|
|
RtlInitAnsiString(&ansiName, aName);
|
|
|
|
//
|
|
// Show device object name.
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS,("USPnpAddDevice: Create device object %s\n", aName));
|
|
|
|
//
|
|
// Allocates Unicode string.
|
|
//
|
|
|
|
Status = RtlAnsiStringToUnicodeString(&uName, &ansiName, TRUE);
|
|
if(STATUS_SUCCESS != Status){
|
|
DebugTrace(TRACE_CRITICAL,("USPnpAddDevice: ERROR!! Can't alloc buffer for Unicode\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USPnpAddDevice_return;
|
|
}
|
|
|
|
//
|
|
// Create device object for this scanner.
|
|
//
|
|
|
|
Status = IoCreateDevice(pDriverObject,
|
|
sizeof(USBSCAN_DEVICE_EXTENSION),
|
|
&uName,
|
|
FILE_DEVICE_SCANNER,
|
|
0,
|
|
FALSE,
|
|
&pDeviceObject);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DebugTrace(TRACE_ERROR,("USPnpAddDevice: ERROR!! Can't create device object\n"));
|
|
DEBUG_BREAKPOINT();
|
|
goto USPnpAddDevice_return;
|
|
}
|
|
|
|
//
|
|
// Device object was successfully created.
|
|
// Free Unicode string used for device creation.
|
|
//
|
|
|
|
RtlFreeUnicodeString(&uName);
|
|
uName.Buffer = NULL;
|
|
|
|
//
|
|
// Initialize Device Extension.
|
|
//
|
|
|
|
pde = (PUSBSCAN_DEVICE_EXTENSION)(pDeviceObject -> DeviceExtension);
|
|
RtlZeroMemory(pde, sizeof(USBSCAN_DEVICE_EXTENSION));
|
|
|
|
//
|
|
// Save own device object.
|
|
//
|
|
|
|
pde -> pOwnDeviceObject = pDeviceObject;
|
|
|
|
//
|
|
// Initialize PendingIoEvent. Set the number of pending i/o requests for this device to 1.
|
|
// When this number falls to zero, it is okay to remove, or stop the device.
|
|
//
|
|
|
|
pde -> PendingIoCount = 0;
|
|
pde -> Stopped = FALSE;
|
|
KeInitializeEvent(&pde -> PendingIoEvent, NotificationEvent, FALSE);
|
|
|
|
//
|
|
// Indicate that IRPs should include MDLs.
|
|
//
|
|
|
|
pDeviceObject->Flags |= DO_DIRECT_IO;
|
|
|
|
//
|
|
// indicate our power code is pagable
|
|
//
|
|
|
|
pDeviceObject->Flags |= DO_POWER_PAGABLE;
|
|
|
|
//
|
|
// Attach our new FDO to the PDO (Physical Device Object).
|
|
//
|
|
|
|
pde -> pStackDeviceObject = IoAttachDeviceToDeviceStack(pDeviceObject,
|
|
pPhysicalDeviceObject);
|
|
if (NULL == pde -> pStackDeviceObject) {
|
|
DebugTrace(TRACE_ERROR,("USPnpAddDevice: ERROR!! Cannot attach FDO to PDO.\n"));
|
|
DEBUG_BREAKPOINT();
|
|
IoDeleteDevice( pDeviceObject );
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
goto USPnpAddDevice_return;
|
|
}
|
|
|
|
//
|
|
// Remember the PDO in our device extension.
|
|
//
|
|
|
|
pde -> pPhysicalDeviceObject = pPhysicalDeviceObject;
|
|
|
|
//
|
|
// Remember the DeviceInstance number.
|
|
//
|
|
|
|
pde -> DeviceInstance = NextDeviceInstance;
|
|
|
|
//
|
|
// Handle exporting interface
|
|
//
|
|
|
|
Status = UsbScanHandleInterface(
|
|
pPhysicalDeviceObject,
|
|
&pde->InterfaceNameString,
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// Each time AddDevice gets called, we advance the global DeviceInstance variable.
|
|
//
|
|
|
|
NextDeviceInstance++;
|
|
|
|
//
|
|
// Set initial device power state as online.
|
|
//
|
|
|
|
pde -> CurrentDevicePowerState = PowerDeviceD0;
|
|
|
|
//
|
|
// Initialize spinlock.
|
|
//
|
|
|
|
KeInitializeSpinLock(&pde->SpinLock);
|
|
|
|
//
|
|
// Initialize wake state.
|
|
//
|
|
|
|
USInitializeWakeState(pde);
|
|
|
|
//
|
|
// Will see device capability on START_DEVICE.
|
|
//
|
|
|
|
pde -> bEnabledForWakeup = FALSE;
|
|
|
|
//
|
|
// Finish initializing.
|
|
//
|
|
|
|
pDeviceObject -> Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
USPnpAddDevice_return:
|
|
|
|
if(NULL != uName.Buffer){
|
|
RtlFreeUnicodeString(&uName);
|
|
}
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USPnpAddDevice: Leaving.. Status = 0x%x\n", Status));
|
|
return Status;
|
|
|
|
} // end USAddDevice()
|
|
|
|
|
|
NTSTATUS USPnp(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles all PNP irps.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject - represents a scanner device
|
|
pIrp - PNP irp
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PUSBSCAN_DEVICE_EXTENSION pde;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
KEVENT event;
|
|
PDEVICE_CAPABILITIES pCaps;
|
|
LONG bTemp;
|
|
POWER_STATE PowerState;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USPnp: Enter..\n"));
|
|
|
|
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
|
|
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
|
|
|
|
Status = pIrp -> IoStatus.Status;
|
|
|
|
// DbgPrint("USPnP: Major=0x%x, Minor=0x%x\n",
|
|
// pIrpStack -> MajorFunction,
|
|
// pIrpStack->MinorFunction);
|
|
|
|
switch (pIrpStack -> MajorFunction) {
|
|
|
|
case IRP_MJ_SYSTEM_CONTROL:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MJ_SYSTEM_CONTROL\n"));
|
|
|
|
//
|
|
// Simply passing down the IRP.
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS,("USPnp: Simply passing down the IRP\n"));
|
|
|
|
IoCopyCurrentIrpStackLocationToNext( pIrp );
|
|
Status = IoCallDriver(pde -> pStackDeviceObject, pIrp);
|
|
break;
|
|
|
|
case IRP_MJ_PNP:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MJ_PNP\n"));
|
|
switch (pIrpStack->MinorFunction) {
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MJ_QUERY_CAPS\n"));
|
|
|
|
//
|
|
// Call downlevel driver first to fill capabilities structure
|
|
// Then add our specific capabilities
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS,("USPnp: Call down to get capabilities\n"));
|
|
|
|
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
Status = USCallNextDriverSynch(pde, pIrp);
|
|
|
|
if(!NT_SUCCESS(Status)){
|
|
DebugTrace(TRACE_ERROR,("USPnp: ERROR!! Call down failed. Status=0x%x\n", Status));
|
|
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
|
|
goto USPnP_return;
|
|
}
|
|
|
|
//
|
|
// Set SurpriseRemoval OK
|
|
//
|
|
|
|
pCaps = pIrpStack -> Parameters.DeviceCapabilities.Capabilities;
|
|
pCaps->SurpriseRemovalOK = TRUE;
|
|
pCaps->Removable = TRUE;
|
|
|
|
//
|
|
// Setup remote wakeup state.
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS,("USPnp: DeviceState[PowerSystemUnspecified]=0x%x.\n",pCaps->DeviceState[PowerSystemUnspecified]));
|
|
DebugTrace(TRACE_STATUS,("USPnp: DeviceState[PowerSystemWorking] =0x%x.\n",pCaps->DeviceState[PowerSystemWorking]));
|
|
DebugTrace(TRACE_STATUS,("USPnp: DeviceState[PowerSystemSleeping1] =0x%x.\n",pCaps->DeviceState[PowerSystemSleeping1]));
|
|
DebugTrace(TRACE_STATUS,("USPnp: DeviceState[PowerSystemSleeping2] =0x%x.\n",pCaps->DeviceState[PowerSystemSleeping2]));
|
|
DebugTrace(TRACE_STATUS,("USPnp: DeviceState[PowerSystemSleeping3] =0x%x.\n",pCaps->DeviceState[PowerSystemSleeping3]));
|
|
DebugTrace(TRACE_STATUS,("USPnp: DeviceState[PowerSystemHibernate] =0x%x.\n",pCaps->DeviceState[PowerSystemHibernate]));
|
|
DebugTrace(TRACE_STATUS,("USPnp: DeviceState[PowerSystemShutdown] =0x%x.\n",pCaps->DeviceState[PowerSystemShutdown]));
|
|
DebugTrace(TRACE_STATUS,("USPnp: DeviceState[PowerSystemMaximum] =0x%x.\n",pCaps->DeviceState[PowerSystemMaximum]));
|
|
|
|
DebugTrace(TRACE_STATUS,("USPnp: Lower stack set DeviceWake(0x%x) SystemWake(0x%x)\n.", pCaps->DeviceWake, pCaps->SystemWake));
|
|
|
|
//
|
|
// Set returning status.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
pIrp -> IoStatus.Status = Status;
|
|
pIrp -> IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
|
|
goto USPnP_return;
|
|
|
|
break;
|
|
|
|
|
|
case IRP_MN_START_DEVICE:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MJ_START_DEVICE\n"));
|
|
|
|
pde -> Stopped = FALSE;
|
|
USIncrementIoCount(pDeviceObject);
|
|
|
|
//
|
|
// First, let the port driver start the device.
|
|
//
|
|
|
|
Status = USCallNextDriverSynch(pde, pIrp);
|
|
if(!NT_SUCCESS(Status)){
|
|
|
|
//
|
|
// Lower layer failed to start device.
|
|
//
|
|
|
|
DebugTrace(TRACE_ERROR,("USPnp: ERROR!! Lower layer failed to start device. Status=0x%x\n", Status));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The port driver has started the device. It is time for
|
|
// us to do some initialization and create symbolic links
|
|
// for the device.
|
|
//
|
|
// Get the device descriptor and save it in our
|
|
// device extension.
|
|
//
|
|
|
|
Status = USGetUSBDeviceDescriptor(pDeviceObject);
|
|
if(!NT_SUCCESS(Status)){
|
|
|
|
//
|
|
// GetDescriptor failed.
|
|
//
|
|
|
|
DebugTrace(TRACE_ERROR,("USPnp: ERROR!! Cannot get DeviceDescriptor.\n"));
|
|
DEBUG_BREAKPOINT();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Configure the device.
|
|
//
|
|
|
|
Status = USConfigureDevice(pDeviceObject);
|
|
#if DBG
|
|
//DEBUG_BREAKPOINT();
|
|
if (USBSCAN_PnPTest) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
#endif
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DebugTrace(TRACE_ERROR,("USPnp: ERROR!! Can't configure the device.\n"));
|
|
DEBUG_BREAKPOINT();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create the symbolic link for this device.
|
|
//
|
|
|
|
Status = USCreateSymbolicLink( pde );
|
|
#if DBG
|
|
//DEBUG_BREAKPOINT();
|
|
if (USBSCAN_PnPTest) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
#endif
|
|
if (!NT_SUCCESS(Status)) {
|
|
DebugTrace(TRACE_ERROR, ("USPnp: ERROR!! Can't create symbolic link.\n"));
|
|
DEBUG_BREAKPOINT();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Initialize the synchronize read event. This event is used the serialze
|
|
// i/o requests to the read pipe if the request size is NOT a usb packet multiple.
|
|
//
|
|
|
|
{
|
|
ULONG i;
|
|
for(i = 0; i < pde->NumberOfPipes; i++){
|
|
if( (pde->PipeInfo[i].PipeType == UsbdPipeTypeBulk)
|
|
&& (pde->PipeInfo[i].EndpointAddress & BULKIN_FLAG) )
|
|
{
|
|
DebugTrace(TRACE_STATUS,("USPnp: Initializing event for Pipe[%d]\n", i));
|
|
KeInitializeEvent(&pde -> ReadPipeBuffer[i].ReadSyncEvent, SynchronizationEvent, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Get device capability.
|
|
//
|
|
|
|
Status = USGetDeviceCapability(pde);
|
|
if(!NT_SUCCESS(Status)){
|
|
DebugTrace(TRACE_ERROR, ("USPnp: ERROR!! Unable to get Capability of this device. Status=0x%x.\n", Status));
|
|
break;
|
|
} // if(!NT_SUCCESS(Status))
|
|
|
|
//
|
|
// Arm for wake if device is capable.
|
|
//
|
|
|
|
if(TRUE == pde->bEnabledForWakeup){
|
|
PowerState.SystemState = pde -> DeviceCapabilities.SystemWake;
|
|
USArmForWake(pde, PowerState);
|
|
} // if(TRUE == pde->bEnabledForWakeup)
|
|
|
|
//
|
|
// Indicate device is now ready.
|
|
//
|
|
|
|
pde -> AcceptingRequests = TRUE;
|
|
|
|
//
|
|
// Set return status.
|
|
//
|
|
|
|
pIrp -> IoStatus.Status = Status;
|
|
pIrp -> IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
|
|
goto USPnP_return;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_REMOVE_DEVICE\n"));
|
|
|
|
//
|
|
// Prohivit further request.
|
|
//
|
|
|
|
bTemp = (LONG)InterlockedExchange((PULONG)&(pde -> AcceptingRequests),
|
|
(LONG)FALSE );
|
|
|
|
//
|
|
// Wait for any io requests pending in our driver to
|
|
// complete before proceeding the remove.
|
|
//
|
|
|
|
if (!pde -> Stopped ) {
|
|
USDecrementIoCount(pDeviceObject);
|
|
}
|
|
|
|
//
|
|
// Disarm remote wakeup.
|
|
//
|
|
|
|
USDisarmWake(pde);
|
|
|
|
KeWaitForSingleObject(&pde -> PendingIoEvent,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,NULL);
|
|
|
|
//
|
|
// Is this device stopped/removed before?
|
|
//
|
|
|
|
if (bTemp) {
|
|
|
|
//
|
|
// Delete symbolic link.
|
|
//
|
|
|
|
USDestroySymbolicLink( pde );
|
|
|
|
//
|
|
// Abort all pipes.
|
|
//
|
|
|
|
USCancelPipe(pDeviceObject, NULL, ALL_PIPE, TRUE);
|
|
}
|
|
|
|
//
|
|
// Disable device interface.
|
|
//
|
|
|
|
UsbScanHandleInterface(pde->pPhysicalDeviceObject,
|
|
&pde->InterfaceNameString,
|
|
FALSE);
|
|
|
|
//
|
|
// Forward remove message to lower driver.
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(pIrp);
|
|
Status = IoCallDriver(pde -> pStackDeviceObject, pIrp);
|
|
|
|
//
|
|
// Free allocated memory.
|
|
//
|
|
|
|
if (pde -> pDeviceDescriptor) {
|
|
USFreePool(pde -> pDeviceDescriptor);
|
|
pde -> pDeviceDescriptor = NULL;
|
|
}
|
|
|
|
if (pde -> pConfigurationDescriptor) {
|
|
USFreePool(pde -> pConfigurationDescriptor);
|
|
pde -> pConfigurationDescriptor = NULL;
|
|
}
|
|
|
|
//
|
|
// Free allocated buffer(s)
|
|
//
|
|
{
|
|
ULONG i;
|
|
for(i = 0; i < pde->NumberOfPipes; i++){
|
|
if(pde->ReadPipeBuffer[i].pStartBuffer){
|
|
USFreePool(pde->ReadPipeBuffer[i].pStartBuffer);
|
|
pde->ReadPipeBuffer[i].pStartBuffer = NULL;
|
|
pde->ReadPipeBuffer[i].pBuffer = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Detatch device object from stack.
|
|
//
|
|
|
|
IoDetachDevice(pde -> pStackDeviceObject);
|
|
|
|
//
|
|
// Delete device object
|
|
//
|
|
|
|
IoDeleteDevice (pDeviceObject);
|
|
pDeviceObject = NULL;
|
|
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_REMOVE_DEVICE complete\n"));
|
|
goto USPnP_return;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_STOP_DEVICE\n"));
|
|
|
|
//
|
|
// Indicate device is stopped.
|
|
//
|
|
|
|
pde -> Stopped = TRUE;
|
|
|
|
if (pde -> AcceptingRequests) {
|
|
|
|
//
|
|
// Disarm remote wakeup.
|
|
//
|
|
|
|
USDisarmWake(pde);
|
|
|
|
//
|
|
// No more requests are allowed.
|
|
//
|
|
|
|
pde -> AcceptingRequests = FALSE;
|
|
|
|
//
|
|
// Delete symbolic link.
|
|
//
|
|
|
|
USDestroySymbolicLink( pde );
|
|
|
|
//
|
|
// Abort all pipes.
|
|
//
|
|
|
|
USCancelPipe(pDeviceObject, NULL, ALL_PIPE, TRUE);
|
|
|
|
//
|
|
// Set device into unconfigured state.
|
|
//
|
|
|
|
USUnConfigureDevice(pDeviceObject);
|
|
|
|
} //(pde -> AcceptingRequests)
|
|
|
|
#ifndef _CHICAGO_
|
|
//
|
|
// Disable device interface.
|
|
//
|
|
|
|
if (pde->InterfaceNameString.Buffer != NULL) {
|
|
IoSetDeviceInterfaceState(&pde->InterfaceNameString,FALSE);
|
|
}
|
|
#endif // _CHICAGO_
|
|
|
|
//
|
|
// Let the port driver stop the device.
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(pIrp);
|
|
Status = IoCallDriver(pde -> pStackDeviceObject, pIrp);
|
|
|
|
//
|
|
// wait for any io requests pending in our driver to
|
|
// complete before finishing the remove
|
|
//
|
|
|
|
USDecrementIoCount(pDeviceObject);
|
|
KeWaitForSingleObject(&pde -> PendingIoEvent, Suspended, KernelMode,
|
|
FALSE,NULL);
|
|
|
|
ASSERT(pde -> pDeviceDescriptor);
|
|
ASSERT(pde -> pConfigurationDescriptor);
|
|
|
|
if (pde -> pDeviceDescriptor) {
|
|
USFreePool(pde -> pDeviceDescriptor);
|
|
pde -> pDeviceDescriptor = NULL;
|
|
}
|
|
|
|
if (pde -> pConfigurationDescriptor) {
|
|
USFreePool(pde -> pConfigurationDescriptor);
|
|
pde -> pConfigurationDescriptor = NULL;
|
|
}
|
|
|
|
//
|
|
// Free allocated buffer(s)
|
|
//
|
|
{
|
|
ULONG i;
|
|
for(i = 0; i < pde->NumberOfPipes; i++){
|
|
if(pde->ReadPipeBuffer[i].pBuffer){
|
|
USFreePool(pde->ReadPipeBuffer[i].pBuffer);
|
|
pde->ReadPipeBuffer[i].pBuffer = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
goto USPnP_return;
|
|
|
|
case IRP_MN_QUERY_INTERFACE:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_QUERY_INTERFACE\n"));
|
|
break;
|
|
|
|
case IRP_MN_QUERY_RESOURCES:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_QUERY_RESOURCES\n"));
|
|
break;
|
|
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"));
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_TEXT:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_QUERY_DEVICE_TEXT\n"));
|
|
break;
|
|
|
|
// case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
|
|
// DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_QUERY_LEGACY_BUS_INFORMATION\n"));
|
|
// break;
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_QUERY_STOP_DEVICE\n"));
|
|
break;
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_QUERY_REMOVE_DEVICE\n"));
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_CANCEL_STOP_DEVICE\n"));
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_CANCEL_REMOVE_DEVICE\n"));
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_QUERY_DEVICE_RELATIONS\n"));
|
|
break;
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
DebugTrace(TRACE_STATUS,("USPnp: IRP_MN_SURPRISE_REMOVAL\n"));
|
|
|
|
//
|
|
// Indicate interface is stopped
|
|
//
|
|
|
|
UsbScanHandleInterface(pde->pPhysicalDeviceObject,
|
|
&pde->InterfaceNameString,
|
|
FALSE);
|
|
|
|
break;
|
|
|
|
default:
|
|
DebugTrace(TRACE_STATUS,("USPnp: Minor PNP message. MinorFunction = 0x%x\n",pIrpStack->MinorFunction));
|
|
break;
|
|
|
|
} /* case MinorFunction, MajorFunction == IRP_MJ_PNP_POWER */
|
|
|
|
//
|
|
// Passing down IRP
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(pIrp);
|
|
Status = IoCallDriver(pde -> pStackDeviceObject, pIrp);
|
|
|
|
DebugTrace(TRACE_STATUS,("USPnp: Passed Pnp Irp down, status = %x\n", Status));
|
|
|
|
if(!NT_SUCCESS(Status)){
|
|
DebugTrace(TRACE_WARNING,("USPnp: WARNING!! IRP Status failed, status = %x\n", Status));
|
|
// DEBUG_BREAKPOINT();
|
|
}
|
|
break; // IRP_MJ_PNP
|
|
|
|
default:
|
|
DebugTrace(TRACE_STATUS,("USPnp: Major PNP IOCTL not handled\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
pIrp -> IoStatus.Status = Status;
|
|
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
|
|
goto USPnP_return;
|
|
|
|
} /* case MajorFunction */
|
|
|
|
|
|
USPnP_return:
|
|
DebugTrace(TRACE_PROC_LEAVE,("USPnP: Leaving.. Status = 0x%x\n", Status));
|
|
return Status;
|
|
|
|
} // end USPnp()
|
|
|
|
|
|
|
|
NTSTATUS
|
|
USCreateSymbolicLink(
|
|
PUSBSCAN_DEVICE_EXTENSION pde
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine create the symbolic link for the device.
|
|
|
|
Arguments:
|
|
pde - pointer to device extension
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING uName;
|
|
UNICODE_STRING uName2;
|
|
ANSI_STRING ansiName;
|
|
CHAR aName[32];
|
|
HANDLE hSwKey;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USCreateSymbolicLink: Enter..\n"));
|
|
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
RtlZeroMemory(&uName, sizeof(UNICODE_STRING));
|
|
RtlZeroMemory(&uName2, sizeof(UNICODE_STRING));
|
|
RtlZeroMemory(&ansiName, sizeof(ANSI_STRING));
|
|
hSwKey = NULL;
|
|
|
|
|
|
//
|
|
// Create the symbolic link for this device.
|
|
//
|
|
|
|
sprintf(aName,"\\Device\\Usbscan%d",pde -> DeviceInstance);
|
|
RtlInitAnsiString(&ansiName, aName);
|
|
|
|
Status = RtlAnsiStringToUnicodeString(&uName, &ansiName, TRUE);
|
|
if(STATUS_SUCCESS != Status){
|
|
DebugTrace(TRACE_CRITICAL,("USCreateSymbolicLink: ERROR!! Cannot allocate buffer for Unicode srting\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USCreateSymbolicLink_return;
|
|
}
|
|
|
|
sprintf(aName,"\\DosDevices\\Usbscan%d",pde -> DeviceInstance);
|
|
RtlInitAnsiString(&ansiName, aName);
|
|
|
|
Status = RtlAnsiStringToUnicodeString(&(pde -> SymbolicLinkName), &ansiName, TRUE);
|
|
if(STATUS_SUCCESS != Status){
|
|
DebugTrace(TRACE_CRITICAL,("USCreateSymbolicLink: ERROR!! Cannot allocate buffer for Unicode srting\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USCreateSymbolicLink_return;
|
|
}
|
|
|
|
//
|
|
// Create Sympolic link.
|
|
//
|
|
|
|
Status = IoCreateSymbolicLink( &(pde -> SymbolicLinkName), &uName );
|
|
|
|
RtlFreeUnicodeString( &uName );
|
|
uName.Buffer = NULL;
|
|
|
|
if (STATUS_SUCCESS != Status ) {
|
|
DebugTrace(TRACE_ERROR,("USCreateSymbolicLink: ERROR!! Cannot create symbolic link.\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
goto USCreateSymbolicLink_return;
|
|
}
|
|
|
|
//
|
|
// Now, stuff the symbolic link into the CreateFileName key so that STI can find the device.
|
|
//
|
|
|
|
IoOpenDeviceRegistryKey( pde -> pPhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DRIVER, KEY_WRITE, &hSwKey);
|
|
|
|
//
|
|
// Create CreateFile name. ("\\.\UsbscanX")
|
|
//
|
|
|
|
RtlInitUnicodeString(&uName,USBSCAN_REG_CREATEFILE); // L"CreateFileName"
|
|
sprintf(aName, "%s%d", USBSCAN_OBJECTNAME_A, pde -> DeviceInstance); // "\\\\.\\Usbscan%d"
|
|
RtlInitAnsiString(&ansiName, aName);
|
|
Status = RtlAnsiStringToUnicodeString(&uName2, &ansiName, TRUE);
|
|
if(STATUS_SUCCESS != Status){
|
|
DebugTrace(TRACE_CRITICAL,("USCreateSymbolicLink: ERROR!! Cannot allocate buffer for Unicode srting\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USCreateSymbolicLink_return;
|
|
}
|
|
|
|
//
|
|
// Set CreateFile name to the registry.
|
|
//
|
|
|
|
ZwSetValueKey(hSwKey,&uName,0,REG_SZ,uName2.Buffer,uName2.Length);
|
|
|
|
//
|
|
// uName is not allocated. Just zero it.
|
|
//
|
|
|
|
RtlZeroMemory(&uName, sizeof(UNICODE_STRING));
|
|
|
|
USCreateSymbolicLink_return:
|
|
|
|
if(NULL != hSwKey){
|
|
ZwClose(hSwKey);
|
|
}
|
|
|
|
if(NULL != uName.Buffer){
|
|
RtlFreeUnicodeString( &uName );
|
|
}
|
|
|
|
if(NULL != uName2.Buffer){
|
|
RtlFreeUnicodeString( &uName2 );
|
|
}
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USCreateSymbolicLink: Leaving.. Status = 0x%x\n", Status));
|
|
return Status;
|
|
|
|
} // end USCreateSymbolicLink()
|
|
|
|
|
|
NTSTATUS
|
|
USDestroySymbolicLink(
|
|
PUSBSCAN_DEVICE_EXTENSION pde
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine removes the symbolic link for the device.
|
|
|
|
Arguments:
|
|
pde - pointer to device extension
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING uName;
|
|
UNICODE_STRING uName2;
|
|
UNICODE_STRING uNumber;
|
|
ANSI_STRING ansiName;
|
|
CHAR aName[32];
|
|
HANDLE hSwKey;
|
|
WCHAR wsCreateFileName[64];
|
|
ULONG ulBufLength, ulRetLength;
|
|
NTSTATUS Status;
|
|
PVOID pvNumber;
|
|
ULONG ulNumber;
|
|
const WCHAR wcsObjectName[] = USBSCAN_OBJECTNAME_W; // L"\\\\.\\Usbscan"
|
|
ULONG uiObjectNameLen = wcslen(wcsObjectName) * sizeof(WCHAR) ;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USDestroySymbolicLink: Enter..\n"));
|
|
|
|
//
|
|
// Delete the symbolic link to this device.
|
|
//
|
|
|
|
IoDeleteSymbolicLink( &(pde -> SymbolicLinkName) );
|
|
|
|
//
|
|
// Remove the CreateFile name from the s/w key, if it's created by this device object.
|
|
//
|
|
|
|
Status = IoOpenDeviceRegistryKey( pde -> pPhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DRIVER,
|
|
KEY_ALL_ACCESS,
|
|
&hSwKey);
|
|
if(STATUS_SUCCESS != Status){
|
|
DebugTrace(TRACE_ERROR,("USDestroySymbolicLink: ERROR!! IoOpenDeviceRegistryKey Failed\n"));
|
|
DEBUG_BREAKPOINT();
|
|
goto USDestroySymbolicLink_return;
|
|
}
|
|
|
|
RtlInitUnicodeString(&uName,USBSCAN_REG_CREATEFILE); // L"CreateFileName"
|
|
memset(aName, 0, sizeof(aName));
|
|
RtlInitAnsiString(&ansiName, aName);
|
|
Status = RtlAnsiStringToUnicodeString(&uName2, &ansiName, TRUE);
|
|
if(STATUS_SUCCESS != Status){
|
|
DebugTrace(TRACE_CRITICAL,("USDestroySymbolicLink: ERROR!! Cannot allocate buffer for Unicode srting\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USDestroySymbolicLink_return;
|
|
}
|
|
|
|
//
|
|
// Check if this CreateFile name is created by this device object.
|
|
//
|
|
|
|
//
|
|
// Query CreateFile name from the registry.
|
|
//
|
|
|
|
ulBufLength = sizeof(wsCreateFileName);
|
|
Status = ZwQueryValueKey(hSwKey,
|
|
&uName,
|
|
KeyValuePartialInformation,
|
|
(PVOID)wsCreateFileName,
|
|
ulBufLength,
|
|
&ulRetLength);
|
|
if(STATUS_SUCCESS != Status){
|
|
DebugTrace(TRACE_ERROR,("USDestroySymbolicLink: ERROR!! Cannot query registry.\n"));
|
|
RtlFreeUnicodeString( &uName2 );
|
|
uName2.Buffer = NULL;
|
|
goto USDestroySymbolicLink_return;
|
|
}
|
|
|
|
if (NULL != wsCreateFileName){
|
|
DebugTrace(TRACE_STATUS,("USDestroySymbolicLink: CreateFileName=%ws, DeviceInstance=%d.\n",
|
|
((PKEY_VALUE_PARTIAL_INFORMATION)wsCreateFileName)->Data,
|
|
pde -> DeviceInstance));
|
|
|
|
//
|
|
// Get instance number of CreteFile name.
|
|
//
|
|
|
|
pvNumber = wcsstr((const wchar_t *)((PKEY_VALUE_PARTIAL_INFORMATION)wsCreateFileName)->Data, wcsObjectName);
|
|
if(NULL != pvNumber){
|
|
|
|
//
|
|
// Move pointer forward. (sizeof(L"\\\\.\\Usbscan") == 22)
|
|
//
|
|
|
|
// if( ((PKEY_VALUE_PARTIAL_INFORMATION)wsCreateFileName)->DataLength > sizeof(wcsObjectName) ){
|
|
// (PCHAR)pvNumber += sizeof(wcsObjectName);
|
|
|
|
if( ((PKEY_VALUE_PARTIAL_INFORMATION)wsCreateFileName)->DataLength > uiObjectNameLen ){
|
|
(PCHAR)pvNumber += uiObjectNameLen;
|
|
} else {
|
|
DebugTrace(TRACE_ERROR,("USDestroySymbolicLink: ERROR!! CreateFile name too short.\n"));
|
|
RtlFreeUnicodeString( &uName2 );
|
|
uName2.Buffer = NULL;
|
|
ZwClose(hSwKey);
|
|
goto USDestroySymbolicLink_return;
|
|
}
|
|
|
|
//
|
|
// Translate X of UsbscanX to integer.
|
|
//
|
|
|
|
RtlInitUnicodeString(&uNumber, pvNumber);
|
|
Status = RtlUnicodeStringToInteger(&uNumber,
|
|
10,
|
|
&ulNumber);
|
|
if(STATUS_SUCCESS != Status){
|
|
DebugTrace(TRACE_ERROR,("USDestroySymbolicLink: ERROR!! RtlUnicodeStringToInteger failed.\n"));
|
|
RtlFreeUnicodeString( &uName2 );
|
|
uName2.Buffer = NULL;
|
|
ZwClose(hSwKey);
|
|
goto USDestroySymbolicLink_return;
|
|
}
|
|
|
|
//
|
|
// See if this CreateFile name is made by this instance.
|
|
//
|
|
|
|
if(ulNumber == pde -> DeviceInstance){
|
|
|
|
//
|
|
// Delete CreateFile name in the registry.
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS,("USDestroySymbolicLink: Deleting %ws%d\n",
|
|
wcsObjectName,
|
|
ulNumber));
|
|
ZwSetValueKey(hSwKey,&uName,0,REG_SZ,uName2.Buffer,uName2.Length);
|
|
} else {
|
|
|
|
//
|
|
// CreateFile name is created by other instance.
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS,("USDestroySymbolicLink: CreateFile name is created by other instance.\n"));
|
|
}
|
|
} else { // (NULL != pvNumber)
|
|
|
|
//
|
|
// "Usbscan" was not found in CreateFile name.
|
|
//
|
|
|
|
DebugTrace(TRACE_WARNING,("USDestroySymbolicLink: WARNING!! Didn't find \"Usbscan\" in CreateFileName\n"));
|
|
}
|
|
} else { // (NULL != wsCreateFileName)
|
|
|
|
//
|
|
// Query CreateFile name returned NULL.
|
|
//
|
|
|
|
DebugTrace(TRACE_WARNING,("USDestroySymbolicLink: WARNING!! CreateFileName=NULL\n"));
|
|
}
|
|
|
|
//
|
|
// Free allocated memory.
|
|
//
|
|
|
|
RtlFreeUnicodeString( &uName2 );
|
|
|
|
//
|
|
// Close registry.
|
|
//
|
|
|
|
ZwClose(hSwKey);
|
|
|
|
|
|
USDestroySymbolicLink_return:
|
|
|
|
//
|
|
// Free allocated string buffer in DeviceObject.
|
|
//
|
|
|
|
RtlFreeUnicodeString( &(pde -> SymbolicLinkName) );
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USDestroySymbolicLink: Leaving.. Status = 0x%x\n",Status));
|
|
return Status;
|
|
|
|
} // end USDestroySymbolicLink()
|
|
|
|
|
|
NTSTATUS
|
|
USGetUSBDeviceDescriptor(
|
|
IN PDEVICE_OBJECT pDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Retrieves the USB device descriptor and stores it in the device
|
|
extension. This descriptor contains product info and
|
|
endpoint 0 (default pipe) info.
|
|
|
|
Arguments:
|
|
pDeviceObject - pointer to device object
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
PUSBSCAN_DEVICE_EXTENSION pde;
|
|
NTSTATUS Status;
|
|
PUSB_DEVICE_DESCRIPTOR pDeviceDescriptor;
|
|
PURB pUrb;
|
|
ULONG siz;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USGetUSBDeviceDescriptor: Enter..\n"));
|
|
|
|
pde = pDeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Allocate pool for URB.
|
|
//
|
|
|
|
pUrb = USAllocatePool(NonPagedPool,
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
|
|
if (NULL == pUrb) {
|
|
DebugTrace(TRACE_CRITICAL,("USGetUSBDeviceDescriptor: ERROR!! cannot allocated URB\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USGetUSBDeviceDescriptor_return;
|
|
}
|
|
|
|
//
|
|
// Allocate pool for Descriptor.
|
|
//
|
|
|
|
siz = sizeof(USB_DEVICE_DESCRIPTOR);
|
|
pDeviceDescriptor = USAllocatePool(NonPagedPool, siz);
|
|
|
|
if (NULL == pDeviceDescriptor) {
|
|
DebugTrace(TRACE_CRITICAL,("USGetUSBDeviceDescriptor: ERROR!! cannot allocated device descriptor\n"));
|
|
DEBUG_BREAKPOINT();
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USGetUSBDeviceDescriptor_return;
|
|
}
|
|
|
|
//
|
|
// Do Macro to set parameter for GetDescriptor to URB.
|
|
//
|
|
|
|
UsbBuildGetDescriptorRequest(pUrb,
|
|
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
USB_DEVICE_DESCRIPTOR_TYPE,
|
|
0,
|
|
0,
|
|
pDeviceDescriptor,
|
|
NULL,
|
|
siz,
|
|
NULL);
|
|
|
|
//
|
|
// Call down.
|
|
//
|
|
|
|
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
|
|
|
|
#if DBG
|
|
//DEBUG_BREAKPOINT();
|
|
if (USBSCAN_PnPTest) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
#endif
|
|
|
|
if (STATUS_SUCCESS == Status) {
|
|
|
|
//
|
|
// Show device descriptor.
|
|
//
|
|
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: Device Descriptor = %x, len %x\n",
|
|
pDeviceDescriptor,
|
|
pUrb->UrbControlDescriptorRequest.TransferBufferLength));
|
|
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: USBSCAN Device Descriptor:\n"));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: -------------------------\n"));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: bLength %d\n", pDeviceDescriptor -> bLength));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: bDescriptorType 0x%x\n", pDeviceDescriptor -> bDescriptorType));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: bcdUSB 0x%x\n", pDeviceDescriptor -> bcdUSB));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: bDeviceClass 0x%x\n", pDeviceDescriptor -> bDeviceClass));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: bDeviceSubClass 0x%x\n", pDeviceDescriptor -> bDeviceSubClass));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: bDeviceProtocol 0x%x\n", pDeviceDescriptor -> bDeviceProtocol));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: bMaxPacketSize0 0x%x\n", pDeviceDescriptor -> bMaxPacketSize0));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: idVendor 0x%x\n", pDeviceDescriptor -> idVendor));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: idProduct 0x%x\n", pDeviceDescriptor -> idProduct));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: bcdDevice 0x%x\n", pDeviceDescriptor -> bcdDevice));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: iManufacturer 0x%x\n", pDeviceDescriptor -> iManufacturer));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: iProduct 0x%x\n", pDeviceDescriptor -> iProduct));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: iSerialNumber 0x%x\n", pDeviceDescriptor -> iSerialNumber));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USGetUSBDeviceDescriptor: bNumConfigurations 0x%x\n", pDeviceDescriptor -> bNumConfigurations));
|
|
|
|
//
|
|
// Save pointer to device descriptor in our device extension
|
|
//
|
|
|
|
pde -> pDeviceDescriptor = pDeviceDescriptor;
|
|
|
|
} else { // (STATUS_SUCCESS == Status)
|
|
|
|
//
|
|
// Error returned from lower driver.
|
|
//
|
|
|
|
DebugTrace(TRACE_ERROR,("USGetUSBDeviceDescriptor: ERROR!! Cannot get device descriptor. (%x)\n", Status));
|
|
USFreePool(pDeviceDescriptor);
|
|
pDeviceDescriptor = NULL;
|
|
} // (STATUS_SUCCESS == Status)
|
|
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
|
|
USGetUSBDeviceDescriptor_return:
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USGetUSBDeviceDescriptor: Leaving.. Status = 0x%x\n", Status));
|
|
return Status;
|
|
} // end USGetUSBDeviceDescriptor()
|
|
|
|
|
|
|
|
NTSTATUS
|
|
USDeferIrpCompletion(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine is called when the port driver completes an IRP.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject - Pointer to the device object for the class device.
|
|
pIrp - Irp completed.
|
|
Context - Driver defined context.
|
|
|
|
Return Value:
|
|
The function value is the final status from the operation.
|
|
|
|
--*/
|
|
{
|
|
PKEVENT pEvent = Context;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USDeferIrpCompletion: Enter..\n"));
|
|
KeSetEvent(pEvent, 1, FALSE);
|
|
DebugTrace(TRACE_PROC_LEAVE,("USDeferIrpCompletion: Leaving.. Status = STATUS_MORE_PROCESSING_REQUIRED\n"));
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
} // end USDeferIrpCompletion()
|
|
|
|
|
|
VOID
|
|
USIncrementIoCount(
|
|
IN PDEVICE_OBJECT pDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PUSBSCAN_DEVICE_EXTENSION pde;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USIncrementIoCount: Enter..\n"));
|
|
|
|
pde = (PUSBSCAN_DEVICE_EXTENSION)(pDeviceObject -> DeviceExtension);
|
|
ASSERT((LONG)pde -> PendingIoCount >= 0);
|
|
InterlockedIncrement(&pde -> PendingIoCount);
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USIncrementIoCount: Leaving.. IoCount=0x%x, Status=VOID\n", pde -> PendingIoCount));
|
|
|
|
} // end USIncrementIoCount()
|
|
|
|
|
|
LONG
|
|
USDecrementIoCount(
|
|
IN PDEVICE_OBJECT pDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PUSBSCAN_DEVICE_EXTENSION pde;
|
|
LONG ioCount;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USDecrementIoCount: Enter..\n"));
|
|
|
|
pde = (PUSBSCAN_DEVICE_EXTENSION)(pDeviceObject -> DeviceExtension);
|
|
ASSERT(pde ->PendingIoCount >= 1);
|
|
|
|
ioCount = InterlockedDecrement(&pde -> PendingIoCount);
|
|
|
|
if (0 == ioCount) {
|
|
KeSetEvent(&pde -> PendingIoEvent,
|
|
1,
|
|
FALSE);
|
|
}
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USDecrementIoCount: Leaving.. IoCount(=Ret)=0x%x\n", ioCount));
|
|
return ioCount;
|
|
} // end USDecrementIoCount()
|
|
|
|
|
|
NTSTATUS
|
|
USBSCAN_CallUSBD(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PURB pUrb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Passes a URB to the USBD class driver
|
|
|
|
Arguments:
|
|
pDeviceObject - pointer to the device object
|
|
pUrb - pointer to Urb request block
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PUSBSCAN_DEVICE_EXTENSION pde;
|
|
PIRP pIrp;
|
|
KEVENT eventTimeout;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
PIO_STACK_LOCATION pNextStack;
|
|
LARGE_INTEGER Timeout;
|
|
KEVENT eventSync;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USBSCAN_CallUSBD: Enter..\n"));
|
|
|
|
pde = pDeviceObject -> DeviceExtension;
|
|
|
|
//
|
|
// issue a synchronous request
|
|
//
|
|
|
|
KeInitializeEvent(&eventTimeout, NotificationEvent, FALSE);
|
|
KeInitializeEvent(&eventSync, SynchronizationEvent, FALSE);
|
|
|
|
pIrp = IoBuildDeviceIoControlRequest(
|
|
IOCTL_INTERNAL_USB_SUBMIT_URB,
|
|
pde -> pStackDeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE, /* INTERNAL */
|
|
&eventTimeout,
|
|
&ioStatus);
|
|
|
|
if(NULL == pIrp){
|
|
DebugTrace(TRACE_CRITICAL,("USBSCAN_CallUSBD: ERROR!! cannot allocated IRP\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USBSCAN_CallUSBD_return;
|
|
}
|
|
|
|
//
|
|
// Call the class driver to perform the operation. If the returned status
|
|
// is PENDING, wait for the request to complete.
|
|
//
|
|
|
|
pNextStack = IoGetNextIrpStackLocation(pIrp);
|
|
ASSERT(pNextStack != NULL);
|
|
|
|
//
|
|
// pass the URB to the USB driver stack
|
|
//
|
|
|
|
pNextStack -> Parameters.Others.Argument1 = pUrb;
|
|
|
|
//
|
|
// Set completion routine
|
|
//
|
|
|
|
IoSetCompletionRoutine(pIrp,
|
|
USDeferIrpCompletion,
|
|
&eventSync,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
DebugTrace(TRACE_STATUS,("USBSCAN_CallUSBD: calling USBD\n"));
|
|
|
|
Status = IoCallDriver(pde -> pStackDeviceObject, pIrp);
|
|
|
|
DebugTrace(TRACE_STATUS,("USBSCAN_CallUSBD: return from IoCallDriver USBD %x\n", Status));
|
|
|
|
if (Status == STATUS_PENDING) {
|
|
DebugTrace(TRACE_STATUS,("USBSCAN_CallUSBD: Wait for single object\n"));
|
|
|
|
//
|
|
// Set timeout in case bad device not responding.
|
|
//
|
|
|
|
Timeout = RtlConvertLongToLargeInteger(-10*1000*1000*(USBSCAN_TIMEOUT_OTHER));
|
|
Status = KeWaitForSingleObject(
|
|
&eventSync,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
&Timeout);
|
|
if(STATUS_TIMEOUT == Status){
|
|
|
|
NTSTATUS LocalStatus;
|
|
|
|
DebugTrace(TRACE_ERROR,("USBSCAN_CallUSBD: ERROR!! call timeout. Now canceling IRP...\n"));
|
|
|
|
//
|
|
// Cancel IRP.
|
|
//
|
|
|
|
IoCancelIrp(pIrp);
|
|
|
|
//
|
|
// Make sure the IRP gets completed.
|
|
//
|
|
|
|
LocalStatus = KeWaitForSingleObject(&eventSync,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
DebugTrace(TRACE_STATUS,("USBSCAN_CallUSBD: Canceled status = 0x%x.\n", LocalStatus));
|
|
|
|
} else {
|
|
DebugTrace(TRACE_STATUS,("USBSCAN_CallUSBD: Wait for single object, returned 0x%x\n", Status));
|
|
}
|
|
} // if (Status == STATUS_PENDING)
|
|
|
|
//
|
|
// Free the IRP.
|
|
//
|
|
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
|
|
USBSCAN_CallUSBD_return:
|
|
DebugTrace(TRACE_PROC_LEAVE, ("USBSCAN_CallUSBD: Leaving.. URB Status = 0x%x, Status = 0x%x\n",
|
|
pUrb -> UrbHeader.Status,
|
|
Status));
|
|
return Status;
|
|
|
|
} // end USBSCAN_CallUSBD()
|
|
|
|
|
|
NTSTATUS
|
|
USConfigureDevice(
|
|
IN PDEVICE_OBJECT pDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initializes a given instance of the device on the USB and selects the
|
|
configuration.
|
|
|
|
Arguments:
|
|
pDeviceObject - pointer to the device object
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
PUSBSCAN_DEVICE_EXTENSION pde;
|
|
PURB pUrb;
|
|
ULONG siz;
|
|
PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor;
|
|
PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor;
|
|
PUSB_ENDPOINT_DESCRIPTOR pEndpointDescriptor;
|
|
PUSB_COMMON_DESCRIPTOR pCommonDescriptor;
|
|
PUSBD_INTERFACE_INFORMATION pInterface;
|
|
UCHAR AlternateSetting;
|
|
UCHAR InterfaceNumber;
|
|
USHORT length;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USConfigureDevice: Enter..\n"));
|
|
|
|
//
|
|
// Initialize local variable.
|
|
//
|
|
|
|
pConfigurationDescriptor = NULL;
|
|
pInterfaceDescriptor = NULL;
|
|
pEndpointDescriptor = NULL;
|
|
pCommonDescriptor = NULL;
|
|
pInterface = NULL;
|
|
pUrb = NULL;
|
|
|
|
siz = 0;
|
|
AlternateSetting = 0;
|
|
InterfaceNumber = 0;
|
|
length = 0;
|
|
|
|
pde = pDeviceObject -> DeviceExtension;
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
//
|
|
// First configure the device
|
|
//
|
|
|
|
pUrb = USAllocatePool(NonPagedPool,
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
|
|
if (NULL == pUrb) {
|
|
DebugTrace(TRACE_CRITICAL,("USConfigureDevice: ERROR!! Can't allocate control descriptor URB.\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USConfigureDevice_return;
|
|
}
|
|
|
|
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR);
|
|
|
|
|
|
get_config_descriptor_retry:
|
|
|
|
pConfigurationDescriptor = USAllocatePool(NonPagedPool, siz);
|
|
if (NULL == pConfigurationDescriptor) {
|
|
DebugTrace(TRACE_CRITICAL,("USConfigureDevice: ERROR!! Can't allocate configuration descriptor.\n"));
|
|
DEBUG_BREAKPOINT();
|
|
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USConfigureDevice_return;
|
|
}
|
|
|
|
//
|
|
// Initialize buffers by 0
|
|
//
|
|
|
|
RtlZeroMemory(pConfigurationDescriptor, siz);
|
|
RtlZeroMemory(pUrb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
|
|
|
|
UsbBuildGetDescriptorRequest(pUrb,
|
|
(USHORT)sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
USB_CONFIGURATION_DESCRIPTOR_TYPE,
|
|
0,
|
|
0,
|
|
pConfigurationDescriptor,
|
|
NULL,
|
|
siz,
|
|
NULL);
|
|
|
|
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
|
|
|
|
DebugTrace(TRACE_STATUS,("USConfigureDevice: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE Status = %x\n", Status));
|
|
DebugTrace(TRACE_STATUS,("USConfigureDevice: Configuration Descriptor = %x, len = %x\n",
|
|
pConfigurationDescriptor,
|
|
pUrb -> UrbControlDescriptorRequest.TransferBufferLength));
|
|
|
|
|
|
//
|
|
// if we got some data see if it was enough.
|
|
//
|
|
// NOTE: we may get an error in URB because of buffer overrun
|
|
//
|
|
|
|
if ( (pUrb -> UrbControlDescriptorRequest.TransferBufferLength > 0) &&
|
|
(pConfigurationDescriptor -> wTotalLength > siz)) {
|
|
|
|
DebugTrace(TRACE_WARNING,("USConfigureDevice: WARNING!! Data is incomplete. Fetch descriptor again...\n"));
|
|
|
|
siz = pConfigurationDescriptor -> wTotalLength;
|
|
USFreePool(pConfigurationDescriptor);
|
|
pConfigurationDescriptor = NULL;
|
|
goto get_config_descriptor_retry;
|
|
}
|
|
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
|
|
//
|
|
// We have the configuration descriptor for the configuration
|
|
// we want. Save it in our device extension.
|
|
//
|
|
|
|
pde -> pConfigurationDescriptor = pConfigurationDescriptor;
|
|
|
|
//
|
|
// Now we issue the select configuration command to get
|
|
// the pipes associated with this configuration.
|
|
//
|
|
|
|
pUrb = USCreateConfigurationRequest(pConfigurationDescriptor, &length);
|
|
if (NULL == pUrb) {
|
|
DebugTrace(TRACE_CRITICAL,("USConfigureDevice: ERROR!! Can't allocate select configuration urb.\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USConfigureDevice_return;
|
|
}
|
|
|
|
//
|
|
// Get the Interface descriptors.
|
|
//
|
|
|
|
pInterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(pConfigurationDescriptor,
|
|
pConfigurationDescriptor,
|
|
-1,
|
|
0,
|
|
-1,
|
|
-1,
|
|
-1);
|
|
|
|
if(NULL == pInterfaceDescriptor){
|
|
DebugTrace(TRACE_CRITICAL,("USConfigureDevice: ERROR!! Can't get Interface descriptor.\n"));
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto USConfigureDevice_return;
|
|
}
|
|
|
|
//
|
|
// Get the Endpoint descriptors.
|
|
//
|
|
|
|
pCommonDescriptor = USBD_ParseDescriptors(pConfigurationDescriptor,
|
|
pConfigurationDescriptor->wTotalLength,
|
|
pInterfaceDescriptor,
|
|
USB_ENDPOINT_DESCRIPTOR_TYPE);
|
|
if(NULL == pCommonDescriptor){
|
|
DebugTrace(TRACE_CRITICAL,("USConfigureDevice: ERROR!! Can't get Endpoint descriptor.\n"));
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto USConfigureDevice_return;
|
|
}
|
|
|
|
ASSERT(USB_ENDPOINT_DESCRIPTOR_TYPE == pCommonDescriptor->bDescriptorType);
|
|
pEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)pCommonDescriptor;
|
|
|
|
//
|
|
// save these pointers is our device extension.
|
|
//
|
|
|
|
pde -> pInterfaceDescriptor = pInterfaceDescriptor;
|
|
pde -> pEndpointDescriptor = pEndpointDescriptor;
|
|
|
|
//
|
|
// Set the max transfer size for each BULK endpoint to 64K.
|
|
// Also, search through the set of endpoints and find the pipe index for our
|
|
// bulk-in, interrupt, and optionally bulk-out pipes.
|
|
//
|
|
|
|
pde -> IndexBulkIn = -1;
|
|
pde -> IndexBulkOut = -1;
|
|
pde -> IndexInterrupt = -1;
|
|
|
|
pInterface = &(pUrb -> UrbSelectConfiguration.Interface);
|
|
|
|
for (i=0; i < pInterfaceDescriptor -> bNumEndpoints; i++) {
|
|
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: End point[%d] descriptor\n", i));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: bLength : 0x%X\n", pEndpointDescriptor[i].bLength));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: bDescriptorType : 0x%X\n", pEndpointDescriptor[i].bDescriptorType));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: bEndpointAddress : 0x%X\n", pEndpointDescriptor[i].bEndpointAddress));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: bmAttributes : 0x%X\n", pEndpointDescriptor[i].bmAttributes));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: wMaxPacketSize : 0x%X\n", pEndpointDescriptor[i].wMaxPacketSize));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: bInterval : 0x%X\n", pEndpointDescriptor[i].bInterval));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: \n"));
|
|
|
|
if (USB_ENDPOINT_TYPE_BULK == pEndpointDescriptor[i].bmAttributes) {
|
|
pInterface -> Pipes[i].MaximumTransferSize = 64*1024;
|
|
if (pEndpointDescriptor[i].bEndpointAddress & BULKIN_FLAG) { // if input endpoint
|
|
pde -> IndexBulkIn = i;
|
|
} else {
|
|
pde -> IndexBulkOut = i;
|
|
}
|
|
} else if (USB_ENDPOINT_TYPE_INTERRUPT == pEndpointDescriptor[i].bmAttributes) {
|
|
pde -> IndexInterrupt = i;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Select the default configuration.
|
|
//
|
|
|
|
UsbBuildSelectConfigurationRequest(pUrb, length, pConfigurationDescriptor);
|
|
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
|
|
if (STATUS_SUCCESS != Status) {
|
|
DebugTrace(TRACE_ERROR,("USConfigureDevice: ERROR!! Selecting default configuration. Status = %x\n", Status));
|
|
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
Status = STATUS_IO_DEVICE_ERROR;
|
|
goto USConfigureDevice_return;
|
|
}
|
|
|
|
//
|
|
// Save the configuration handle in our device extension.
|
|
//
|
|
|
|
pde -> ConfigurationHandle = pUrb -> UrbSelectConfiguration.ConfigurationHandle;
|
|
|
|
//
|
|
// Insure that this device won't overflow our PipeInfo structure.
|
|
//
|
|
|
|
if (pInterfaceDescriptor -> bNumEndpoints > MAX_NUM_PIPES) {
|
|
DebugTrace(TRACE_ERROR,("USConfigureDevice: ERROR!! Too many endpoints for this driver! # endpoints = %d\n",
|
|
pInterfaceDescriptor -> bNumEndpoints));
|
|
// DEBUG_BREAKPOINT();
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USConfigureDevice_return;
|
|
}
|
|
|
|
//
|
|
// Save pipe configurations in our device extension
|
|
//
|
|
|
|
pde -> NumberOfPipes = pInterfaceDescriptor -> bNumEndpoints;
|
|
|
|
for (i=0; i < pInterfaceDescriptor -> bNumEndpoints; i++) {
|
|
pde -> PipeInfo[i] = pInterface -> Pipes[i];
|
|
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: Pipe[%d] information\n", i));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: MaximumPacketSize : 0x%X\n", pde -> PipeInfo[i].MaximumPacketSize));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: EndpointAddress : 0x%X\n", pde -> PipeInfo[i].EndpointAddress));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: Interval : 0x%X\n", pde -> PipeInfo[i].Interval));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: PipeType : 0x%X\n", pde -> PipeInfo[i].PipeType));
|
|
DebugTrace(TRACE_DEVICE_DATA,("USConfigureDevice: PipeHandle : 0x%X\n", pde -> PipeInfo[i].PipeHandle));
|
|
|
|
//
|
|
// Initialize the read pipe buffer if type is Bulk-In.
|
|
//
|
|
|
|
if( (pde->PipeInfo[i].PipeType == UsbdPipeTypeBulk)
|
|
&& (pde->PipeInfo[i].EndpointAddress & BULKIN_FLAG) )
|
|
{
|
|
|
|
DebugTrace(TRACE_STATUS,("USConfigureDevice: Alocates buffer for Pipe[%d]\n", i));
|
|
|
|
pde -> ReadPipeBuffer[i].RemainingData = 0;
|
|
pde -> ReadPipeBuffer[i].pBuffer = USAllocatePool(NonPagedPool, 2 * (pde -> PipeInfo[i].MaximumPacketSize));
|
|
if (NULL == pde -> ReadPipeBuffer[i].pBuffer) {
|
|
DebugTrace(TRACE_CRITICAL,("USConfigureDevice: Cannot allocate bulk-in buffer.\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
goto USConfigureDevice_return;
|
|
}
|
|
pde -> ReadPipeBuffer[i].pStartBuffer = pde -> ReadPipeBuffer[i].pBuffer;
|
|
} else {
|
|
pde -> ReadPipeBuffer[i].pBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
|
|
USConfigureDevice_return:
|
|
DebugTrace(TRACE_PROC_LEAVE,("USConfigureDevice: Leaving.. Status = %x\n", Status));
|
|
return Status;
|
|
} // USConfigureDevice()
|
|
|
|
|
|
NTSTATUS
|
|
USUnConfigureDevice(
|
|
IN PDEVICE_OBJECT pDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
pDeviceObject - pointer to the device object
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PURB pUrb;
|
|
ULONG siz;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USUnConfigureDevice: Enter..\n"));
|
|
|
|
siz = sizeof(struct _URB_SELECT_CONFIGURATION);
|
|
pUrb = USAllocatePool(NonPagedPool, siz);
|
|
if (NULL == pUrb) {
|
|
DebugTrace(TRACE_CRITICAL,("USUnConfigureDevice: ERROR!! cannot allocated URB\n"));
|
|
DEBUG_BREAKPOINT();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USUnConfigureDevice_return;
|
|
}
|
|
RtlZeroMemory(pUrb, siz);
|
|
|
|
//
|
|
// Send the select configuration urb with a NULL pointer for the configuration
|
|
// handle, this closes the configuration and puts the device in the 'unconfigured'
|
|
// state.
|
|
//
|
|
|
|
UsbBuildSelectConfigurationRequest(pUrb, (USHORT)siz, NULL);
|
|
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
|
|
DebugTrace(TRACE_STATUS,("USUnConfigureDevice: Device Configuration Closed status = %x usb status = %x.\n",
|
|
Status, pUrb->UrbHeader.Status));
|
|
|
|
USFreePool(pUrb);
|
|
pUrb = NULL;
|
|
|
|
USUnConfigureDevice_return:
|
|
DebugTrace(TRACE_PROC_LEAVE,("USUnConfigureDevice: Leaving.. Status = %x\n", Status));
|
|
return Status;
|
|
} // USUnConfigureDevice()
|
|
|
|
NTSTATUS
|
|
USGetDeviceCapability(
|
|
IN PUSBSCAN_DEVICE_EXTENSION pde
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
pDeviceObject - pointer to the device object
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PIRP pIrp;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
KEVENT Event;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USGetDeviceCapability: Enter..\n"));
|
|
|
|
//
|
|
// Initialize local.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
pIrp = NULL;
|
|
pIrpStack = NULL;
|
|
|
|
//
|
|
// Allocate Irp.
|
|
//
|
|
|
|
pIrp = IoAllocateIrp(pde->pStackDeviceObject->StackSize, FALSE);
|
|
if(NULL == pIrp){
|
|
DebugTrace(TRACE_WARNING,("USUnConfigureDevice: ERROR!! Unable to allocate Irp.\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto USGetDeviceCapability_return;
|
|
} // if(NULL == pIrp)
|
|
|
|
//
|
|
// Get next stack location of the allocated IRP.
|
|
//
|
|
|
|
pIrpStack = IoGetNextIrpStackLocation(pIrp);
|
|
ASSERT(NULL != pIrpStack);
|
|
|
|
//
|
|
// Initialize required fields.
|
|
//
|
|
|
|
RtlZeroMemory(&pde->DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
|
|
pde->DeviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES);
|
|
pde->DeviceCapabilities.Version = 1;
|
|
pde->DeviceCapabilities.Address = -1;
|
|
pde->DeviceCapabilities.UINumber = -1;
|
|
|
|
//
|
|
// Set required parameters.
|
|
//
|
|
|
|
pIrpStack->MajorFunction = IRP_MJ_PNP;
|
|
pIrpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
|
|
pIrpStack->Parameters.DeviceCapabilities.Capabilities = &pde->DeviceCapabilities;
|
|
|
|
pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Initialize synchronization.
|
|
//
|
|
|
|
KeInitializeEvent(&Event,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
//
|
|
// Set completion routine
|
|
//
|
|
|
|
IoSetCompletionRoutine(pIrp,
|
|
USDeferIrpCompletion,
|
|
&Event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
//
|
|
// Call down
|
|
//
|
|
|
|
Status = IoCallDriver(pde -> pStackDeviceObject, pIrp);
|
|
if(Status == STATUS_PENDING){
|
|
|
|
//
|
|
// Waiting for the completion.
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS,("USGetDeviceCapability: STATUS_PENDING. Wait for completion.\n"));
|
|
KeWaitForSingleObject(&Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
Status = pIrp -> IoStatus.Status;
|
|
} // if(Status == STATUS_PENDING)
|
|
|
|
//
|
|
// See if device is capable for remote wake.
|
|
//
|
|
|
|
if(NT_SUCCESS(Status)){
|
|
if(PowerDeviceD0 != pde->DeviceCapabilities.DeviceWake){
|
|
|
|
//
|
|
// Remote wake isn't supported on this device.
|
|
//
|
|
|
|
pde->bEnabledForWakeup = TRUE;
|
|
} // if(PowerDeviceD0 == pCaps->DeviceWake)
|
|
} // if(NT_SUCCESS(Status))
|
|
|
|
//
|
|
// Free allocated Irp.
|
|
//
|
|
|
|
IoFreeIrp(pIrp);
|
|
pIrp = NULL;
|
|
|
|
USGetDeviceCapability_return:
|
|
DebugTrace(TRACE_PROC_LEAVE,("USGetDeviceCapability: Leaving.. Status = %x\n", Status));
|
|
return Status;
|
|
} // USGetDeviceCapability()
|
|
|
|
|
|
VOID
|
|
USUnload(
|
|
IN PDRIVER_OBJECT pDriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Unload routine. The routine is called when the driver is unloaded.
|
|
Release every resource allocated in relation with the driver object.
|
|
|
|
Arguments:
|
|
pDriverObject - pointer to the driver object
|
|
|
|
Return Value:
|
|
None
|
|
|
|
-- */
|
|
{
|
|
PAGED_CODE();
|
|
|
|
DebugTrace((MIN_TRACE | TRACE_FLAG_PROC),("UsbScanUnload(0x%X);\n", pDriverObject));
|
|
|
|
} // end USUnload()
|
|
|
|
|
|
NTSTATUS
|
|
USCallNextDriverSynch(
|
|
IN PUSBSCAN_DEVICE_EXTENSION pde,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls lower driver and waits for result
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - pointer to device extension
|
|
Irp - pointer to IRP
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
KEVENT Event;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
NTSTATUS Status;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USCallNextDriverSynch: Enter..\n"));
|
|
|
|
IrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
//
|
|
// Copy IRP stack to the next.
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(pIrp);
|
|
|
|
//
|
|
// Initialize synchronizing event.
|
|
//
|
|
|
|
KeInitializeEvent(&Event,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
//
|
|
// Set completion routine
|
|
//
|
|
|
|
IoSetCompletionRoutine(pIrp,
|
|
USDeferIrpCompletion,
|
|
&Event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
//
|
|
// Call down
|
|
//
|
|
|
|
Status = IoCallDriver(pde -> pStackDeviceObject, pIrp);
|
|
|
|
if (Status == STATUS_PENDING) {
|
|
|
|
//
|
|
// Waiting for the completion.
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS,("USCallNextDriverSynch: STATUS_PENDING. Wait for event.\n"));
|
|
KeWaitForSingleObject(&Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
Status = pIrp -> IoStatus.Status;
|
|
}
|
|
|
|
//
|
|
// Return
|
|
//
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USCallNextDriverSynch: Leaving.. Status = %x\n", Status));
|
|
return (Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
UsbScanHandleInterface(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PUNICODE_STRING InterfaceName,
|
|
BOOLEAN Create
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies the device object.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("UsbScanHandleInterface: Enter..\n"));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
#ifndef _CHICAGO_
|
|
|
|
if (Create) {
|
|
|
|
Status=IoRegisterDeviceInterface(
|
|
DeviceObject,
|
|
&GUID_DEVINTERFACE_IMAGE,
|
|
NULL,
|
|
InterfaceName
|
|
);
|
|
DebugTrace(TRACE_STATUS,("Called IoRegisterDeviceInterface . Returned=0x%X\n",Status));
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
IoSetDeviceInterfaceState(
|
|
InterfaceName,
|
|
TRUE
|
|
);
|
|
|
|
DebugTrace(TRACE_STATUS,("Called IoSetDeviceInterfaceState(TRUE) . \n"));
|
|
}
|
|
} else {
|
|
|
|
if (InterfaceName->Buffer != NULL) {
|
|
|
|
Status = IoSetDeviceInterfaceState(
|
|
InterfaceName,
|
|
FALSE
|
|
);
|
|
|
|
RtlFreeUnicodeString(
|
|
InterfaceName
|
|
);
|
|
|
|
InterfaceName->Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
#endif // !_CHICAGO_
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("IoRegisterDeviceInterface: Leaving... Status=0x%X\n",Status));
|
|
return Status;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
USArmForWake(
|
|
PUSBSCAN_DEVICE_EXTENSION pde,
|
|
POWER_STATE SystemState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Arm device for remote wakeup.
|
|
|
|
Arguments:
|
|
pde - pointer to device extension
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if successful,
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bRet;
|
|
LONG OldWakeState;
|
|
NTSTATUS status;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USArmForWake: Enter..\n"));
|
|
|
|
//
|
|
// Initialize local.
|
|
//
|
|
|
|
bRet = FALSE;
|
|
status = STATUS_SUCCESS;
|
|
OldWakeState = WAKESTATE_DISARMED;
|
|
|
|
//
|
|
// See if device/system supports wakeup.
|
|
//
|
|
|
|
if(TRUE != pde->bEnabledForWakeup){
|
|
DebugTrace(TRACE_STATUS,("USArmForWake: This device or system doesn't support RemoteWake.\n"));
|
|
bRet = FALSE;
|
|
goto USArmForWake_return;
|
|
} // if(TRUE != pde->bEnabledForWakeup)
|
|
|
|
//
|
|
// Make sure about curent state.
|
|
//
|
|
|
|
while(1){
|
|
// Try to move us into the arming state
|
|
OldWakeState = InterlockedCompareExchange(&pde->WakeState,
|
|
WAKESTATE_WAITING,
|
|
WAKESTATE_DISARMED);
|
|
if(WAKESTATE_DISARMED == OldWakeState){
|
|
break;
|
|
} // if(OldWakeState == WAKESTATE_DISARMED)
|
|
|
|
|
|
if( (WAKESTATE_ARMED == OldWakeState)
|
|
|| (WAKESTATE_WAITING == OldWakeState) )
|
|
{
|
|
// The device is already armed.
|
|
DebugTrace(TRACE_STATUS,("USArmForWake: Device is already armed for wake\n"));
|
|
bRet = TRUE;
|
|
goto USArmForWake_return;
|
|
}
|
|
|
|
// Wait for the previous wait-wake IRP to finish
|
|
DebugTrace(TRACE_STATUS,("USArmForWake: Wait for previous wake IRP to complete.\n"));
|
|
USDisarmWake(pde);
|
|
} // while(1)
|
|
|
|
// The state just got moved to WAKESTATE_WAITING. First ensure the previous
|
|
// WaitWake IRP has finished
|
|
|
|
KeWaitForSingleObject(&pde->WakeCompletedEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
//
|
|
// Request the power IRP, STATUS_PENDING is success
|
|
//
|
|
|
|
status = PoRequestPowerIrp(pde->pStackDeviceObject,
|
|
IRP_MN_WAIT_WAKE,
|
|
SystemState,
|
|
USWaitWakePoCompletionRoutine,
|
|
(PVOID)pde,
|
|
NULL );
|
|
if(!NT_SUCCESS(status)){
|
|
|
|
//
|
|
// IRP_MN_WAIT_WAKE didn't succeed. Possiblly lower stack doesn't support.
|
|
//
|
|
|
|
DebugTrace(TRACE_WARNING,("USArmForWake: WARNING!! IRP_MN_WAIT_WAKE failed. Statust=0x%x.\n", status));
|
|
|
|
pde->WakeState = WAKESTATE_DISARMED;
|
|
KeSetEvent(&pde->WakeCompletedEvent,
|
|
IO_NO_INCREMENT,
|
|
FALSE);
|
|
} // if(!NT_SUCCESS(status))
|
|
|
|
bRet = (status == STATUS_PENDING);
|
|
|
|
USArmForWake_return:
|
|
DebugTrace(TRACE_PROC_LEAVE,("USArmForWake: Leaving.. Ret=0x%x\n", bRet));
|
|
return bRet;
|
|
|
|
} // USArmForWake()
|
|
|
|
|
|
VOID
|
|
USDisarmWake(
|
|
PUSBSCAN_DEVICE_EXTENSION pde
|
|
)
|
|
{
|
|
LONG oldWakeState;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USDisarmWake: Enter...\n"));
|
|
|
|
//
|
|
// See if device/system supports wakeup.
|
|
//
|
|
|
|
if(TRUE != pde->bEnabledForWakeup){
|
|
DebugTrace(TRACE_STATUS,("USDisarmWake: This device or system doesn't support RemoteWake.\n"));
|
|
goto USDisarmWake_return;
|
|
} // if(TRUE != pde->bEnabledForWakeup)
|
|
|
|
// Go from WAKESTATE_WAITING to WAKESTATE_WAITING_CANCELLED, or
|
|
// WAKESTATE_ARMED to WAKESTATE_ARMING_CANCELLED, or
|
|
// stay in WAKESTATE_DISARMED or WAKESTATE_COMPLETING
|
|
|
|
oldWakeState = MyInterlockedOr(&pde->SpinLock,
|
|
&pde->WakeState,
|
|
1);
|
|
|
|
if(WAKESTATE_ARMED == oldWakeState){
|
|
DebugTrace(TRACE_STATUS,("USDisarmWake: Currently armed, canceling WaitWakeIRP...\n"));
|
|
ASSERT(NULL != pde->pWakeIrp);
|
|
|
|
IoCancelIrp(pde->pWakeIrp);
|
|
|
|
//
|
|
// Now that we�fve cancelled the IRP, try to give back ownership
|
|
// to the completion routine by restoring the WAKESTATE_ARMED state
|
|
//
|
|
|
|
|
|
//
|
|
// Note: Check again here to make sure there's no "Dangerous moment"
|
|
//
|
|
|
|
oldWakeState = InterlockedCompareExchange(&pde->WakeState,
|
|
WAKESTATE_ARMED,
|
|
WAKESTATE_ARMING_CANCELLED);
|
|
if(WAKESTATE_COMPLETING == oldWakeState){
|
|
|
|
//
|
|
// We didn�ft give back control of IRP in time, so we own it now.
|
|
//
|
|
|
|
IoCompleteRequest(pde->pWakeIrp, IO_NO_INCREMENT);
|
|
} // if(WAKESTATE_COMPLETING == oldWakeState)
|
|
} // if(WAKESTATE_ARMED == oldWakeState)
|
|
|
|
USDisarmWake_return:
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USDisarmWake: Leaving.. Ret=VOID.\n"));
|
|
} // USDisarmWake()
|
|
|
|
|
|
VOID
|
|
USWaitWakePoCompletionRoutine(
|
|
PDEVICE_OBJECT pDeviceObject,
|
|
UCHAR MinorFunction,
|
|
POWER_STATE State,
|
|
PVOID pContext,
|
|
PIO_STATUS_BLOCK pIoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Completion routine for WaitWait IRP.
|
|
--*/
|
|
{
|
|
PUSBSCAN_DEVICE_EXTENSION pde;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USWaitWakePoCompletionRoutine: Enter...\n"));
|
|
|
|
pde = (PUSBSCAN_DEVICE_EXTENSION) pContext;
|
|
|
|
//
|
|
// WaitWakeIRP has been freed.
|
|
//
|
|
|
|
pde->pWakeIrp = NULL;
|
|
pde->WakeState = WAKESTATE_DISARMED;
|
|
|
|
//
|
|
// Adjust synchronization event so another Wait-Wake can get queued
|
|
//
|
|
|
|
KeSetEvent(&pde->WakeCompletedEvent,
|
|
IO_NO_INCREMENT,
|
|
FALSE);
|
|
|
|
if(NT_SUCCESS(pIoStatus->Status)){
|
|
DebugTrace(TRACE_STATUS,("USWaitWakePoCompletionRoutine: Wakeup succeeded. Queue rearm callback.\n"));
|
|
|
|
|
|
//
|
|
// WaitWakeIRP has been completed successfully. Rearming for next wakeup.
|
|
//
|
|
|
|
USQueuePassiveLevelCallback(pde->pOwnDeviceObject,
|
|
USPassiveLevelReArmCallbackWorker);
|
|
|
|
} else if( (STATUS_UNSUCCESSFUL == pIoStatus->Status)
|
|
|| (STATUS_NOT_IMPLEMENTED == pIoStatus->Status)
|
|
|| (STATUS_POWER_STATE_INVALID == pIoStatus->Status)
|
|
|| (STATUS_NOT_SUPPORTED == pIoStatus->Status) )
|
|
{
|
|
//
|
|
// Remote wakeup isn't supported on this bus/device.
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS,("USWaitWakePoCompletionRoutine: RemoteWake isn't supported. Ret=VOID.\n"));
|
|
pde -> bEnabledForWakeup = FALSE;
|
|
|
|
} else {
|
|
DebugTrace(TRACE_STATUS,("USWaitWakePoCompletionRoutine: Wakeup didn't succeed.(0x%x).\n", pIoStatus->Status));
|
|
}
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USWaitWakePoCompletionRoutine: Leaving.. Ret=VOID.\n"));
|
|
return;
|
|
} // USWaitWakePoCompletionRoutine()
|
|
|
|
VOID
|
|
USInitializeWakeState(
|
|
PUSBSCAN_DEVICE_EXTENSION pde
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initialize wake state.
|
|
|
|
Arguments:
|
|
pde - pointer to device extension
|
|
|
|
Return Value:
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
|
|
pde->WakeState = WAKESTATE_DISARMED;
|
|
pde->pWakeIrp = NULL;
|
|
|
|
//
|
|
// Initialize event for sync.
|
|
//
|
|
|
|
KeInitializeEvent(&pde->WakeCompletedEvent,
|
|
SynchronizationEvent,
|
|
TRUE);
|
|
} // USArmDevice()
|
|
|
|
VOID
|
|
USQueuePassiveLevelCallback(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIO_WORKITEM_ROUTINE pCallbackFunction
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine queues a passive level callback if it's called
|
|
at DISPATCH_LEVEL otherwise calls the worker routine directly.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device extenion.
|
|
|
|
CallbackFunction - Function to invoke when at PASSIVE_LEVEL.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PIO_WORKITEM item;
|
|
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USQueuePassiveLevelCallback: Enter...\n"));
|
|
|
|
//
|
|
// If the current IRQL level is not DISPATCH_LEVEL, we will call the
|
|
// CallbackFunction directly without queuing a workitem.
|
|
//
|
|
|
|
if(KeGetCurrentIrql() != DISPATCH_LEVEL) {
|
|
(*pCallbackFunction)(pDeviceObject, NULL);
|
|
} else { // if(KeGetCurrentIrql() != DISPATCH_LEVEL)
|
|
|
|
//
|
|
// Allocate a workitem and queue it for passive level processing.
|
|
//
|
|
|
|
item = IoAllocateWorkItem(pDeviceObject);
|
|
if(NULL != item){
|
|
IoQueueWorkItem(item,
|
|
pCallbackFunction,
|
|
DelayedWorkQueue,
|
|
item
|
|
);
|
|
} else { // if(NULL != item)
|
|
|
|
DebugTrace(TRACE_WARNING,("USQueuePassiveLevelCallback: WARNING!! IoAllocateWorkItem() failed, running out of resource.\n"));
|
|
} // else(NULL != item)
|
|
} // else(KeGetCurrentIrql() != DISPATCH_LEVEL)
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USQueuePassiveLevelCallback: Leaving.. Ret=VOID.\n"));
|
|
|
|
} // USQueuePassiveLevelCallback()
|
|
|
|
VOID
|
|
USPassiveLevelReArmCallbackWorker(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PVOID pContext
|
|
)
|
|
{
|
|
PUSBSCAN_DEVICE_EXTENSION pde;
|
|
POWER_STATE PowerState;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USPassiveLevelReArmCallbackWorker: Enter...\n"));
|
|
|
|
pde = pDeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Rearm for wake.
|
|
//
|
|
|
|
PowerState.SystemState = pde -> DeviceCapabilities.SystemWake;
|
|
USArmForWake(pde, PowerState);
|
|
|
|
if(NULL != pContext){
|
|
IoFreeWorkItem((PIO_WORKITEM)pContext);
|
|
} // if(Context)
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,("USPassiveLevelReArmCallbackWorker: Leaving.. Ret=VOID.\n"));
|
|
|
|
} // USPassiveLevelReArmCallbackWorker()
|
|
|
|
|
|
LONG
|
|
MyInterlockedOr(
|
|
PKSPIN_LOCK pSpinLock,
|
|
LONG volatile *Destination,
|
|
LONG Value
|
|
)
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
LONG lOldValue;
|
|
|
|
//
|
|
// Acquire spinlock to access shared resource, going into IRQL_DISPATCH_LEVEL.
|
|
//
|
|
|
|
KeAcquireSpinLock(pSpinLock, &OldIrql);
|
|
|
|
//
|
|
// Save old value;
|
|
//
|
|
|
|
lOldValue = *Destination;
|
|
|
|
//
|
|
// Or Value to the destination.
|
|
//
|
|
|
|
*Destination |= Value;
|
|
|
|
//
|
|
// Release spinlock and return to the original IRQL.
|
|
//
|
|
|
|
KeReleaseSpinLock(pSpinLock, OldIrql);
|
|
|
|
//
|
|
// Return original value.
|
|
//
|
|
|
|
return lOldValue;
|
|
|
|
} // MyInterlockedOr()
|
|
|
|
|
|
NTSTATUS
|
|
UsbScanReadDeviceRegistry(
|
|
IN PUSBSCAN_DEVICE_EXTENSION pExtension,
|
|
IN PCWSTR pKeyName,
|
|
OUT PVOID *ppvData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine open registry for this device and query a value specified
|
|
by key name. This routine allocate non-paged memory and return its pointer.
|
|
Caller must free returned pointer.
|
|
|
|
Arguments:
|
|
|
|
pExtension - pointer to device extension
|
|
pKeyName - pointer to a wide string specify key name
|
|
ppvData - pointer to the queried data pointer allocated by this routine
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS - if success,
|
|
STATUS_INVALID_PARAMETER - if passed argument is invalid,
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE hRegKey;
|
|
PVOID pvBuffer;
|
|
ULONG DataSize;
|
|
PVOID pvRetData;
|
|
UNICODE_STRING unicodeKeyName;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER, ("UsbScanReadDeviceRegistry: Entering...\n"));
|
|
|
|
//
|
|
// Initialize status
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
hRegKey = NULL;
|
|
pvBuffer = NULL;
|
|
pvRetData = NULL;
|
|
DataSize = 0;
|
|
|
|
//
|
|
// Check the arguments
|
|
//
|
|
|
|
if( (NULL == pExtension)
|
|
|| (NULL == pKeyName)
|
|
|| (NULL == ppvData) )
|
|
{
|
|
DebugTrace(TRACE_ERROR, ("UsbScanReadDeviceRegistry: ERROR!! Invalid argument.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto UsbScanReadDeviceRegistry_return;
|
|
}
|
|
|
|
//
|
|
// Open device registry.
|
|
//
|
|
|
|
Status = IoOpenDeviceRegistryKey(pExtension->pPhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DRIVER,
|
|
KEY_ALL_ACCESS,
|
|
&hRegKey);
|
|
if(!NT_SUCCESS(Status)){
|
|
DebugTrace(TRACE_ERROR, ("UsbScanReadDeviceRegistry: ERROR!! IoOpenDeviceRegistryKey failed.\n"));
|
|
goto UsbScanReadDeviceRegistry_return;
|
|
}
|
|
|
|
//
|
|
// Query required size.
|
|
//
|
|
|
|
RtlInitUnicodeString(&unicodeKeyName, pKeyName);
|
|
Status = ZwQueryValueKey(hRegKey,
|
|
&unicodeKeyName,
|
|
KeyValuePartialInformation,
|
|
NULL,
|
|
0,
|
|
&DataSize);
|
|
if(0 == DataSize){
|
|
if(STATUS_OBJECT_NAME_NOT_FOUND == Status){
|
|
DebugTrace(TRACE_STATUS, ("UsbScanReadDeviceRegistry: Reg-key \"%wZ\" doesn't exist.\n", &unicodeKeyName));
|
|
} else {
|
|
DebugTrace(TRACE_ERROR, ("UsbScanReadDeviceRegistry: ERROR!! Cannot retrieve reqired data size of %wZ. Status=0x%x\n",
|
|
&unicodeKeyName ,
|
|
Status));
|
|
}
|
|
goto UsbScanReadDeviceRegistry_return;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for temp buffer. size +2 for NULL.
|
|
//
|
|
|
|
pvBuffer = USAllocatePool(NonPagedPool, DataSize+2);
|
|
if(NULL == pvBuffer){
|
|
DebugTrace(TRACE_CRITICAL, ("UsbScanReadDeviceRegistry: ERROR!! Buffer allocate failed.\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto UsbScanReadDeviceRegistry_return;
|
|
}
|
|
RtlZeroMemory(pvBuffer, DataSize+sizeof(WCHAR));
|
|
|
|
//
|
|
// Query specified value.
|
|
//
|
|
|
|
DebugTrace(TRACE_STATUS, ("UsbScanReadDeviceRegistry: Query \"%wZ\".\n", &unicodeKeyName));
|
|
Status = ZwQueryValueKey(hRegKey,
|
|
&unicodeKeyName,
|
|
KeyValuePartialInformation,
|
|
pvBuffer,
|
|
DataSize,
|
|
&DataSize);
|
|
if(!NT_SUCCESS(Status)){
|
|
DebugTrace(TRACE_ERROR, ("UsbScanReadDeviceRegistry: ERROR!! ZwQueryValueKey failed. Status=0x%x\n", Status));
|
|
goto UsbScanReadDeviceRegistry_return;
|
|
}
|
|
|
|
UsbScanReadDeviceRegistry_return:
|
|
if(!NT_SUCCESS(Status)){
|
|
|
|
//
|
|
// This routine failed.
|
|
//
|
|
|
|
if(pvRetData){
|
|
USFreePool(pvRetData);
|
|
}
|
|
*ppvData = NULL;
|
|
} else {
|
|
|
|
//
|
|
// This routine succeeded.
|
|
//
|
|
|
|
*ppvData = pvBuffer;
|
|
}
|
|
|
|
//
|
|
// Clean-up.
|
|
//
|
|
|
|
if(hRegKey){
|
|
ZwClose(hRegKey);
|
|
}
|
|
DebugTrace(TRACE_PROC_LEAVE, ("UsbScanReadDeviceRegistry: Leaving... Status=0x%x\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
UsbScanWriteDeviceRegistry(
|
|
IN PUSBSCAN_DEVICE_EXTENSION pExtension,
|
|
IN PCWSTR pKeyName,
|
|
IN ULONG Type,
|
|
IN PVOID pvData,
|
|
IN ULONG DataSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine open registry for this device and set a value specified
|
|
by key name.
|
|
|
|
Arguments:
|
|
|
|
pExtension - pointer to device extension
|
|
pKeyName - pointer to a wide string specify key name
|
|
Type - specifies the type of data to be written
|
|
pvData - pointer to a caller allocated buffer containing data
|
|
DataSize - specifies the size in bytes of the data buffer
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS - if success,
|
|
STATUS_INVALID_PARAMETER - if passed argument is invalid,
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE hRegKey;
|
|
UNICODE_STRING unicodeKeyName;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(TRACE_PROC_ENTER, ("UsbScanWriteDeviceRegistry: Entering...\n"));
|
|
|
|
//
|
|
// Initialize status
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
hRegKey = NULL;
|
|
|
|
//
|
|
// Check the arguments
|
|
//
|
|
|
|
if( (NULL == pExtension)
|
|
|| (NULL == pKeyName)
|
|
|| (NULL == pvData)
|
|
|| (0 == DataSize) )
|
|
{
|
|
DebugTrace(TRACE_ERROR, ("UsbScanWriteDeviceRegistry: ERROR!! Invalid argument.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto UsbScanWriteDeviceRegistry_return;
|
|
}
|
|
|
|
//
|
|
// Open device registry.
|
|
//
|
|
|
|
Status = IoOpenDeviceRegistryKey(pExtension->pPhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DRIVER,
|
|
KEY_ALL_ACCESS,
|
|
&hRegKey);
|
|
if(!NT_SUCCESS(Status)){
|
|
DebugTrace(TRACE_ERROR, ("UsbScanWriteDeviceRegistry: ERROR!! IoOpenDeviceRegistryKey failed.\n"));
|
|
goto UsbScanWriteDeviceRegistry_return;
|
|
}
|
|
|
|
//
|
|
// Set specified value.
|
|
//
|
|
|
|
RtlInitUnicodeString(&unicodeKeyName, pKeyName);
|
|
DebugTrace(TRACE_STATUS, ("UsbScanWriteDeviceRegistry: Setting \"%wZ\".\n", &unicodeKeyName));
|
|
Status = ZwSetValueKey(hRegKey,
|
|
&unicodeKeyName,
|
|
0,
|
|
Type,
|
|
pvData,
|
|
DataSize);
|
|
if(!NT_SUCCESS(Status)){
|
|
DebugTrace(TRACE_ERROR, ("UsbScanWriteDeviceRegistry: ERROR!! ZwSetValueKey failed. Status = 0x%x\n", Status));
|
|
goto UsbScanWriteDeviceRegistry_return;
|
|
}
|
|
|
|
UsbScanWriteDeviceRegistry_return:
|
|
|
|
//
|
|
// Clean-up.
|
|
//
|
|
|
|
if(hRegKey){
|
|
ZwClose(hRegKey);
|
|
}
|
|
DebugTrace(TRACE_PROC_LEAVE, ("UsbScanWriteDeviceRegistry: Leaving... Status=0x%x\n", Status));
|
|
return Status;
|
|
} // UsbScanWriteDeviceRegistry()
|
|
|
|
PURB
|
|
USCreateConfigurationRequest(
|
|
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
|
|
IN OUT PUSHORT Siz
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Pointer to initailized select_configuration urb.
|
|
|
|
--*/
|
|
{
|
|
PURB urb = NULL;
|
|
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
|
|
PUSBD_INTERFACE_LIST_ENTRY interfaceList, tmp;
|
|
LONG numberOfInterfaces, interfaceNumber, i;
|
|
|
|
PAGED_CODE();
|
|
DebugTrace(TRACE_PROC_ENTER, ("USCreateConfigurationRequest: Entering...\n"));
|
|
|
|
//
|
|
// build a request structure and call the new api
|
|
//
|
|
|
|
numberOfInterfaces = ConfigurationDescriptor->bNumInterfaces;
|
|
|
|
tmp = interfaceList = USAllocatePool(PagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (numberOfInterfaces+1));
|
|
|
|
//
|
|
// just grab the first alt setting we find for each interface
|
|
//
|
|
|
|
i = interfaceNumber = 0;
|
|
|
|
while (i< numberOfInterfaces) {
|
|
|
|
interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,
|
|
ConfigurationDescriptor,
|
|
-1,
|
|
0, // assume alt setting zero here
|
|
-1,
|
|
-1,
|
|
-1);
|
|
|
|
ASSERT(interfaceDescriptor != NULL);
|
|
|
|
if (interfaceDescriptor) {
|
|
interfaceList->InterfaceDescriptor =
|
|
interfaceDescriptor;
|
|
interfaceList++;
|
|
i++;
|
|
} else {
|
|
// could not find the requested interface descriptor
|
|
// bail, we will prorblay crash somewhere in the
|
|
// client driver.
|
|
|
|
goto USCreateConfigurationRequest_return;
|
|
}
|
|
|
|
interfaceNumber++;
|
|
}
|
|
|
|
//
|
|
// terminate the list
|
|
//
|
|
interfaceList->InterfaceDescriptor = NULL;
|
|
|
|
urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, tmp);
|
|
|
|
USCreateConfigurationRequest_return:
|
|
|
|
ExFreePool(tmp);
|
|
|
|
if (urb) {
|
|
*Siz = urb->UrbHeader.Length;
|
|
}
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE, ("USCreateConfigurationRequest: Leaving... Ret=0x%x\n", urb));
|
|
return urb;
|
|
|
|
} // USCreateConfigurationRequest()
|
|
|
|
VOID
|
|
UsbScanLogError(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|
IN ULONG SequenceNumber,
|
|
IN UCHAR MajorFunctionCode,
|
|
IN UCHAR RetryCount,
|
|
IN ULONG UniqueErrorValue,
|
|
IN NTSTATUS FinalStatus,
|
|
IN NTSTATUS SpecificIOStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates an error log entry, copies the supplied data
|
|
to it, and requests that it be written to the error log file.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Supplies a pointer to the driver object for the
|
|
device.
|
|
|
|
DeviceObject - Supplies a pointer to the device object associated
|
|
with the device that had the error, early in
|
|
initialization, one may not yet exist.
|
|
|
|
SequenceNumber - Supplies a ulong value that is unique to an IRP over
|
|
the life of the irp in this driver - 0 generally
|
|
means an error not associated with an irp.
|
|
|
|
MajorFunctionCode - Supplies the major function code of the irp if there
|
|
is an error associated with it.
|
|
|
|
RetryCount - Supplies the number of times a particular operation
|
|
has been retried.
|
|
|
|
UniqueErrorValue - Supplies a unique long word that identifies the
|
|
particular call to this function.
|
|
|
|
FinalStatus - Supplies the final status given to the irp that was
|
|
associated with this error. If this log entry is
|
|
being made during one of the retries this value
|
|
will be STATUS_SUCCESS.
|
|
|
|
SpecificIOStatus - Supplies the IO status for this particular error.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_ERROR_LOG_PACKET ErrorLogEntry;
|
|
PVOID ObjectToUse;
|
|
SHORT DumpToAllocate;
|
|
|
|
if (ARGUMENT_PRESENT(DeviceObject)) {
|
|
|
|
ObjectToUse = DeviceObject;
|
|
|
|
} else {
|
|
|
|
ObjectToUse = DriverObject;
|
|
|
|
}
|
|
|
|
DumpToAllocate = 0;
|
|
|
|
ErrorLogEntry = IoAllocateErrorLogEntry(ObjectToUse,
|
|
(UCHAR) (sizeof(IO_ERROR_LOG_PACKET) + DumpToAllocate));
|
|
|
|
if (!ErrorLogEntry) {
|
|
return;
|
|
}
|
|
|
|
ErrorLogEntry->ErrorCode = SpecificIOStatus;
|
|
ErrorLogEntry->SequenceNumber = SequenceNumber;
|
|
ErrorLogEntry->MajorFunctionCode = MajorFunctionCode;
|
|
ErrorLogEntry->RetryCount = RetryCount;
|
|
ErrorLogEntry->UniqueErrorValue = UniqueErrorValue;
|
|
ErrorLogEntry->FinalStatus = FinalStatus;
|
|
ErrorLogEntry->DumpDataSize = DumpToAllocate;
|
|
|
|
if (DumpToAllocate) {
|
|
|
|
// If needed - add more to parameter list and move memory here
|
|
//RtlCopyMemory(ErrorLogEntry->DumpData, &P1, sizeof(PHYSICAL_ADDRESS));
|
|
|
|
}
|
|
|
|
IoWriteErrorLogEntry(ErrorLogEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ORIGINAL_POOLTRACK
|
|
|
|
int NumberOfAllocate = 0;
|
|
|
|
PVOID
|
|
USAllocatePool(
|
|
IN POOL_TYPE PoolType,
|
|
IN ULONG ulNumberOfBytes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper for pool allocation. Use tag to avoid heap corruption.
|
|
|
|
Arguments:
|
|
|
|
PoolType - type of pool memory to allocate
|
|
ulNumberOfBytes - number of bytes to allocate
|
|
|
|
Return Value:
|
|
|
|
Pointer to the allocated memory
|
|
|
|
--*/
|
|
{
|
|
PVOID pvRet;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USAllocatePool: Enter.. Size = %d\n", ulNumberOfBytes));
|
|
|
|
pvRet = ExAllocatePoolWithTag(PoolType,
|
|
ulNumberOfBytes,
|
|
TAG_USBSCAN);
|
|
|
|
NumberOfAllocate++;
|
|
DebugTrace(TRACE_PROC_LEAVE,("USAllocatePool: Leaving.. pvRet = %x, Count=%d\n", pvRet, NumberOfAllocate));
|
|
return pvRet;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
USFreePool(
|
|
IN PVOID pvAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper for pool free. Check tag to avoid heap corruption
|
|
|
|
Arguments:
|
|
|
|
pvAddress - Pointer to the allocated memory
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
|
|
ULONG ulTag;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,("USFreePool: Enter..\n"));
|
|
|
|
ulTag = *((PULONG)pvAddress-1);
|
|
|
|
if( (TAG_USBSCAN == ulTag) || (TAG_USBD == ulTag) ){
|
|
DebugTrace(TRACE_STATUS,("USFreePool: Free memory. tag = %c%c%c%c\n",
|
|
((PUCHAR)&ulTag)[0],
|
|
((PUCHAR)&ulTag)[1],
|
|
((PUCHAR)&ulTag)[2],
|
|
((PUCHAR)&ulTag)[3] ))
|
|
} else {
|
|
DebugTrace(TRACE_WARNING,("USFreePool: WARNING!! Free memory. tag = %c%c%c%c\n",
|
|
((PUCHAR)&ulTag)[0],
|
|
((PUCHAR)&ulTag)[1],
|
|
((PUCHAR)&ulTag)[2],
|
|
((PUCHAR)&ulTag)[3] ))
|
|
}
|
|
|
|
ExFreePool(pvAddress);
|
|
|
|
NumberOfAllocate--;
|
|
DebugTrace(TRACE_PROC_LEAVE,("USFreePool: Leaving.. Status = VOID, Count=%d\n", NumberOfAllocate));
|
|
}
|
|
|
|
#endif // ORIGINAL_POOLTRACK
|