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