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.
940 lines
30 KiB
940 lines
30 KiB
/*++
|
|
|
|
Copyright (c) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
GENUSB.C
|
|
|
|
Abstract:
|
|
|
|
This source file contains the DriverEntry() and AddDevice() entry points
|
|
for the GENUSB driver and the dispatch routines which handle:
|
|
|
|
IRP_MJ_POWER
|
|
IRP_MJ_SYSTEM_CONTROL
|
|
IRP_MJ_PNP
|
|
|
|
Environment:
|
|
|
|
kernel mode
|
|
|
|
Revision History:
|
|
|
|
Sep 2001 : Copied from USBMASS
|
|
|
|
--*/
|
|
|
|
//*****************************************************************************
|
|
// I N C L U D E S
|
|
//*****************************************************************************
|
|
|
|
#include "genusb.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, GenUSB_DeviceControl)
|
|
#endif
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_DeviceControl()
|
|
//
|
|
//******************************************************************************
|
|
|
|
|
|
NTSTATUS
|
|
GenUSB_DeviceControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
ULONG ioControlCode;
|
|
ULONG buffLen;
|
|
ULONG requiredLen;
|
|
ULONG numberInterfaces;
|
|
ULONG i;
|
|
PVOID source;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PCHAR buffer;
|
|
ULONG urbStatus;
|
|
USHORT resultLength;
|
|
BOOLEAN complete;
|
|
USBD_PIPE_HANDLE usbdPipeHandle;
|
|
|
|
PGENUSB_GET_STRING_DESCRIPTOR stringDescriptor;
|
|
PGENUSB_GET_REQUEST request;
|
|
PGENUSB_REQUEST_RESULTS requestResult;
|
|
PGENUSB_SELECT_CONFIGURATION selectConfig;
|
|
PGENUSB_SET_READ_WRITE_PIPES readWritePipes;
|
|
GENUSB_READ_WRITE_PIPE transfer;
|
|
|
|
PAGED_CODE ();
|
|
|
|
complete = TRUE;
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
|
|
if (!NT_SUCCESS(status)) {
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
// While there are several readers of the IsStarted state, it is only
|
|
// set at the end of GenUSB_StartDevice.
|
|
if (!deviceExtension->IsStarted) {
|
|
LOGENTRY(deviceExtension,'IOns', DeviceObject, Irp, 0);
|
|
status = STATUS_DEVICE_NOT_CONNECTED;
|
|
goto GenUSB_DeviceControlDone;
|
|
}
|
|
|
|
//
|
|
// After talking extensively with JD, he tells me that I do not need
|
|
// to queue requests for power downs or query stop. If that is the
|
|
// case then even if the device power state isn't PowerDeviceD0 we
|
|
// can still allow trasfers. This, of course, is a property of the
|
|
// brand new port driver that went into XP.
|
|
//
|
|
// if (DeviceExtension->DevicePowerState != PowerDeviceD0)
|
|
// {
|
|
// }
|
|
//
|
|
|
|
//
|
|
// BUGBUG if we ever implement IDLE, we need to turn the device
|
|
// back on here.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
// Get the Ioctl code
|
|
ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
// We need to clear the information field in all cases.
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
switch (ioControlCode) {
|
|
|
|
case IOCTL_GENUSB_GET_DEVICE_DESCRIPTOR:
|
|
case IOCTL_GENUSB_GET_CONFIGURATION_DESCRIPTOR:
|
|
LOGENTRY(deviceExtension, 'IO_1', ioControlCode, DeviceObject, Irp);
|
|
|
|
//
|
|
// All of these ioctls copy data from the device extension
|
|
// to the caller's buffer
|
|
//
|
|
switch (ioControlCode) {
|
|
case IOCTL_GENUSB_GET_DEVICE_DESCRIPTOR:
|
|
source = deviceExtension->DeviceDescriptor;
|
|
requiredLen = deviceExtension->DeviceDescriptor->bLength;
|
|
break;
|
|
case IOCTL_GENUSB_GET_CONFIGURATION_DESCRIPTOR:
|
|
source = deviceExtension->ConfigurationDescriptor;
|
|
requiredLen = deviceExtension->ConfigurationDescriptor->wTotalLength;
|
|
break;
|
|
default:
|
|
// Panic
|
|
ASSERT (ioControlCode);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto GenUSB_DeviceControlDone;
|
|
}
|
|
|
|
// Verify that there is a system buffer
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer) {
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
// Verify that this buffer is of sufficient length
|
|
buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
if (buffLen < requiredLen) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
// Copy in the data and return the length in the information field.
|
|
RtlCopyMemory (buffer, source, requiredLen);
|
|
Irp->IoStatus.Information = requiredLen;
|
|
break;
|
|
|
|
case IOCTL_GENUSB_GET_STRING_DESCRIPTOR:
|
|
LOGENTRY(deviceExtension, 'IO_2', ioControlCode, DeviceObject, Irp);
|
|
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer)
|
|
{
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
stringDescriptor = Irp->AssociatedIrp.SystemBuffer;
|
|
buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// verify input length
|
|
//
|
|
buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
if (buffLen != sizeof (GENUSB_GET_STRING_DESCRIPTOR))
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// verify output length
|
|
//
|
|
buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
if (buffLen < sizeof (USB_STRING_DESCRIPTOR)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
//
|
|
// if the caller didn't specify a language ID, then insert the default
|
|
// language ID. (but only if the caller is not trying to retrive
|
|
// the array of language IDs.
|
|
//
|
|
if ((0 == stringDescriptor->LanguageId) &&
|
|
(0 != stringDescriptor->Index)) {
|
|
stringDescriptor->LanguageId = deviceExtension->LanguageId;
|
|
}
|
|
|
|
switch (stringDescriptor->Recipient)
|
|
{
|
|
|
|
case GENUSB_RECIPIENT_DEVICE:
|
|
stringDescriptor->Recipient = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
|
|
break;
|
|
|
|
case GENUSB_RECIPIENT_INTERFACE:
|
|
stringDescriptor->Recipient = URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE;
|
|
break;
|
|
|
|
case GENUSB_RECIPIENT_ENDPOINT:
|
|
stringDescriptor->Recipient = URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT;
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto GenUSB_DeviceControlDone;
|
|
}
|
|
|
|
status = GenUSB_GetDescriptor (DeviceObject,
|
|
stringDescriptor->Recipient,
|
|
USB_STRING_DESCRIPTOR_TYPE,
|
|
stringDescriptor->Index,
|
|
stringDescriptor->LanguageId,
|
|
0, // retry count
|
|
buffLen,
|
|
&buffer);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
DBGPRINT(1, ("Get String Descriptor failed (%x) %08X\n",
|
|
stringDescriptor->Index,
|
|
status));
|
|
break;
|
|
}
|
|
Irp->IoStatus.Information = buffLen;
|
|
break;
|
|
|
|
case IOCTL_GENUSB_GET_REQUEST:
|
|
LOGENTRY(deviceExtension, 'IO_3', ioControlCode, DeviceObject, Irp);
|
|
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer) {
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
request = Irp->AssociatedIrp.SystemBuffer;
|
|
requestResult = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// verify input length
|
|
//
|
|
buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
if (buffLen != sizeof (GENUSB_GET_REQUEST)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// verify output length
|
|
//
|
|
buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
if (buffLen < sizeof (GENUSB_REQUEST_RESULTS)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// adjust the buffer
|
|
//
|
|
buffer = requestResult->Buffer;
|
|
buffLen -= FIELD_OFFSET (GENUSB_REQUEST_RESULTS, Buffer);
|
|
|
|
LOGENTRY(deviceExtension,
|
|
'IoGR',
|
|
(request->RequestType << 8) & request->Request,
|
|
request->Value,
|
|
request->Index);
|
|
|
|
DBGPRINT(2, ("Get Request: Type %x Request %x Value %x Index %x\n",
|
|
request->RequestType,
|
|
request->Request,
|
|
request->Value,
|
|
request->Index));
|
|
|
|
status = GenUSB_VendorControlRequest (DeviceObject,
|
|
request->RequestType,
|
|
request->Request,
|
|
request->Value,
|
|
request->Index,
|
|
(USHORT) buffLen, // disallow longer descriptors
|
|
0, // retry count
|
|
&urbStatus,
|
|
&resultLength,
|
|
&buffer);
|
|
|
|
requestResult->Status = urbStatus;
|
|
requestResult->Length = resultLength;
|
|
|
|
if (!NT_SUCCESS (status))
|
|
{
|
|
DBGPRINT(1, ("Get Descriptor failed (%x) %08X\n", urbStatus));
|
|
Irp->IoStatus.Information = sizeof (GENUSB_REQUEST_RESULTS);
|
|
status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
Irp->IoStatus.Information = resultLength
|
|
+ FIELD_OFFSET (GENUSB_REQUEST_RESULTS, Buffer);
|
|
|
|
}
|
|
break;
|
|
|
|
case IOCTL_GENUSB_GET_CAPS:
|
|
LOGENTRY(deviceExtension, 'IO_4', ioControlCode, DeviceObject, Irp);
|
|
//
|
|
// METHOD_BUFFERED irp. the buffer is in the AssociatedIrp.
|
|
//
|
|
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer) {
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
if (buffLen < sizeof (GENUSB_CAPABILITIES)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
((PGENUSB_CAPABILITIES) buffer) ->DeviceDescriptorLength =
|
|
deviceExtension->DeviceDescriptor->bLength;
|
|
|
|
((PGENUSB_CAPABILITIES) buffer) ->ConfigurationInformationLength =
|
|
deviceExtension->ConfigurationDescriptor->wTotalLength;
|
|
|
|
Irp->IoStatus.Information = sizeof (GENUSB_CAPABILITIES);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IOCTL_GENUSB_SELECT_CONFIGURATION:
|
|
LOGENTRY(deviceExtension, 'IO_5', ioControlCode, DeviceObject, Irp);
|
|
|
|
//
|
|
// GenUSB_SelectInterface checks to see if the configuration handle
|
|
// is already set and fails if it is.
|
|
//
|
|
// if (NULL != deviceExtension->ConfigurationHandle)
|
|
// {
|
|
// status = STATUS_UNSUCCESSFUL;
|
|
// }
|
|
//
|
|
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer)
|
|
{
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
selectConfig = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// The input buffer must be long enough to contain at least the
|
|
// header information
|
|
//
|
|
buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
if (buffLen < sizeof (GENUSB_SELECT_CONFIGURATION))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The input buffer must be exactly the length as specfied by the
|
|
// header information.
|
|
//
|
|
numberInterfaces = selectConfig->NumberInterfaces;
|
|
if (buffLen != sizeof (GENUSB_SELECT_CONFIGURATION)
|
|
+ (sizeof (USB_INTERFACE_DESCRIPTOR) * numberInterfaces))
|
|
{
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The output buffer must be same length
|
|
//
|
|
if (buffLen != irpSp->Parameters.DeviceIoControl.OutputBufferLength)
|
|
{
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
status = GenUSB_SelectConfiguration (deviceExtension,
|
|
numberInterfaces,
|
|
selectConfig->Interfaces,
|
|
selectConfig->Interfaces);
|
|
if (!NT_SUCCESS (status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// rebase the interface numbers
|
|
//
|
|
for (i = 0; i < selectConfig->NumberInterfaces; i++)
|
|
{
|
|
|
|
selectConfig->Interfaces[i].bInterfaceNumber = (UCHAR) i;
|
|
}
|
|
selectConfig->NumberInterfaces = deviceExtension->InterfacesFound;
|
|
Irp->IoStatus.Information = buffLen;
|
|
|
|
break;
|
|
|
|
case IOCTL_GENUSB_DESELECT_CONFIGURATION:
|
|
LOGENTRY(deviceExtension, 'IO_6', ioControlCode, DeviceObject, Irp);
|
|
|
|
status = GenUSB_DeselectConfiguration (deviceExtension, TRUE);
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
break;
|
|
|
|
case IOCTL_GENUSB_GET_PIPE_INFO:
|
|
LOGENTRY(deviceExtension, 'IO_7', ioControlCode, DeviceObject, Irp);
|
|
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer)
|
|
{
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
//
|
|
// verify input length
|
|
//
|
|
buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
if (buffLen != sizeof (GENUSB_PIPE_INFO_REQUEST))
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// verify output length
|
|
//
|
|
buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
if (buffLen != sizeof (GENUSB_PIPE_INFORMATION))
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
status =
|
|
GenUSB_GetSetPipe (
|
|
deviceExtension,
|
|
NULL, // no interface index
|
|
&((PGENUSB_PIPE_INFO_REQUEST) Irp->AssociatedIrp.SystemBuffer)->InterfaceNumber,
|
|
NULL, // no pipe index
|
|
&((PGENUSB_PIPE_INFO_REQUEST) Irp->AssociatedIrp.SystemBuffer)->EndpointAddress,
|
|
NULL, // No set Properties
|
|
(PGENUSB_PIPE_INFORMATION) Irp->AssociatedIrp.SystemBuffer,
|
|
NULL, // No set Properties
|
|
NULL); // No UsbdPipeHandles needed
|
|
|
|
if (NT_SUCCESS (status))
|
|
{
|
|
Irp->IoStatus.Information = sizeof (GENUSB_PIPE_INFORMATION);
|
|
}
|
|
|
|
break;
|
|
|
|
case IOCTL_GENUSB_SET_READ_WRITE_PIPES:
|
|
LOGENTRY(deviceExtension, 'IO_8', ioControlCode, DeviceObject, Irp);
|
|
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer)
|
|
{
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
readWritePipes =
|
|
(PGENUSB_SET_READ_WRITE_PIPES) Irp->AssociatedIrp.SystemBuffer;
|
|
//
|
|
// verify input length
|
|
//
|
|
buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
if (buffLen != sizeof (GENUSB_SET_READ_WRITE_PIPES))
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// verify output length
|
|
//
|
|
buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
if (buffLen != 0)
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
status = GenUSB_SetReadWritePipes (
|
|
deviceExtension,
|
|
(PGENUSB_PIPE_HANDLE) &readWritePipes->ReadPipe,
|
|
(PGENUSB_PIPE_HANDLE) &readWritePipes->WritePipe);
|
|
|
|
|
|
// on success the information field stays at zero.
|
|
//
|
|
// if (NT_SUCCESS (status))
|
|
// {
|
|
// Irp->IoStatus.Information = 0;
|
|
// }
|
|
|
|
break;
|
|
case IOCTL_GENUSB_GET_PIPE_PROPERTIES:
|
|
LOGENTRY(deviceExtension, 'IO_9', ioControlCode, DeviceObject, Irp);
|
|
//
|
|
// METHOD_BUFFERED irp. the buffer is in the AssociatedIrp.
|
|
//
|
|
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer)
|
|
{
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
if (buffLen != sizeof (GENUSB_PIPE_HANDLE))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
if (buffLen != sizeof (GENUSB_PIPE_PROPERTIES))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
if (! VERIFY_PIPE_HANDLE_SIG (buffer, deviceExtension))
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
status =
|
|
GenUSB_GetSetPipe (
|
|
deviceExtension,
|
|
&((PGENUSB_PIPE_HANDLE) buffer)->InterfaceIndex,
|
|
NULL, // no interface number
|
|
&((PGENUSB_PIPE_HANDLE) buffer)->PipeIndex,
|
|
NULL, // no endpoint address
|
|
NULL, // no set
|
|
NULL, // no Pipe Info
|
|
((PGENUSB_PIPE_PROPERTIES) buffer),
|
|
NULL); // usbd PipeHandle not needed
|
|
|
|
Irp->IoStatus.Information = sizeof (GENUSB_PIPE_PROPERTIES);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IOCTL_GENUSB_SET_PIPE_PROPERTIES:
|
|
LOGENTRY(deviceExtension, 'IO_A', ioControlCode, DeviceObject, Irp);
|
|
//
|
|
// METHOD_BUFFERED irp. the buffer is in the AssociatedIrp.
|
|
//
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer)
|
|
{
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
// Verify Input Length
|
|
buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
if (buffLen != sizeof (GENUSB_PIPE_HANDLE) + sizeof (GENUSB_PIPE_PROPERTIES))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
// Verify Output Length
|
|
buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
if (buffLen != 0)
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (! VERIFY_PIPE_HANDLE_SIG (buffer, deviceExtension))
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
status =
|
|
GenUSB_GetSetPipe (
|
|
deviceExtension,
|
|
&((PGENUSB_PIPE_HANDLE) buffer)->InterfaceIndex,
|
|
NULL, // no interface number
|
|
&((PGENUSB_PIPE_HANDLE) buffer)->PipeIndex,
|
|
NULL, // no endpoint address
|
|
(PGENUSB_PIPE_PROPERTIES) (buffer + sizeof (GENUSB_PIPE_HANDLE)),
|
|
NULL, // no Pipe Info
|
|
NULL, // no Get
|
|
NULL); // no UsbdPipeHandle needed
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IOCTL_GENUSB_RESET_PIPE:
|
|
LOGENTRY(deviceExtension, 'IO_B', ioControlCode, DeviceObject, Irp);
|
|
//
|
|
// METHOD_BUFFERED irp. the buffer is in the AssociatedIrp.
|
|
//
|
|
|
|
if (NULL == Irp->AssociatedIrp.SystemBuffer)
|
|
{
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
if (buffLen != sizeof (GENUSB_RESET_PIPE))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
if (buffLen != 0)
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (! VERIFY_PIPE_HANDLE_SIG (buffer, deviceExtension))
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
status =
|
|
GenUSB_GetSetPipe (
|
|
deviceExtension,
|
|
&((PGENUSB_PIPE_HANDLE) buffer)->InterfaceIndex,
|
|
NULL, // no interface number
|
|
&((PGENUSB_PIPE_HANDLE) buffer)->PipeIndex,
|
|
NULL, // no endpoint address
|
|
NULL, // no set
|
|
NULL, // no Pipe Info
|
|
NULL, // no PipeProperties
|
|
&usbdPipeHandle);
|
|
|
|
if (!NT_SUCCESS (status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
status = GenUSB_ResetPipe (deviceExtension,
|
|
usbdPipeHandle,
|
|
((PGENUSB_RESET_PIPE)buffer)->ResetPipe,
|
|
((PGENUSB_RESET_PIPE)buffer)->ClearStall,
|
|
((PGENUSB_RESET_PIPE)buffer)->FlushData);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
break;
|
|
|
|
case IOCTL_GENUSB_READ_WRITE_PIPE:
|
|
LOGENTRY(deviceExtension, 'IO_C', ioControlCode, DeviceObject, Irp);
|
|
|
|
status = GenUSB_ProbeAndSubmitTransfer (Irp, irpSp, deviceExtension);
|
|
complete = FALSE;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// 'Fail' the Irp by returning the default status.
|
|
//
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
GenUSB_DeviceControlDone:
|
|
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
|
|
|
|
if (complete)
|
|
{
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
GenUSB_ProbeAndSubmitTransferComplete (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PGENUSB_TRANSFER LocalTrans,
|
|
IN USBD_STATUS Status,
|
|
IN ULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
GenUSB_ProbeAndSubmitTransfer (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PMDL mdl;
|
|
BOOLEAN userLocked;
|
|
BOOLEAN transferLocked;
|
|
|
|
PGENUSB_READ_WRITE_PIPE userTrans; // a pointer to the user's buffer
|
|
PGENUSB_TRANSFER localTrans; // a local copy of the user data.
|
|
|
|
LOGENTRY(DeviceExtension, 'PROB', DeviceExtension->Self, Irp, 0);
|
|
|
|
status = STATUS_SUCCESS;
|
|
userTrans = NULL;
|
|
localTrans = NULL;
|
|
userLocked = FALSE;
|
|
transferLocked = FALSE;
|
|
|
|
//
|
|
// Validate the user's buffer.
|
|
//
|
|
try {
|
|
|
|
if (sizeof (GENUSB_READ_WRITE_PIPE) !=
|
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength)
|
|
{
|
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
userTrans = (PGENUSB_READ_WRITE_PIPE)
|
|
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
if (NULL == userTrans)
|
|
{
|
|
ExRaiseStatus (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
localTrans = (PGENUSB_TRANSFER)
|
|
ExAllocatePool (NonPagedPool, sizeof (GENUSB_TRANSFER));
|
|
|
|
if (NULL == localTrans)
|
|
{
|
|
ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
RtlZeroMemory (localTrans, sizeof (GENUSB_TRANSFER));
|
|
|
|
//
|
|
// The input comes in User Buffer, and should be a
|
|
// PGENUSB_READ_WRITE_PIPE structure.
|
|
//
|
|
localTrans->UserMdl = IoAllocateMdl (userTrans,
|
|
sizeof(PGENUSB_READ_WRITE_PIPE),
|
|
FALSE, // no 2nd buffer
|
|
TRUE, // charge quota
|
|
NULL); // no associated irp
|
|
|
|
if (NULL == localTrans->UserMdl)
|
|
{
|
|
ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
MmProbeAndLockPages (localTrans->UserMdl,
|
|
KernelMode,
|
|
((localTrans->UserCopy.UsbdTransferFlags
|
|
& USBD_TRANSFER_DIRECTION_IN)
|
|
? IoReadAccess
|
|
: IoWriteAccess));
|
|
userLocked = TRUE;
|
|
|
|
|
|
// make a local copy of the user data so that it doesn't move.
|
|
localTrans->UserCopy = *userTrans;
|
|
|
|
// mask off the invalid flags.
|
|
localTrans->UserCopy.UsbdTransferFlags &=
|
|
USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION;
|
|
|
|
// Now probe the transfer location
|
|
localTrans->TransferMdl = IoAllocateMdl (
|
|
localTrans->UserCopy.UserBuffer,
|
|
localTrans->UserCopy.BufferLength,
|
|
FALSE, // no 2nd buffer
|
|
TRUE, // do charge the quota
|
|
NULL); // no associated irp
|
|
|
|
if (NULL == localTrans->TransferMdl)
|
|
{
|
|
ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
MmProbeAndLockPages (localTrans->TransferMdl,
|
|
KernelMode,
|
|
((localTrans->UserCopy.UsbdTransferFlags
|
|
& USBD_TRANSFER_DIRECTION_IN)
|
|
? IoReadAccess
|
|
: IoWriteAccess));
|
|
|
|
transferLocked = TRUE;
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
status = GetExceptionCode();
|
|
goto GenUSBProbSubmitTransferReject;
|
|
}
|
|
|
|
if (! VERIFY_PIPE_HANDLE_SIG (&localTrans->UserCopy.Pipe, DeviceExtension))
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto GenUSBProbSubmitTransferReject;
|
|
}
|
|
|
|
// Unfortunately we complete, we will no longer running in the contect
|
|
// of the caller.
|
|
// Therefore we we cannot use LocalTrans->UserCopy.UserBuffer to just
|
|
// dump the return data. We instead need a system address for it.
|
|
localTrans->SystemAddress =
|
|
MmGetSystemAddressForMdlSafe (localTrans->UserMdl, NormalPagePriority);
|
|
|
|
if (NULL == localTrans->SystemAddress)
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GenUSBProbSubmitTransferReject;
|
|
}
|
|
|
|
//
|
|
// now perform the transfer.
|
|
//
|
|
LOGENTRY(DeviceExtension, 'prob', DeviceExtension->Self, Irp, status);
|
|
status = GenUSB_TransmitReceive (
|
|
DeviceExtension,
|
|
Irp,
|
|
((PGENUSB_PIPE_HANDLE)&localTrans->UserCopy.Pipe)->InterfaceIndex,
|
|
((PGENUSB_PIPE_HANDLE)&localTrans->UserCopy.Pipe)->PipeIndex,
|
|
localTrans->UserCopy.UsbdTransferFlags,
|
|
NULL, // no buffer pointer
|
|
localTrans->TransferMdl,
|
|
localTrans->UserCopy.BufferLength,
|
|
localTrans,
|
|
GenUSB_ProbeAndSubmitTransferComplete);
|
|
|
|
return status;
|
|
|
|
GenUSBProbSubmitTransferReject:
|
|
|
|
LOGENTRY (DeviceExtension, 'prob', DeviceExtension->Self, Irp, status);
|
|
if (NULL != localTrans)
|
|
{
|
|
if (localTrans->UserMdl)
|
|
{
|
|
if (userLocked)
|
|
{
|
|
MmUnlockPages (localTrans->UserMdl);
|
|
}
|
|
IoFreeMdl (localTrans->UserMdl);
|
|
}
|
|
if (localTrans->TransferMdl)
|
|
{
|
|
if (transferLocked)
|
|
{
|
|
MmUnlockPages (localTrans->TransferMdl);
|
|
}
|
|
IoFreeMdl (localTrans->TransferMdl);
|
|
}
|
|
ExFreePool (localTrans);
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
GenUSB_ProbeAndSubmitTransferComplete (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PGENUSB_TRANSFER LocalTrans,
|
|
IN USBD_STATUS UrbStatus,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
LOGENTRY(deviceExtension, 'PrbC', Irp, Length, UrbStatus);
|
|
|
|
// Regardless of whether or not the transaction was successful,
|
|
// we need to free the MDL that points to the users transfer buffer.
|
|
MmUnlockPages (LocalTrans->TransferMdl);
|
|
IoFreeMdl (LocalTrans->TransferMdl);
|
|
|
|
LocalTrans->UserCopy.UrbStatus = UrbStatus;
|
|
LocalTrans->UserCopy.BufferLength = Length;
|
|
|
|
//
|
|
// since we are not in the caller's context any more
|
|
// we cannot just use LocalTrans->UserCopy.UserBuffer to copy the data
|
|
// back. We must instead use the system address, which should already
|
|
// be all set up.
|
|
//
|
|
ASSERT (NULL != LocalTrans->SystemAddress);
|
|
*LocalTrans->SystemAddress = LocalTrans->UserCopy;
|
|
|
|
// Now free the user buffer containing the arguments.
|
|
MmUnlockPages (LocalTrans->UserMdl);
|
|
IoFreeMdl (LocalTrans->UserMdl);
|
|
|
|
|
|
ExFreePool (LocalTrans);
|
|
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|