/*++ Copyright (C) Microsoft Corporation, 1997 - 2001 Module Name: ioctl.c Abstract: Environment: kernel mode only Notes: Revision History: --*/ #include #include #include #include #include "usbd_api.h" #include "private.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")); // // 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()