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.
1605 lines
53 KiB
1605 lines
53 KiB
/*++
|
|
|
|
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()
|
|
|
|
|