Leaked source code of windows server 2003
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

/*++
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;
}