windows-nt/Source/XPSP1/NT/printscan/wia/kernel/usbscan/ioctl.c
2020-09-26 16:20:57 +08:00

1606 lines
52 KiB
C

/*++
Copyright (C) Microsoft Corporation, 1997 - 1999
Module Name:
ioctl.c
Abstract:
Author:
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include <stdio.h>
#include <stddef.h>
#include <wdm.h>
#include <usbscan.h>
#include "usbd_api.h"
#include "private.h"
//#include "missdef.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, USDeviceControl)
#pragma alloc_text(PAGE, USReadWriteRegisters)
#pragma alloc_text(PAGE, USCancelPipe)
#pragma alloc_text(PAGE, USAbortResetPipe)
#endif
#ifdef _WIN64
BOOLEAN
IoIs32bitProcess(
IN PIRP Irp
);
#endif // _WIN64
NTSTATUS
USDeviceControl(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
Arguments:
pDeviceObject - Device object for a device.
pIrp - DEVICE IOCTL irp
Return Value:
NT Status - STATUS_SUCCESS
--*/
{
PIO_STACK_LOCATION pIrpStack;
PIO_STACK_LOCATION pNextIrpStack;
PFILE_OBJECT fileObject;
PUSBSCAN_FILE_CONTEXT pFileContext;
ULONG IoControlCode;
PUSBSCAN_DEVICE_EXTENSION pde;
NTSTATUS Status;
PDRV_VERSION pVersion;
PDEVICE_DESCRIPTOR pDesc;
PUSBSCAN_GET_DESCRIPTOR pGetDesc;
PUSBSCAN_PIPE_CONFIGURATION pPipeConfig;
PVOID pBuffer;
IO_BLOCK LocalIoBlock;
IO_BLOCK_EX LocalIoBlockEx;
PIO_BLOCK pIoBlock;
PIO_BLOCK_EX pIoBlockEx;
ULONG InLength;
ULONG OutLength;
BOOLEAN fRead = FALSE;
BOOLEAN fAbort = TRUE;
ULONG i;
PURB pUrb;
PAGED_CODE();
DebugTrace(TRACE_PROC_ENTER,("USDeviceControl: Enter...\n"));
//
// Check arguments.
//
if( (NULL == pDeviceObject)
|| (NULL == pDeviceObject->DeviceExtension)
|| (NULL == pIrp) )
{
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Invalid parameter passed.\n"));
Status = STATUS_INVALID_PARAMETER;
DebugTrace(TRACE_PROC_LEAVE,("USDeviceControl: Leaving.. Status = %x.\n", Status));
return Status;
}
//
// Indicates I/O processing increase.
//
USIncrementIoCount( pDeviceObject );
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
if (FALSE == pde -> AcceptingRequests) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! IOCTL issued after device stopped/removed!\n"));
Status = STATUS_DELETE_PENDING;
pIrp -> IoStatus.Status = Status;
pIrp -> IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
goto USDeviceControl_return;
}
//
// Check device power state.
//
if (PowerDeviceD0 != pde -> CurrentDevicePowerState) {
DebugTrace(TRACE_WARNING,("USDeviceControl: WARNING!! Device is suspended.\n"));
Status = STATUS_DELETE_PENDING;
pIrp -> IoStatus.Status = Status;
pIrp -> IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
goto USDeviceControl_return;
}
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
pNextIrpStack = IoGetNextIrpStackLocation( pIrp );
IoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
InLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
OutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
pBuffer = pIrp -> AssociatedIrp.SystemBuffer;
fileObject = pIrpStack->FileObject;
pFileContext = fileObject->FsContext;
DebugTrace(TRACE_STATUS,("USDeviceControl: Control code 0x%x = ", IoControlCode));
switch (IoControlCode) {
case IOCTL_GET_VERSION:
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_GET_VERSION\n"));
if (OutLength < sizeof(DRV_VERSION) ) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Buffer(0x%x) too small(<0x%x)\n", OutLength, sizeof(DRV_VERSION)));
DEBUG_BREAKPOINT();
Status = STATUS_INVALID_PARAMETER;
break;
}
pVersion = (PDRV_VERSION)pBuffer;
pVersion->major = 1;
pVersion->minor = 0;
pVersion->internal = 0;
pIrp -> IoStatus.Information = sizeof(DRV_VERSION);
Status = STATUS_SUCCESS;
break;
case IOCTL_CANCEL_IO:
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_CANCEL_IO\n"));
fAbort = TRUE;
//
// Falling through to the next case, this is intentional. We want to reset pipe when
// cancel requested
//
case IOCTL_RESET_PIPE:
if(IOCTL_RESET_PIPE == IoControlCode){
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_RESET_PIPE\n"));
fAbort = FALSE;
}
//
// Validate buffer size
//
if (InLength < sizeof(PIPE_TYPE) ) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Pipe type buffer (0x%x bytes) too small\n" ,InLength));
Status = STATUS_INVALID_PARAMETER;
break;
}
Status = USCancelPipe(pDeviceObject,
pIrp,
*(PIPE_TYPE*)pBuffer,
fAbort);
break;
case IOCTL_WAIT_ON_DEVICE_EVENT:
{
ULONG Index;
ULONG Timeout;
PULONG pTimeout;
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_WAIT_ON_DEVICE_EVENT\n"));
Index = USGetPipeIndexToUse(pDeviceObject,
pIrp,
pde -> IndexInterrupt);
if (OutLength < pde -> PipeInfo[Index].MaximumPacketSize) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! User buffer(0x%x) too small(<)\n"
, OutLength
, pde -> PipeInfo[Index].MaximumPacketSize));
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Copy timeout value from file context.
//
Timeout = pFileContext->TimeoutEvent;
//
// If timeout value is 0, then never timeout.
//
if(0 == Timeout){
pTimeout = NULL;
} else {
DebugTrace(TRACE_STATUS,("USDeviceControl: Timeout is set to 0x%x sec.\n", Timeout));
pTimeout = &Timeout;
}
Status = USTransfer(pDeviceObject,
pIrp,
Index,
pIrp -> AssociatedIrp.SystemBuffer,
NULL,
pde -> PipeInfo[Index].MaximumPacketSize,
pTimeout);
//
// IRP should be completed in USTransfer or its completion routine.
//
goto USDeviceControl_return;
}
case IOCTL_READ_REGISTERS:
fRead = TRUE;
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_READ_REGISTERS\n"));
case IOCTL_WRITE_REGISTERS:{
if (IOCTL_WRITE_REGISTERS == IoControlCode) {
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_WRITE_REGISTERS\n"));
fRead = FALSE;
}
#ifdef _WIN64
if(IoIs32bitProcess(pIrp)){
PIO_BLOCK_32 pIoBlock32;
if (InLength < sizeof(IO_BLOCK_32) ) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Invalid input 32bit buffer size(0x%x<0x%x)\n"
, InLength,
sizeof(IO_BLOCK_32)));
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Copy all parameters from 32bit structure.
//
pIoBlock32 = (PIO_BLOCK_32)pBuffer;
pIoBlock = &LocalIoBlock;
pIoBlock -> uOffset = pIoBlock32 -> uOffset;
pIoBlock -> uLength = pIoBlock32 -> uLength;
pIoBlock -> pbyData = pIoBlock32 -> pbyData;
pIoBlock -> uIndex = pIoBlock32 -> uIndex;
} else { // if(IoIs32bitProcess(pIrp))
#endif // _WIN64
if (InLength < sizeof(IO_BLOCK) ) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Invalid input buffer size(0x%x<0x%x)\n"
, InLength,
sizeof(IO_BLOCK)));
Status = STATUS_INVALID_PARAMETER;
break;
}
pIoBlock = (PIO_BLOCK)pBuffer;
#ifdef _WIN64
} // if(IoIs32bitProcess(pIrp))
#endif // _WIN64
if(TRUE == fRead){
//
// Check the size of Output buffer.
//
if (OutLength < pIoBlock -> uLength) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Out buffer(0x%x) too small(<0x%x)\n"
, OutLength
, pIoBlock -> uLength));
Status = STATUS_INVALID_PARAMETER;
break;
} // if (OutLength < pIoBlock -> uLength)
} // if(TRUE == fRead)
pIrp -> IoStatus.Information = pIoBlock -> uLength;
//
// Caller gives us a pointer, embedded into IOCTL buffer. If call is made from
// user-mode , we need to validate that given pointer is readable.
//
if (pIrp->RequestorMode != KernelMode) {
try {
ProbeForRead(pIoBlock->pbyData,
pIoBlock -> uLength,
sizeof(UCHAR));
} except(EXCEPTION_EXECUTE_HANDLER) {
DebugTrace(TRACE_ERROR,("USDeviceControl: Read/Write registers buffer pointer is invalid\n"));
DEBUG_BREAKPOINT();
Status = GetExceptionCode();
pIrp -> IoStatus.Information = 0;
break;
} // except
} // !kernelmode
//
// Now go to worker function
//
Status = USReadWriteRegisters(pDeviceObject,
pIoBlock,
fRead,
InLength);
if (STATUS_SUCCESS != Status) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! USReadWriteRegisters failed\n"));
DEBUG_BREAKPOINT();
pIrp -> IoStatus.Information = 0;
}
break;
} // case IOCTL_WRITE_REGISTERS:
case IOCTL_GET_CHANNEL_ALIGN_RQST:
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_GET_CHANNEL_ALIGN_REQUEST\n"));
if (OutLength < sizeof(CHANNEL_INFO) ) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Buffer(0x%x) too small(<0x%x)\n"
, OutLength
,sizeof(CHANNEL_INFO)));
Status = STATUS_INVALID_PARAMETER;
break;
}
pIoBlock = (PIO_BLOCK)pBuffer;
RtlZeroMemory((PCHANNEL_INFO)pIoBlock, sizeof(CHANNEL_INFO));
for (i = 0; i < pde -> NumberOfPipes; i++) {
//
// Have to check which pipe to use
//
ULONG Index;
Index = USGetPipeIndexToUse(pDeviceObject,
pIrp,
i);
switch (pde -> PipeInfo[Index].PipeType) {
case USB_ENDPOINT_TYPE_INTERRUPT:
((PCHANNEL_INFO)pIoBlock)->EventChannelSize = pde -> PipeInfo[Index].MaximumPacketSize;
break;
case USB_ENDPOINT_TYPE_BULK:
if (pde -> pEndpointDescriptor[Index].bEndpointAddress & BULKIN_FLAG) {
((PCHANNEL_INFO)pIoBlock) -> uReadDataAlignment = pde -> PipeInfo[Index].MaximumPacketSize;
} else {
((PCHANNEL_INFO)pIoBlock) -> uWriteDataAlignment = pde -> PipeInfo[Index].MaximumPacketSize;
}
break;
}
}
pIrp -> IoStatus.Information = sizeof(CHANNEL_INFO);
Status = STATUS_SUCCESS;
break;
case IOCTL_GET_DEVICE_DESCRIPTOR:
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_GET_DEVICE_DESCRIPTOR\n"));
if (OutLength < sizeof(DEVICE_DESCRIPTOR)) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Out buffer(0x%x) is too small(<0x%x)\n"
, OutLength
, sizeof(DEVICE_DESCRIPTOR)));
Status = STATUS_INVALID_PARAMETER_6;
break;
}
pDesc = (PDEVICE_DESCRIPTOR)pBuffer;
pDesc -> usVendorId = pde -> pDeviceDescriptor -> idVendor;
pDesc -> usProductId = pde -> pDeviceDescriptor -> idProduct;
pDesc -> usBcdDevice = pde -> pDeviceDescriptor -> bcdDevice;
DebugTrace(TRACE_STATUS,("USDeviceControl: Vendor ID:%d\n", pDesc -> usVendorId));
DebugTrace(TRACE_STATUS,("USDeviceControl: Product ID:%d\n", pDesc -> usProductId));
DebugTrace(TRACE_STATUS,("USDeviceControl: BcdDevice:%d\n", pDesc -> usBcdDevice));
pIrp -> IoStatus.Information = sizeof(DEVICE_DESCRIPTOR);
Status = STATUS_SUCCESS;
break;
case IOCTL_GET_USB_DESCRIPTOR:
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_GET_USB_DESCRIPTOR\n"));
if (OutLength < sizeof(USBSCAN_GET_DESCRIPTOR)) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Out buffer(0x%x) is too small(<0x%x)\n"
, OutLength
, sizeof(USBSCAN_GET_DESCRIPTOR)));
Status = STATUS_INVALID_PARAMETER_6;
break;
}
pGetDesc = (PUSBSCAN_GET_DESCRIPTOR)pBuffer;
pUrb = USAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (NULL == pUrb) {
DebugTrace(TRACE_CRITICAL,("USDeviceControl: ERROR!! Can't allocate control descriptor URB.\n"));
DEBUG_BREAKPOINT();
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
#ifdef DEBUG
switch(pGetDesc -> DescriptorType){
case USB_DEVICE_DESCRIPTOR_TYPE:
DebugTrace(TRACE_STATUS,("USDeviceControl: USB_DEVICE_DESCRIPTOR_TYPE\n"));
break;
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
DebugTrace(TRACE_STATUS,("USDeviceControl: USB_CONFIGURATION_DESCRIPTOR_TYPE\n"));
break;
case USB_STRING_DESCRIPTOR_TYPE:
DebugTrace(TRACE_STATUS,("USDeviceControl: USB_STRING_DESCRIPTOR_TYPE\n"));
break;
default:
DebugTrace(TRACE_WARNING,("USDeviceControl: WARNING!! 0x%x = Undefined.\n", pGetDesc -> DescriptorType));
Status = STATUS_INVALID_PARAMETER_3;
USFreePool(pUrb);
pUrb = NULL;
pIrp -> IoStatus.Information = 0;
goto USDeviceControl_return;
}
DebugTrace(TRACE_STATUS, ("USDeviceControl: Index :%d\n",pGetDesc -> Index));
DebugTrace(TRACE_STATUS, ("USDeviceControl: LanguageID :%d\n", pGetDesc -> LanguageId));
#endif //DEBUG
UsbBuildGetDescriptorRequest(pUrb,
(USHORT)sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
pGetDesc -> DescriptorType,
pGetDesc -> Index,
pGetDesc -> LanguageId,
pBuffer,
NULL,
OutLength,
NULL);
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
#ifdef DEBUG
if ( (STATUS_SUCCESS == Status)
// && (USB_DEVICE_DESCRIPTOR_TYPE == pGetDesc -> DescriptorType)
)
{
PUSB_DEVICE_DESCRIPTOR pDeviceDescriptor;
pDeviceDescriptor = (PUSB_DEVICE_DESCRIPTOR)pBuffer;
DebugTrace(TRACE_STATUS,("USDeviceControl: Device Descriptor = %x, len %x\n",
pDeviceDescriptor,
pUrb->UrbControlDescriptorRequest.TransferBufferLength));
DebugTrace(TRACE_STATUS,("USDeviceControl: USBSCAN Device Descriptor:\n"));
DebugTrace(TRACE_STATUS,("USDeviceControl: -------------------------\n"));
DebugTrace(TRACE_STATUS,("USDeviceControl: bLength %d\n", pDeviceDescriptor->bLength));
DebugTrace(TRACE_STATUS,("USDeviceControl: bDescriptorType 0x%x\n", pDeviceDescriptor->bDescriptorType));
DebugTrace(TRACE_STATUS,("USDeviceControl: bcdUSB 0x%x\n", pDeviceDescriptor->bcdUSB));
DebugTrace(TRACE_STATUS,("USDeviceControl: bDeviceClass 0x%x\n", pDeviceDescriptor->bDeviceClass));
DebugTrace(TRACE_STATUS,("USDeviceControl: bDeviceSubClass 0x%x\n", pDeviceDescriptor->bDeviceSubClass));
DebugTrace(TRACE_STATUS,("USDeviceControl: bDeviceProtocol 0x%x\n", pDeviceDescriptor->bDeviceProtocol));
DebugTrace(TRACE_STATUS,("USDeviceControl: bMaxPacketSize0 0x%x\n", pDeviceDescriptor->bMaxPacketSize0));
DebugTrace(TRACE_STATUS,("USDeviceControl: idVendor 0x%x\n", pDeviceDescriptor->idVendor));
DebugTrace(TRACE_STATUS,("USDeviceControl: idProduct 0x%x\n", pDeviceDescriptor->idProduct));
DebugTrace(TRACE_STATUS,("USDeviceControl: bcdDevice 0x%x\n", pDeviceDescriptor->bcdDevice));
DebugTrace(TRACE_STATUS,("USDeviceControl: iManufacturer 0x%x\n", pDeviceDescriptor->iManufacturer));
DebugTrace(TRACE_STATUS,("USDeviceControl: iProduct 0x%x\n", pDeviceDescriptor->iProduct));
DebugTrace(TRACE_STATUS,("USDeviceControl: iSerialNumber 0x%x\n", pDeviceDescriptor->iSerialNumber));
DebugTrace(TRACE_STATUS,("USDeviceControl: bNumConfigurations 0x%x\n", pDeviceDescriptor->bNumConfigurations));
} else {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR! Status = %d\n", Status));
}
#endif //DEBUG
USFreePool(pUrb);
pUrb = NULL;
pIrp -> IoStatus.Information = ((PUSB_DEVICE_DESCRIPTOR)pBuffer)->bLength;
break;
case IOCTL_SEND_USB_REQUEST:
{
//
// Generic pass-through mechanism for USB vendor requests.
//
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_SEND_USB_REQUEST\n"));
//
// Validate length parameters.
//
#ifdef _WIN64
if(IoIs32bitProcess(pIrp)){
PIO_BLOCK_EX_32 pIoBlockEx32;
if (InLength < sizeof(IO_BLOCK_EX_32) ) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Invalid input 32bit buffer size(0x%x<0x%x)\n"
, InLength,
sizeof(IO_BLOCK_EX_32)));
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Copy all parameters from 32bit structure.
//
pIoBlockEx32 = (PIO_BLOCK_EX_32)pBuffer;
pIoBlockEx = &LocalIoBlockEx;
pIoBlockEx -> uOffset = pIoBlockEx32 -> uOffset;
pIoBlockEx -> uLength = pIoBlockEx32 -> uLength;
pIoBlockEx -> pbyData = pIoBlockEx32 -> pbyData;
pIoBlockEx -> uIndex = pIoBlockEx32 -> uIndex;
pIoBlockEx -> bRequest = pIoBlockEx32 -> bRequest;
pIoBlockEx -> bmRequestType = pIoBlockEx32 -> bmRequestType;
pIoBlockEx -> fTransferDirectionIn = pIoBlockEx32 -> fTransferDirectionIn;
} else { // if(IoIs32bitProcess(pIrp))
#endif // _WIN64
if (InLength < sizeof(IO_BLOCK_EX) ) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! I/O buffer(0x%x) too small(<0x%x)\n"
, InLength
, sizeof(IO_BLOCK_EX)));
Status = STATUS_INVALID_PARAMETER;
break;
}
pIoBlockEx = (PIO_BLOCK_EX)pBuffer;
#ifdef _WIN64
} // if(IoIs32bitProcess(pIrp))
#endif // _WIN64
if (pIoBlockEx->fTransferDirectionIn) {
//
// Check output buffer length is valid.
//
if (OutLength < pIoBlockEx -> uLength) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! OutLength too small\n"));
DEBUG_BREAKPOINT();
Status = STATUS_INVALID_PARAMETER;
pIrp -> IoStatus.Information = 0;
break;
}
pIrp -> IoStatus.Information = pIoBlockEx -> uLength;
} else {
//
// No output to the caller.
//
pIrp -> IoStatus.Information = 0;
}
//
// Validate user buffer.
//
if (pIrp->RequestorMode != KernelMode) {
try {
ProbeForRead(pIoBlockEx->pbyData,
pIoBlockEx->uLength,
sizeof(UCHAR));
} except(EXCEPTION_EXECUTE_HANDLER) {
DebugTrace(TRACE_ERROR,("USDeviceControl: User buffer pointer is invalid\n"));
Status = GetExceptionCode();
pIrp -> IoStatus.Information = 0;
break;
} // except
} // !kernelmode
//
// Now go to worker function
//
Status = USPassThruUSBRequest(pDeviceObject,
(PIO_BLOCK_EX)pBuffer,
InLength,
OutLength
);
if (STATUS_SUCCESS != Status) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! USPassThruUSBRequest failed\n"));
DEBUG_BREAKPOINT();
pIrp -> IoStatus.Information = 0;
}
break;
} // case IOCTL_SEND_USB_REQUEST:
case IOCTL_SEND_USB_REQUEST_PTP:
{
//
// Generic pass-through mechanism for USB vendor requests.
//
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_SEND_USB_REQUEST_PTP\n"));
//
// Validate length parameters.
//
#ifdef _WIN64
if(IoIs32bitProcess(pIrp)){
PIO_BLOCK_EX_32 pIoBlockEx32;
if (InLength < sizeof(IO_BLOCK_EX_32) ) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Invalid input 32bit buffer size(0x%x<0x%x)\n"
, InLength,
sizeof(IO_BLOCK_EX_32)));
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Copy all parameters from 32bit structure.
//
pIoBlockEx32 = (PIO_BLOCK_EX_32)pBuffer;
pIoBlockEx = &LocalIoBlockEx;
pIoBlockEx -> uOffset = pIoBlockEx32 -> uOffset;
pIoBlockEx -> uLength = pIoBlockEx32 -> uLength;
pIoBlockEx -> pbyData = pIoBlockEx32 -> pbyData;
pIoBlockEx -> uIndex = pIoBlockEx32 -> uIndex;
pIoBlockEx -> bRequest = pIoBlockEx32 -> bRequest;
pIoBlockEx -> bmRequestType = pIoBlockEx32 -> bmRequestType;
pIoBlockEx -> fTransferDirectionIn = pIoBlockEx32 -> fTransferDirectionIn;
} else { // if(IoIs32bitProcess(pIrp))
#endif // _WIN64
if (InLength < sizeof(IO_BLOCK_EX) ) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! I/O buffer(0x%x) too small(<0x%x)\n"
, InLength
, sizeof(IO_BLOCK_EX)));
Status = STATUS_INVALID_PARAMETER;
break;
}
pIoBlockEx = (PIO_BLOCK_EX)pBuffer;
#ifdef _WIN64
} // if(IoIs32bitProcess(pIrp))
#endif // _WIN64
if (pIoBlockEx->fTransferDirectionIn) {
//
// Check output buffer length is valid.
//
if (OutLength < pIoBlockEx -> uLength) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! OutLength too small\n"));
DEBUG_BREAKPOINT();
Status = STATUS_INVALID_PARAMETER;
pIrp -> IoStatus.Information = 0;
break;
}
pIrp -> IoStatus.Information = pIoBlockEx -> uLength;
} else {
//
// No output to the caller.
//
pIrp -> IoStatus.Information = 0;
}
//
// Validate user buffer.
//
if (pIrp->RequestorMode != KernelMode) {
try {
ProbeForRead(pIoBlockEx->pbyData,
pIoBlockEx->uLength,
sizeof(UCHAR));
} except(EXCEPTION_EXECUTE_HANDLER) {
DebugTrace(TRACE_ERROR,("USDeviceControl: User buffer pointer is invalid\n"));
Status = GetExceptionCode();
pIrp -> IoStatus.Information = 0;
break;
} // except
} // !kernelmode
//
// Now go to worker function
//
Status = USPassThruUSBRequestPTP(pDeviceObject,
(PIO_BLOCK_EX)pBuffer,
InLength,
OutLength);
if (STATUS_SUCCESS != Status) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! USPassThruUSBRequestPTP failed\n"));
DEBUG_BREAKPOINT();
pIrp -> IoStatus.Information = 0;
}
break;
} // case IOCTL_SEND_USB_REQUEST_PTP:
case IOCTL_GET_PIPE_CONFIGURATION:
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_GET_PIPE_CONFIGURATION\n"));
//
// Check output buffer length
//
if (OutLength < sizeof(USBSCAN_PIPE_CONFIGURATION)) {
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! GetPipeConfig buffer(0x%x) too small(<0x%x)\n"
, OutLength
, sizeof(USBSCAN_PIPE_CONFIGURATION)));
Status = STATUS_INVALID_PARAMETER_6;
break;
}
//
// Copy Pipe configuration to user buffer.
//
pPipeConfig = (PUSBSCAN_PIPE_CONFIGURATION)pBuffer;
RtlZeroMemory(pPipeConfig, sizeof(USBSCAN_PIPE_CONFIGURATION));
pPipeConfig->NumberOfPipes = pde->NumberOfPipes;
for(i=0; i < pPipeConfig->NumberOfPipes; i++){
pPipeConfig->PipeInfo[i].MaximumPacketSize = pde->PipeInfo[i].MaximumPacketSize;
pPipeConfig->PipeInfo[i].EndpointAddress = pde->PipeInfo[i].EndpointAddress;
pPipeConfig->PipeInfo[i].Interval = pde->PipeInfo[i].Interval;
pPipeConfig->PipeInfo[i].PipeType = pde->PipeInfo[i].PipeType;
}
pIrp -> IoStatus.Information = sizeof(USBSCAN_PIPE_CONFIGURATION);
Status = STATUS_SUCCESS;
break;
case IOCTL_SET_TIMEOUT:
DebugTrace(TRACE_STATUS,("USDeviceControl: IOCTL_SET_TIMEOUT\n"));
//
// Make sure input buffer size is big enough.
//
if(sizeof(USBSCAN_TIMEOUT) > InLength){
//
// Incorrect Input buffer size.
//
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Invalid input buffer size\n"));
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Copy timeout value.
//
pFileContext -> TimeoutRead = ((PUSBSCAN_TIMEOUT)pBuffer) -> TimeoutRead;
pFileContext -> TimeoutWrite = ((PUSBSCAN_TIMEOUT)pBuffer) -> TimeoutWrite;
pFileContext -> TimeoutEvent = ((PUSBSCAN_TIMEOUT)pBuffer) -> TimeoutEvent;
pIrp -> IoStatus.Information = 0;
Status = STATUS_SUCCESS;
break;
default:
DebugTrace(TRACE_ERROR,("USDeviceControl: ERROR!! Unsupported IOCTL\n"));
Status = STATUS_NOT_SUPPORTED;
break;
}
pIrp -> IoStatus.Status = Status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
USDeviceControl_return:
USDecrementIoCount(pDeviceObject);
DebugTrace(TRACE_PROC_LEAVE,("USDeviceControl: Leaving.. Status = 0x%x\n", Status));
return Status;
} // end USDeviceControl()
NTSTATUS
USReadWriteRegisters(
IN PDEVICE_OBJECT pDeviceObject,
IN PIO_BLOCK pIoBlock,
IN BOOLEAN fRead,
IN ULONG IoBlockSize
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
PUSBSCAN_DEVICE_EXTENSION pde;
PURB pUrb;
ULONG siz;
UCHAR Request;
PVOID pBuffer = NULL;
//USHORT uIndex;
unsigned uIndex;
PAGED_CODE();
DebugTrace(TRACE_PROC_ENTER,("USReadWriteRegisters: Enter..\n"));
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
//
// Allocate URB
//
siz = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
pUrb = USAllocatePool(NonPagedPool, siz);
if (NULL == pUrb) {
DebugTrace(TRACE_CRITICAL,("USReadWriteRegisters: ERROR!! cannot allocated URB\n"));
DEBUG_BREAKPOINT();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto USReadWriteRegisters_return;
}
RtlZeroMemory(pUrb, siz);
//
// Setup URB
//
Request = REGISTER_AREA;
if (pIoBlock -> uLength > 1) {
DebugTrace(TRACE_STATUS,("USReadWriteRegisters: ULength > 1, turning on automatic increment\n"));
Request |= OPCODE_SEQ_TRANSFER; // automatic address increment after the read
} else {
Request |= OPCODE_SINGLE_ADDR_TRANSFER; // no address increment after the read
}
//
// Reading registers will read into pIoBlock itself.
//
pBuffer = pIoBlock;
//
// If we are writing registers, then we need to make a copy of the
// register block into a non-paged block of memory before handing it off
// to usbd.
//
if (!fRead) {
DebugTrace(TRACE_STATUS,("USReadWriteRegisters: Write request, allocating non-paged reg buffer, len = %d\n",pIoBlock->uLength));
pBuffer = USAllocatePool(NonPagedPool, pIoBlock->uLength);
if (NULL == pBuffer) {
DebugTrace(TRACE_CRITICAL,("USReadWriteRegisters: ERROR!! cannot allocate write reg buffer\n"));
DEBUG_BREAKPOINT();
USFreePool(pUrb);
pUrb = NULL;
Status = STATUS_INSUFFICIENT_RESOURCES;
goto USReadWriteRegisters_return;
}
//
// Caller gives us a pointer, embedded into IOCTL buffer. We need to
// validate that given pointer is readable.
//
try{
RtlCopyMemory(pBuffer,
pIoBlock->pbyData,
pIoBlock->uLength);
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// Caller buffer is not valid, or worse..
//
DebugTrace(TRACE_ERROR,("USReadWriteRegisters: ERROR!! Copying caller buffer failed.\n"));
DEBUG_BREAKPOINT();
Status = GetExceptionCode();
//
// Clear allocated pool
//
USFreePool(pUrb);
USFreePool(pBuffer);
pUrb = NULL;
pBuffer = NULL;
goto USReadWriteRegisters_return;
}
}
//
// If the IoBlock is new style (Intel has added a uIndex field to the end of it),
// then make sure we pass the corrected uIndex value to usbd.
//
uIndex = 0;
if (IoBlockSize == sizeof(IO_BLOCK)) {
DebugTrace(TRACE_STATUS,("USReadWriteRegisters: New (intel) style IoBlock -- setting uIndex to pIoBlock -> uIndex\n"));
uIndex = pIoBlock -> uIndex;
}
UsbBuildVendorClassSpecificCommand(pUrb,
fRead ? USBD_TRANSFER_DIRECTION_IN : 0,
pIoBlock->uLength,
pBuffer,
NULL,
fRead ? 0xc0 : 0x40,
Request,
(SHORT)pIoBlock->uOffset,
(USHORT)uIndex);
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
if (!fRead) {
DebugTrace(TRACE_STATUS,("USReadWriteRegisters: freeing temp reg buffer\n"));
USFreePool(pBuffer);
pBuffer = NULL;
}
USFreePool(pUrb);
pUrb = NULL;
USReadWriteRegisters_return:
if(!NT_SUCCESS(Status)){
DebugTrace(TRACE_ERROR,("USReadWriteRegisters: ERROR!! Still had unfreed pointer. Free it...\n"));
if(pUrb){
USFreePool(pUrb);
}
if( (pBuffer)
&& (!fRead ) )
{
USFreePool(pBuffer);
}
}
DebugTrace(TRACE_PROC_LEAVE,("USReadWriteRegisters: Leaving.. Status = 0x%x\n", Status));
return Status;
}
NTSTATUS
USCancelPipe(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PIPE_TYPE PipeType,
IN BOOLEAN fAbort // TRUE = Abort, FALSE = Reset
)
/*++
Routine Description:
Cansel URB or reset pipe. If PipeType is PIPE_ALL, it applies to every pipes a device has.
If not, it applies to only one default pipe even if a device supports multipul same type of pipes.
Arguments:
pDeviceObject - Pointer to Device Object
pIrp - Can be NULL if PipeType is ALL_PIPE
PipeType - Specifies type of pipe
fAbort - Specifies type of operation
Return Value:
Returns status
--*/
{
NTSTATUS Status, temp;
PUSBSCAN_DEVICE_EXTENSION pde;
PAGED_CODE();
// DebugTrace(TRACE_PROC_ENTER,("USCancelPipe: Enter.. - "));
Status = STATUS_SUCCESS;
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
switch (PipeType) {
case EVENT_PIPE:
DebugTrace(TRACE_STATUS,("USCancelPipe: EVENT_PIPE\n"));
if(NULL == pIrp){
DebugTrace(TRACE_ERROR,("USCancelPipe: ERROR!! pIrp not valid\n"));
break;
}
if (-1 == pde -> IndexInterrupt) {
DebugTrace(TRACE_ERROR,("USCancelPipe: ERROR!! Interrupt pipe not valid\n"));
DEBUG_BREAKPOINT();
Status = STATUS_NOT_SUPPORTED;
break;
}
Status = USAbortResetPipe(pDeviceObject,
USGetPipeIndexToUse(pDeviceObject, pIrp, pde -> IndexInterrupt),
fAbort);
DebugTrace(TRACE_STATUS,("Event Pipe aborted/reset, Status = 0x%x\n",Status));
break;
case READ_DATA_PIPE:
DebugTrace(TRACE_STATUS,("USCancelPipe: READ_DATA_PIPE\n"));
if(NULL == pIrp){
DebugTrace(TRACE_ERROR,("USCancelPipe: ERROR!! pIrp not valid\n"));
break;
}
if (-1 == pde -> IndexBulkIn) {
DebugTrace(TRACE_ERROR,("USCancelPipe: ERROR!! bulk-in pipe not valid\n"));
DEBUG_BREAKPOINT();
Status = STATUS_NOT_SUPPORTED;
break;
}
Status = USAbortResetPipe(pDeviceObject,
USGetPipeIndexToUse(pDeviceObject, pIrp, pde -> IndexBulkIn),
fAbort);
DebugTrace(TRACE_STATUS,("USCancelPipe: Read Pipe aborted/reset, Status = 0x%x\n",Status));
break;
case WRITE_DATA_PIPE:
DebugTrace(TRACE_STATUS,("USCancelPipe: WRITE_DATA_PIPE\n"));
if(NULL == pIrp){
DebugTrace(TRACE_ERROR,("USCancelPipe: ERROR!! pIrp not valid\n"));
break;
}
if (-1 == pde -> IndexBulkOut) {
DebugTrace(TRACE_ERROR,("USCancelPipe: ERROR!! bulk-out pipe not valid\n"));
DEBUG_BREAKPOINT();
Status = STATUS_NOT_SUPPORTED;
break;
}
Status = USAbortResetPipe(pDeviceObject,
USGetPipeIndexToUse(pDeviceObject, pIrp, pde -> IndexBulkOut),
fAbort);
DebugTrace(TRACE_STATUS,("Write Pipe aborted/reset, Status = 0x%x\n",Status));
break;
case ALL_PIPE:
{
ULONG i;
DebugTrace(TRACE_STATUS,("USCancelPipe: ALL_PIPE\n"));
for(i=0; i < pde -> NumberOfPipes; i++){
temp = USAbortResetPipe(pDeviceObject, i, fAbort);
// DebugTrace(TRACE_STATUS,("USCancelPipe: pipe[%d] aborted/reset, Status = 0x%x\n", i, temp));
if(STATUS_SUCCESS != temp){
Status = temp;
}
}
break;
}
default:
DebugTrace(TRACE_ERROR,("USCancelPipe: ERROR!! INVALID_PIPE\n"));
Status = STATUS_INVALID_PARAMETER;
break;
}
DebugTrace(TRACE_PROC_LEAVE,("USCancelPipe: Leaving.. Status = 0x%x\n", Status));
return Status;
}
NTSTATUS
USAbortResetPipe(
IN PDEVICE_OBJECT pDeviceObject,
IN ULONG uIndex,
IN BOOLEAN fAbort // TRUE = Abort, FALSE = Reset
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS StatusReset = STATUS_SUCCESS;
PUSBSCAN_DEVICE_EXTENSION pde;
PURB pUrb;
ULONG siz;
PAGED_CODE();
DebugTrace(TRACE_PROC_ENTER,("USAbortResetPipe: Enter... \n"));
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
pUrb = NULL;
//
// Allocate URB
//
siz = sizeof(struct _URB_PIPE_REQUEST);
pUrb = USAllocatePool(NonPagedPool, siz);
if (NULL == pUrb) {
DebugTrace(TRACE_ERROR,("USAbortResetPipe: ERROR!! cannot allocated URB\n"));
DEBUG_BREAKPOINT();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto USAbortResetPipe_return;
}
RtlZeroMemory(pUrb, siz);
if (fAbort) {
DebugTrace(TRACE_STATUS,("USAbortResetPipe: Aborting pipe[%d]\n", uIndex));
//
// Issue abort pipe call to USBD.
//
UsbBuildAbortPipeRequest(pUrb,
siz,
pde -> PipeInfo[uIndex].PipeHandle);
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
if (STATUS_SUCCESS != Status) {
DebugTrace(TRACE_ERROR,("USAbortResetPipe: ERROR!! Abort pipe failed. Status = 0x%x\n",Status));
goto USAbortResetPipe_return;
}
UsbBuildResetPipeRequest(pUrb,
siz,
pde -> PipeInfo[uIndex].PipeHandle);
StatusReset = USBSCAN_CallUSBD(pDeviceObject, pUrb);
if (STATUS_SUCCESS != StatusReset) {
DebugTrace(TRACE_ERROR,("USAbortResetPipe: ERROR!! resetting pipe. Status = 0x%x\n",StatusReset));
goto USAbortResetPipe_return;
}
} else {
DebugTrace(TRACE_STATUS,("Reseting pipe[%d]\n", uIndex));
//
// Issue reset pipe call to USBD.
//
UsbBuildResetPipeRequest(pUrb,
siz,
pde -> PipeInfo[uIndex].PipeHandle);
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
if (STATUS_SUCCESS != Status) {
DebugTrace(TRACE_ERROR,("USAbortResetPipe: ERROR!! Reset pipe failed. Status = 0x%x\n",Status));
goto USAbortResetPipe_return;
}
}
USAbortResetPipe_return:
//
// Clean up.
//
if(pUrb){
USFreePool(pUrb);
}
DebugTrace(TRACE_PROC_LEAVE,("USAbortResetPipe: Leaving.. Status = 0x%x\n", Status));
return Status;
}
NTSTATUS
USPassThruUSBRequest(
IN PDEVICE_OBJECT pDeviceObject,
IN PIO_BLOCK_EX pIoBlockEx,
IN ULONG InLength,
IN ULONG OutLength
)
/*++
Routine Description:
Implements generic pass-thru for vendor request to USBD
Arguments:
pDeviceObject - Device object
pIoBlockEx - Pointer to I/O block as described in USBSCAN.H, passed from user mode client
InLength - In length from IRP
OutLength - Out length from IRP
Return Value:
NTSTATUS type
--*/
{
NTSTATUS Status;
PUSBSCAN_DEVICE_EXTENSION pde;
PURB pUrb;
ULONG siz;
PVOID pBuffer;
BOOLEAN fDirectionIn;
PAGED_CODE();
DebugTrace(TRACE_PROC_ENTER,("USPassThruUSBRequest: Enter..\n"));
//
// Initialize local variable.
//
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
Status = STATUS_SUCCESS;
pUrb = NULL;
pBuffer = NULL;
fDirectionIn = TRUE;
//
// Allocate memory for URB
//
siz = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
pUrb = USAllocatePool(NonPagedPool, siz);
if (NULL == pUrb) {
DebugTrace(TRACE_CRITICAL,("USPassThruUSBRequest: ERROR!! cannot allocated URB\n"));
DEBUG_BREAKPOINT();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto USPassThruUSBRequest_return;
}
RtlZeroMemory(pUrb, siz);
//
// Setup URB
//
pBuffer = pIoBlockEx;
//
// If we are writing data, then we need to make a copy of the
// register block into a non-paged block of memory before handing it off
// to usbd.
//
if (!pIoBlockEx->fTransferDirectionIn) {
DebugTrace(TRACE_STATUS,("USPassThruUSBRequest: Write request, allocating non-paged buffer, len = %d\n",pIoBlockEx->uLength));
fDirectionIn = FALSE;
if ( pIoBlockEx->uLength ) {
pBuffer = USAllocatePool(NonPagedPool, pIoBlockEx->uLength);
if (NULL == pBuffer) {
DebugTrace(TRACE_CRITICAL,("USPassThruUSBRequest: ERROR!! cannot allocate write buffer"));
DEBUG_BREAKPOINT();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto USPassThruUSBRequest_return;
}
//
// Caller gives us a pointer, embedded into IOCTL buffer. We need to
// validate that given pointer is readable.
//
try{
RtlCopyMemory(pBuffer,
pIoBlockEx->pbyData,
pIoBlockEx->uLength);
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// Caller buffer is not valid, or worse..
//
DebugTrace(TRACE_ERROR,("USPassThruUSBRequest: ERROR!! Copying caller buffer failed.\n"));
DEBUG_BREAKPOINT();
Status = GetExceptionCode();
goto USPassThruUSBRequest_return;
}
} else {
//
// Zero length buffer used for Write , IHV claim that's useful.
//
pBuffer = NULL;
} // if ( pIoBlockEx->uLength )
}
UsbBuildVendorClassSpecificCommand(pUrb,
pIoBlockEx->fTransferDirectionIn ? USBD_TRANSFER_DIRECTION_IN : 0,
pIoBlockEx->uLength,
pBuffer,
NULL,
pIoBlockEx->bmRequestType,
pIoBlockEx->bRequest,
(SHORT)pIoBlockEx->uOffset,
(USHORT)pIoBlockEx -> uIndex
);
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
USPassThruUSBRequest_return:
//
// Clean up.
//
if(NULL != pUrb){
DebugTrace(TRACE_STATUS,("USPassThruUSBRequest: Free USB Request Block.\n"));
USFreePool(pUrb);
}
if( (!fDirectionIn)
&& (NULL != pBuffer) )
{
DebugTrace(TRACE_STATUS,("USPassThruUSBRequest: Free temp buffer.\n"));
USFreePool(pBuffer);
}
DebugTrace(TRACE_PROC_LEAVE,("USPassThruUSBRequest: Leaving.. Status = 0x%x\n", Status));
return Status;
}
NTSTATUS
USPassThruUSBRequestPTP(
IN PDEVICE_OBJECT pDeviceObject,
IN PIO_BLOCK_EX pIoBlockEx,
IN ULONG InLength,
IN ULONG OutLength
)
/*++
Routine Description:
Implements generic pass-thru for vendor request to USBD
Arguments:
pDeviceObject - Device object
pIoBlockEx - Pointer to I/O block as described in USBSCAN.H, passed from user mode client
InLength - In length from IRP
OutLength - Out length from IRP
Return Value:
NTSTATUS type
--*/
{
NTSTATUS Status;
PUSBSCAN_DEVICE_EXTENSION pde;
PURB pUrb;
ULONG siz;
PVOID pBuffer;
BOOLEAN fDirectionIn;
USHORT usUsbFunction;
PAGED_CODE();
DebugTrace(TRACE_PROC_ENTER,("USPassThruUSBRequest: Enter..\n"));
//
// Initialize local variable.
//
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
Status = STATUS_SUCCESS;
pUrb = NULL;
pBuffer = NULL;
fDirectionIn = TRUE;
usUsbFunction = 0;
//
// Allocate memory for URB
//
siz = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
pUrb = USAllocatePool(NonPagedPool, siz);
if (NULL == pUrb) {
DebugTrace(TRACE_CRITICAL,("USPassThruUSBRequest: ERROR!! cannot allocated URB\n"));
DEBUG_BREAKPOINT();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto USPassThruUSBRequest_return;
}
RtlZeroMemory(pUrb, siz);
//
// Setup URB
//
pBuffer = pIoBlockEx;
//
// If we are writing data, then we need to make a copy of the
// register block into a non-paged block of memory before handing it off
// to usbd.
//
if (!pIoBlockEx->fTransferDirectionIn) {
DebugTrace(TRACE_STATUS,("USPassThruUSBRequest: Write request, allocating non-paged buffer, len = %d\n",pIoBlockEx->uLength));
fDirectionIn = FALSE;
if ( pIoBlockEx->uLength ) {
pBuffer = USAllocatePool(NonPagedPool, pIoBlockEx->uLength);
if (NULL == pBuffer) {
DebugTrace(TRACE_CRITICAL,("USPassThruUSBRequest: ERROR!! cannot allocate write buffer"));
DEBUG_BREAKPOINT();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto USPassThruUSBRequest_return;
}
//
// Caller gives us a pointer, embedded into IOCTL buffer. We need to
// validate that given pointer is readable.
//
try{
RtlCopyMemory(pBuffer,
pIoBlockEx->pbyData,
pIoBlockEx->uLength);
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// Caller buffer is not valid, or worse..
//
DebugTrace(TRACE_ERROR,("USPassThruUSBRequest: ERROR!! Copying caller buffer failed.\n"));
DEBUG_BREAKPOINT();
Status = GetExceptionCode();
goto USPassThruUSBRequest_return;
}
} else {
//
// Zero length buffer used for Write , IHV claim that's useful.
//
pBuffer = NULL;
} // if ( pIoBlockEx->uLength )
}
//
// Set proper USB funtion depends on bmRequestType.
//
if(0xa1 == pIoBlockEx->bmRequestType){ // USB_PTPREQUEST_TYPE_IN: Class/Interface Device to Host.
usUsbFunction = URB_FUNCTION_CLASS_INTERFACE;
} else if(0x21 == pIoBlockEx->bmRequestType){ // USB_PTPREQUEST_TYPE_OUT: Class/Interface Host to Device.
usUsbFunction = URB_FUNCTION_CLASS_INTERFACE;
} else { // Default.
usUsbFunction = URB_FUNCTION_VENDOR_DEVICE;
}
UsbBuildVendorClassSpecificCommandPTP(usUsbFunction,
pUrb,
pIoBlockEx->fTransferDirectionIn ? USBD_TRANSFER_DIRECTION_IN : 0,
pIoBlockEx->uLength,
pBuffer,
NULL,
pIoBlockEx->bmRequestType,
pIoBlockEx->bRequest,
(SHORT)pIoBlockEx->uOffset,
(USHORT)pIoBlockEx -> uIndex);
Status = USBSCAN_CallUSBD(pDeviceObject, pUrb);
USPassThruUSBRequest_return:
//
// Clean up.
//
if(NULL != pUrb){
DebugTrace(TRACE_STATUS,("USPassThruUSBRequest: Free USB Request Block.\n"));
USFreePool(pUrb);
}
if( (!fDirectionIn)
&& (NULL != pBuffer) )
{
DebugTrace(TRACE_STATUS,("USPassThruUSBRequest: Free temp buffer.\n"));
USFreePool(pBuffer);
}
DebugTrace(TRACE_PROC_LEAVE,("USPassThruUSBRequest: Leaving.. Status = 0x%x\n", Status));
return Status;
} // USPassThruUSBRequestPTP()