diff options
Diffstat (limited to 'network/wwan/cxwmbclass/datapipe.cpp')
| -rw-r--r-- | network/wwan/cxwmbclass/datapipe.cpp | 998 |
1 files changed, 998 insertions, 0 deletions
diff --git a/network/wwan/cxwmbclass/datapipe.cpp b/network/wwan/cxwmbclass/datapipe.cpp new file mode 100644 index 00000000..4452b761 --- /dev/null +++ b/network/wwan/cxwmbclass/datapipe.cpp @@ -0,0 +1,998 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "precomp.h" + +typedef struct _USB_WRITE_REQ_CONTEXT +{ + WDFMEMORY UrbMemory; + PURB Urb; + PMDL Mdl; + WDFMEMORY LookasideBuffer; + PBUS_OBJECT BusObject; + MBB_BUS_SEND_DATA_COMPLETION_CALLBACK Callback; + MBB_REQUEST_HANDLE RequestHandle; + +} USB_WRITE_REQ_CONTEXT, *PUSB_WRITE_REQ_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(USB_WRITE_REQ_CONTEXT, GetWriteRequestContext) + +EVT_WDF_USB_READER_COMPLETION_ROUTINE BulkInReadComplete; + +EVT_WDF_USB_READERS_FAILED BulkInReadError; + +NTSTATUS +GetWriteRequests(WDFUSBDEVICE UsbDevice, WDFREQUEST* ReturnedWriteRequest); + +VOID FreeWriteRequest(WDFUSBDEVICE UsbDevice, WDFREQUEST WriteRequest); + +NTSTATUS +MbbBusSelectDataAltSetting(__in MBB_BUS_HANDLE BusHandle, __in UCHAR AltSetting) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS SettingParams; + WDFUSBINTERFACE UsbInterface = NULL; + WDF_USB_PIPE_INFORMATION pipeInfo; + WDFUSBPIPE pipe; + UCHAR ConfiguredPipes = 0; + UCHAR index = 0; + NTSTATUS Status; + NTSTATUS TempStatus; + WDF_USB_CONTINUOUS_READER_CONFIG ReaderConfig; + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + WdfWaitLockAcquire(usbDeviceContext->PipeStateLock, NULL); + + UsbInterface = WdfUsbTargetDeviceGetInterface(BusObject->WdfUsbDevice, usbDeviceContext->WdfDataInterfaceIndex); + + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&SettingParams, AltSetting == 0 ? 0 : usbDeviceContext->UsbDataInterfaceSetting); + + Status = WdfUsbInterfaceSelectSetting(UsbInterface, NULL, &SettingParams); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + ConfiguredPipes = WdfUsbInterfaceGetNumConfiguredPipes(UsbInterface); + + if (((AltSetting == ALT_DATA_SETTING_0) && (ConfiguredPipes != ALT_DATA_SETTING_0_PIPES)) || + ((AltSetting == ALT_DATA_SETTING_1) && (ConfiguredPipes != ALT_DATA_SETTING_1_PIPES))) + { + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + if (AltSetting == ALT_DATA_SETTING_1) + { + for (index = 0; index < ConfiguredPipes; index++) + { + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + + pipe = WdfUsbInterfaceGetConfiguredPipe( + UsbInterface, + index, // PipeIndex, + &pipeInfo); + + if (WdfUsbPipeTypeBulk == pipeInfo.PipeType) + { + + if (WdfUsbTargetPipeIsInEndpoint(pipe)) + { + usbDeviceContext->BulkInputPipeConfigured = TRUE; + usbDeviceContext->BulkInputPipe = pipe; + usbDeviceContext->BulkInputPipeMaxPacket = pipeInfo.MaximumPacketSize; + } + else + { + usbDeviceContext->BulkOutputPipeConfigured = TRUE; + usbDeviceContext->BulkOutputPipe = pipe; + usbDeviceContext->BulkOutputPipeMaxPacket = pipeInfo.MaximumPacketSize; + } + } + else + { + + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + } + + if (!(usbDeviceContext->BulkInputPipeConfigured && usbDeviceContext->BulkOutputPipeConfigured)) + { + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + // + // configure the continous reader on the bulk pipe now, since this can only be done once on a given pipe + // unless it is unselected + // + WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&ReaderConfig, BulkInReadComplete, BusObject, BusObject->MaxBulkInTransfer); + + if (BusObject->UsbCapDeviceInfo.DeviceInfoHeader.DeviceType == USB_CAP_DEVICE_TYPE_UDE_MBIM) + { + ReaderConfig.NumPendingReads = PENDING_BULK_IN_READS_FOR_UDE_MBIM; + } + else + { + ReaderConfig.NumPendingReads = PENDING_BULK_IN_READS; + } + ReaderConfig.HeaderLength = BusObject->BulkInHeaderSize; + ReaderConfig.EvtUsbTargetPipeReadersFailed = BulkInReadError; + + Status = WdfUsbTargetPipeConfigContinuousReader(usbDeviceContext->BulkInputPipe, &ReaderConfig); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + // + // call this now that the pipe is configured + // + PreAllocateWriteRequests(BusObject->WdfUsbDevice); + } + else + { + // + // selecting the setting causes the frame work to delete the pipe + // + WDFREQUEST WriteRequest = NULL; + + usbDeviceContext->BulkInputPipeConfigured = FALSE; + usbDeviceContext->BulkInputPipe = NULL; + + usbDeviceContext->BulkOutputPipeConfigured = FALSE; + usbDeviceContext->BulkOutputPipe = NULL; + + WdfSpinLockAcquire(usbDeviceContext->WriteCollectionLock); + + WriteRequest = (WDFREQUEST)WdfCollectionGetLastItem(usbDeviceContext->WriteRequestCollection); + + // + // delete the write request because they are associated with a pipe object + // + while (WriteRequest != NULL) + { + WdfCollectionRemove(usbDeviceContext->WriteRequestCollection, WriteRequest); + + WdfObjectDelete(WriteRequest); + WriteRequest = (WDFREQUEST)WdfCollectionGetLastItem(usbDeviceContext->WriteRequestCollection); + } + + WdfSpinLockRelease(usbDeviceContext->WriteCollectionLock); + } + +Cleanup: + + if (!NT_SUCCESS(Status)) + { + // + // failed to configure the pipes, set back to alt setting 0 + // + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&SettingParams, 0); + + TempStatus = WdfUsbInterfaceSelectSetting(UsbInterface, NULL, &SettingParams); + + usbDeviceContext->BulkInputPipeConfigured = FALSE; + usbDeviceContext->BulkInputPipe = NULL; + + usbDeviceContext->BulkOutputPipeConfigured = FALSE; + usbDeviceContext->BulkOutputPipe = NULL; + } + + WdfWaitLockRelease(usbDeviceContext->PipeStateLock); + + return Status; +} + +NTSTATUS +MbbUsbDeviceStartDataPipes(__in PUSB_DEVICE_CONTEXT usbDeviceContext) +{ + NTSTATUS Status; + + WdfWaitLockAcquire(usbDeviceContext->PipeStateLock, NULL); + + if (!(usbDeviceContext->BulkInputPipeConfigured && usbDeviceContext->BulkOutputPipeConfigured)) + { + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + Status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkInputPipe)); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + usbDeviceContext->BulkInputPipeStarted = TRUE; + + Status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe)); + + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + usbDeviceContext->BulkOutputPipeStarted = TRUE; + +Cleanup: + + if (!NT_SUCCESS(Status)) + { + // + // failed to configure the pipes, set back to alt setting 0 + // + if (usbDeviceContext->BulkInputPipeStarted) + { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkInputPipe), WdfIoTargetCancelSentIo); + } + + if (usbDeviceContext->BulkOutputPipeStarted) + { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), WdfIoTargetCancelSentIo); + } + + usbDeviceContext->BulkInputPipeStarted = FALSE; + usbDeviceContext->BulkOutputPipeStarted = FALSE; + } + + WdfWaitLockRelease(usbDeviceContext->PipeStateLock); + + return Status; +} + +NTSTATUS +MbbBusStartDataPipes(__in MBB_BUS_HANDLE BusHandle) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + return MbbUsbDeviceStartDataPipes(GetUsbDeviceContext(BusObject->WdfUsbDevice)); +} + +VOID MbbUsbDeviceStopDataPipes(__in PUSB_DEVICE_CONTEXT usbDeviceContext) +{ + WDFUSBINTERFACE UsbInterface = NULL; + + WdfWaitLockAcquire(usbDeviceContext->PipeStateLock, NULL); + + if (usbDeviceContext->BulkInputPipeConfigured) + { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkInputPipe), WdfIoTargetCancelSentIo); + } + if (usbDeviceContext->BulkOutputPipeConfigured) + { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), WdfIoTargetCancelSentIo); + } + + usbDeviceContext->BulkInputPipeStarted = FALSE; + + usbDeviceContext->BulkOutputPipeStarted = FALSE; + + WdfWaitLockRelease(usbDeviceContext->PipeStateLock); + + return; +} + +VOID MbbBusStopDataPipes(__in MBB_BUS_HANDLE BusHandle) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + PUSB_DEVICE_CONTEXT usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + WdfWorkItemFlush(usbDeviceContext->BulkPipeResetWorkitem); + + MbbUsbDeviceStopDataPipes(GetUsbDeviceContext(BusObject->WdfUsbDevice)); +} + +NTSTATUS +MbbUsbDeviceResetBulkPipe(__in PUSB_DEVICE_CONTEXT usbDeviceContext, __in BOOLEAN Out) + +{ + WDFUSBPIPE Pipe = NULL; + WDF_REQUEST_SEND_OPTIONS SendOptions; + NTSTATUS StatusToReturn = STATUS_SUCCESS; + NTSTATUS Status; + + WdfWaitLockAcquire(usbDeviceContext->PipeStateLock, NULL); + + if (Out ? usbDeviceContext->BulkOutputPipeConfigured : usbDeviceContext->BulkInputPipeConfigured) + { + + Pipe = Out ? usbDeviceContext->BulkOutputPipe : usbDeviceContext->BulkInputPipe; + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(30)); + + Status = WdfUsbTargetPipeAbortSynchronously(Pipe, NULL, &SendOptions); + + if (!NT_SUCCESS(Status)) + { + if (StatusToReturn == STATUS_SUCCESS) + { + StatusToReturn = Status; + } + } + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(30)); + + Status = WdfUsbTargetPipeResetSynchronously(Pipe, NULL, &SendOptions); + + if (!NT_SUCCESS(Status)) + { + if (StatusToReturn == STATUS_SUCCESS) + { + StatusToReturn = Status; + } + } + } + WdfWaitLockRelease(usbDeviceContext->PipeStateLock); + + return StatusToReturn; +} + +NTSTATUS +MbbBusResetBulkPipe(__in MBB_BUS_HANDLE BusHandle, __in BOOLEAN Out) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + return MbbUsbDeviceResetBulkPipe(GetUsbDeviceContext(BusObject->WdfUsbDevice), Out); +} + +EVT_WDF_REQUEST_COMPLETION_ROUTINE WriteCompletionRoutine; + +void WriteCompletionRoutine(__in WDFREQUEST Request, __in WDFIOTARGET Target, __in PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, __in WDFCONTEXT Context) +/*++ + +Routine Description + + Request - Handle to the WDFREQUEST which was used to send data to the USB target. + Target - Handle to the Iotarget to which teh Request was sent. COnceptually this + is the BULK USB __out pipe(on of Data or beacon) + CompletionParams - In case of USB this contains the USB status and amount of bytes transferred + + + Context - This is the COntext we set in WdfRequestSend + + +Arguments: + + + +Return Value: + + + +--*/ + +{ + PUSB_WRITE_REQ_CONTEXT WriteContext; + NTSTATUS Status; + + UNREFERENCED_PARAMETER(Target); + WriteContext = (PUSB_WRITE_REQ_CONTEXT)Context; + + Status = CompletionParams->IoStatus.Status; + + // + // For usb devices, we should look at the Usb.Completion param. + // + + if (WriteContext->Callback != NULL) + { + (*WriteContext->Callback)(WriteContext->BusObject->ProtocolHandle, WriteContext->RequestHandle, Status, WriteContext->Mdl); + } + + if (WriteContext->LookasideBuffer != NULL) + { + + WdfObjectDelete(WriteContext->LookasideBuffer); + } + + if (WriteContext->UrbMemory != NULL) + { + WdfObjectDelete(WriteContext->UrbMemory); + } + + FreeWriteRequest(WriteContext->BusObject->WdfUsbDevice, Request); +} + +NTSTATUS +MbbBusWriteData(__in MBB_BUS_HANDLE BusHandle, __in MBB_REQUEST_HANDLE RequestHandle, __in PMDL Mdl, __in MBB_BUS_SEND_DATA_COMPLETION_CALLBACK Callback) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + PMDL TempMdl = NULL; + ULONGLONG TotalTransferLength = 0; + NTSTATUS Status; + WDFMEMORY urbMemory = NULL; + WDF_OBJECT_ATTRIBUTES objectAttribs; + PURB urbBuffer = NULL; + WDF_REQUEST_SEND_OPTIONS SendOptions; + WDFREQUEST WriteRequest = NULL; + USBD_PIPE_HANDLE usbdPipeHandle = NULL; + PUSB_WRITE_REQ_CONTEXT writeContext = NULL; + BOOLEAN SentToDevice = FALSE; + WDFMEMORY BufferMemoryObject = NULL; + WDFREQUEST WriteRequestZLP = NULL; + PUSB_WRITE_REQ_CONTEXT writeContextZLP = NULL; + + usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + if (!ExAcquireRundownProtection(&usbDeviceContext->BulkPipeResetRundown)) + { + return STATUS_NDIS_ADAPTER_NOT_READY; + } + + // + // make sure the length is not too big + // + TempMdl = Mdl; + + while (TempMdl != NULL) + { + TotalTransferLength += MmGetMdlByteCount(TempMdl); + + TempMdl = TempMdl->Next; + } + + if (TotalTransferLength > BusObject->NtbParam.dwNtbOutMaxSize) + { + // + // too big + // + Status = STATUS_UNSUCCESSFUL; + + goto Cleanup; + } + + if ((TotalTransferLength < BusObject->NtbParam.dwNtbOutMaxSize) && (TotalTransferLength % usbDeviceContext->BulkOutputPipeMaxPacket == 0)) + { + // + // The transfer length is less than the max out transfer size, and transfer length is a multiple of MaxPacket size. + // Need to send a ZLP to the device stack to terminated the transfer. + + Status = GetWriteRequests(BusObject->WdfUsbDevice, &WriteRequestZLP); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContextZLP = GetWriteRequestContext(WriteRequestZLP); + + writeContextZLP->BusObject = BusObject; + writeContextZLP->Callback = NULL; + } + + Status = GetWriteRequests(BusObject->WdfUsbDevice, &WriteRequest); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContext = GetWriteRequestContext(WriteRequest); + + if (usbDeviceContext->LookasideList == NULL) + { + + // + // allocate the URB, request is the parent + // + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); + objectAttribs.ParentObject = WriteRequest; + + Status = WdfUsbTargetDeviceCreateUrb(BusObject->WdfUsbDevice, &objectAttribs, &urbMemory, &urbBuffer); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + // + // get the USBD pipe handle, to build the URB + // + usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(usbDeviceContext->BulkOutputPipe); + + // + // NOTE : call UsbBuildInterruptOrBulkTransferRequest otherwise + // WdfUsbTargetPipeFormatRequestForUrb will assert + // with *** Assertion failed: Urb->UrbHeader.Length >= sizeof(_URB_HEADER) + // + UsbBuildInterruptOrBulkTransferRequest( + urbBuffer, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + usbdPipeHandle, + NULL, + Mdl, + (ULONG)TotalTransferLength, + USBD_TRANSFER_DIRECTION_OUT | USBD_SHORT_TRANSFER_OK, + NULL); + + // + // By calling WdfUsbTargetPipeFormatRequestForUrb the frameworks allocate a lot of resources + // like the underlying IRP for the request and hence it is better to do it at initilization + // to prevent an avoidable failure later. + // + Status = WdfUsbTargetPipeFormatRequestForUrb(usbDeviceContext->BulkOutputPipe, WriteRequest, urbMemory, NULL); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContext->UrbMemory = urbMemory; + writeContext->Urb = (PURB)urbBuffer; + } + else + { + // + // usb stack does not support chained mdl's, double buffer the transfer + // + PUCHAR DestBuffer = NULL; + PUCHAR SourceAddress = NULL; + size_t BufferSize = 0; + ULONG SourceLength = 0; + WDFMEMORY_OFFSET MemoryOffset; + + Status = WdfMemoryCreateFromLookaside(usbDeviceContext->LookasideList, &BufferMemoryObject); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + DestBuffer = (PUCHAR)WdfMemoryGetBuffer(BufferMemoryObject, &BufferSize); + + TempMdl = Mdl; + TotalTransferLength = 0; + while (TempMdl != NULL) + { + SourceLength = MmGetMdlByteCount(TempMdl); + + SourceAddress = (PUCHAR)MmGetSystemAddressForMdlSafe(TempMdl, NormalPagePriority | MdlMappingNoExecute); + + if (SourceAddress == NULL) + { + + Status = STATUS_INSUFFICIENT_RESOURCES; + + goto Cleanup; + } + + RtlCopyMemory(DestBuffer, SourceAddress, SourceLength); + + DestBuffer += SourceLength; + + TotalTransferLength += SourceLength; + + ASSERT(TotalTransferLength <= BufferSize); + + TempMdl = TempMdl->Next; + } + + MemoryOffset.BufferOffset = 0; + MemoryOffset.BufferLength = (ULONG)TotalTransferLength; + + Status = WdfUsbTargetPipeFormatRequestForWrite(usbDeviceContext->BulkOutputPipe, WriteRequest, BufferMemoryObject, &MemoryOffset); + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContext->LookasideBuffer = BufferMemoryObject; + BufferMemoryObject = NULL; + } + + // + // set REQUEST_CONTEXT parameters. + // + + writeContext->Mdl = Mdl; + writeContext->BusObject = BusObject; + writeContext->Callback = Callback; + writeContext->RequestHandle = RequestHandle; + + WdfRequestSetCompletionRoutine(WriteRequest, WriteCompletionRoutine, writeContext); + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(30)); + + SentToDevice = WdfRequestSend(WriteRequest, WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), &SendOptions); + + Status = STATUS_PENDING; + + if (!SentToDevice) + { + Status = WdfRequestGetStatus(WriteRequest); + } + else + { + WriteRequest = NULL; + } + + if (NT_SUCCESS(Status)) + { + + // + // actual data write worked, see if we need to send the zlp + // + + if (WriteRequestZLP != NULL) + { + + NTSTATUS ZlpStatus; + + Status = WdfUsbTargetPipeFormatRequestForWrite(usbDeviceContext->BulkOutputPipe, WriteRequestZLP, NULL, NULL); + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + WdfRequestSetCompletionRoutine(WriteRequestZLP, WriteCompletionRoutine, writeContextZLP); + + WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions, 0); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions, WDF_REL_TIMEOUT_IN_SEC(30)); + + SentToDevice = WdfRequestSend(WriteRequestZLP, WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), &SendOptions); + + ZlpStatus = STATUS_PENDING; + + if (!SentToDevice) + { + + ZlpStatus = WdfRequestGetStatus(WriteRequestZLP); + } + else + { + WriteRequestZLP = NULL; + } + } + } + +Cleanup: + + ExReleaseRundownProtection(&usbDeviceContext->BulkPipeResetRundown); + + if (WriteRequest != NULL) + { + if (NULL != writeContext) + { + if (NULL != writeContext->LookasideBuffer) + { + WdfObjectDelete(writeContext->LookasideBuffer); + } + if (NULL != writeContext->UrbMemory) + { + WdfObjectDelete(writeContext->UrbMemory); + } + } + + FreeWriteRequest(BusObject->WdfUsbDevice, WriteRequest); + WriteRequest = NULL; + } + + if (WriteRequestZLP != NULL) + { + FreeWriteRequest(BusObject->WdfUsbDevice, WriteRequestZLP); + WriteRequestZLP = NULL; + } + + return Status; +} + +VOID BulkInReadComplete(__in WDFUSBPIPE Pipe, __in WDFMEMORY Memory, __in size_t NumBytesTransferred, __in WDFCONTEXT Context) + +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)Context; + PUCHAR Buffer = NULL; + PMDL Mdl = NULL; + PUCHAR DataBuffer = NULL; + + if (NumBytesTransferred > 0) + { + // + // actaully got some data + // + Buffer = (PUCHAR)WdfMemoryGetBuffer(Memory, NULL); + + // + // the header at the front is where we will put the MDL + // + Mdl = (PMDL)Buffer; + + // + // the actual payload starts after the header/mdl + // + DataBuffer = Buffer + BusObject->BulkInHeaderSize; + + ASSERT(((ULONG_PTR)DataBuffer & 0x7) == 0); + + // + // bytes transfered does not include the header + // + MmInitializeMdl(Mdl, DataBuffer, NumBytesTransferred); + + MmBuildMdlForNonPagedPool(Mdl); + + ASSERT(BusObject->BulkInHeaderSize >= MmSizeOfMdl(Mdl, NumBytesTransferred)); + + WdfObjectReference(Memory); + + (*BusObject->ReceiveDataCallback)(BusObject->ProtocolHandle, Memory, Mdl); + } + + return; +} + +BOOLEAN +BulkInReadError(__in WDFUSBPIPE Pipe, __in NTSTATUS Status, __in USBD_STATUS UsbdStatus) + +{ + return TRUE; +} + +VOID MbbBusReturnReceiveBuffer(__in MBB_BUS_HANDLE BusHandle, __in MBB_RECEIVE_CONTEXT ReceiveContext, __in PMDL Mdl) + +{ + WDFMEMORY Memory = (WDFMEMORY)ReceiveContext; + + WdfObjectDereference(Memory); + + return; +} + +NTSTATUS +CreateWriteRequest(WDFUSBDEVICE UsbDevice, WDFREQUEST* ReturnedWriteRequest) + +{ + + WDFREQUEST WriteRequest = NULL; + PUSB_WRITE_REQ_CONTEXT writeContext = NULL; + WDF_OBJECT_ATTRIBUTES objectAttribs; + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + NTSTATUS Status = STATUS_INVALID_PARAMETER; + + *ReturnedWriteRequest = NULL; + + usbDeviceContext = GetUsbDeviceContext(UsbDevice); + + if (usbDeviceContext->BulkOutputPipe == NULL) + { + goto Cleanup; + } + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttribs, USB_WRITE_REQ_CONTEXT); + objectAttribs.ParentObject = UsbDevice; + + // + // create the request + // + Status = WdfRequestCreate(&objectAttribs, WdfUsbTargetPipeGetIoTarget(usbDeviceContext->BulkOutputPipe), &WriteRequest); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + writeContext = GetWriteRequestContext(WriteRequest); + RtlZeroMemory(writeContext, sizeof(*writeContext)); + + // + // Preallocate the request timer to prevent the request from failing while trying to send it. + // + Status = WdfRequestAllocateTimer(WriteRequest); + + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + Status = WdfUsbTargetPipeFormatRequestForWrite(usbDeviceContext->BulkOutputPipe, WriteRequest, NULL, NULL); + if (!NT_SUCCESS(Status)) + { + + goto Cleanup; + } + + *ReturnedWriteRequest = WriteRequest; + WriteRequest = NULL; + +Cleanup: + + if (WriteRequest != NULL) + { + WdfObjectDelete(WriteRequest); + WriteRequest = NULL; + } + + return Status; +} + +NTSTATUS +PreAllocateWriteRequests(WDFUSBDEVICE UsbDevice) + +{ + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + WDFREQUEST WriteRequest = NULL; + NTSTATUS Status; + ULONG i = 0; + + usbDeviceContext = GetUsbDeviceContext(UsbDevice); + + for (i = 0; i < MAX_PREALLOCATED_WRITE_REQUESTS; i++) + { + Status = CreateWriteRequest(UsbDevice, &WriteRequest); + + if (!NT_SUCCESS(Status)) + { + break; + } + + Status = WdfCollectionAdd(usbDeviceContext->WriteRequestCollection, WriteRequest); + + if (!NT_SUCCESS(Status)) + { + WdfObjectDelete(WriteRequest); + WriteRequest = NULL; + break; + } + } + + return Status; +} + +NTSTATUS +GetWriteRequests(WDFUSBDEVICE UsbDevice, WDFREQUEST* ReturnedWriteRequest) +{ + + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + NTSTATUS Status = STATUS_SUCCESS; + WDF_REQUEST_REUSE_PARAMS ReuseParams; + PUSB_WRITE_REQ_CONTEXT writeContext = NULL; + + usbDeviceContext = GetUsbDeviceContext(UsbDevice); + + *ReturnedWriteRequest = NULL; + + if (usbDeviceContext->BulkOutputPipe == NULL) + { + return STATUS_UNSUCCESSFUL; + } + + WdfSpinLockAcquire(usbDeviceContext->WriteCollectionLock); + + *ReturnedWriteRequest = (WDFREQUEST)WdfCollectionGetLastItem(usbDeviceContext->WriteRequestCollection); + + if (*ReturnedWriteRequest == NULL) + { + // + // the collection is empty, try creating a new one + // + WdfSpinLockRelease(usbDeviceContext->WriteCollectionLock); + + Status = CreateWriteRequest(UsbDevice, ReturnedWriteRequest); + } + else + { + + WdfCollectionRemove(usbDeviceContext->WriteRequestCollection, *ReturnedWriteRequest); + + WdfSpinLockRelease(usbDeviceContext->WriteCollectionLock); + + WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, 0, STATUS_SUCCESS); + + WdfRequestReuse(*ReturnedWriteRequest, &ReuseParams); + } + + if (NT_SUCCESS(Status)) + { + writeContext = GetWriteRequestContext(*ReturnedWriteRequest); + RtlZeroMemory(writeContext, sizeof(*writeContext)); + } + + return Status; +} + +VOID FreeWriteRequest(WDFUSBDEVICE UsbDevice, WDFREQUEST WriteRequest) + +{ + PUSB_DEVICE_CONTEXT usbDeviceContext = NULL; + NTSTATUS Status = STATUS_SUCCESS; + ULONG RequestCount = 0; + + usbDeviceContext = GetUsbDeviceContext(UsbDevice); + + WdfSpinLockAcquire(usbDeviceContext->WriteCollectionLock); + + RequestCount = WdfCollectionGetCount(usbDeviceContext->WriteRequestCollection); + + if (RequestCount < MAX_PREALLOCATED_WRITE_REQUESTS * 2) + { + // + // put it back in the collection + // + Status = WdfCollectionAdd(usbDeviceContext->WriteRequestCollection, WriteRequest); + + if (NT_SUCCESS(Status)) + { + WriteRequest = NULL; + } + } + + WdfSpinLockRelease(usbDeviceContext->WriteCollectionLock); + + if (WriteRequest != NULL) + { + WdfObjectDelete(WriteRequest); + WriteRequest = NULL; + } + + return; +} + +VOID MbbBusResetDataPipes(_In_ MBB_BUS_HANDLE BusHandle) +{ + PBUS_OBJECT BusObject = (PBUS_OBJECT)BusHandle; + PUSB_DEVICE_CONTEXT usbDeviceContext = GetUsbDeviceContext(BusObject->WdfUsbDevice); + + if (!InterlockedCompareExchange(&usbDeviceContext->BulkPipeResetFlag, TRUE, FALSE)) + { + WdfWorkItemEnqueue(usbDeviceContext->BulkPipeResetWorkitem); + } + else + { + } +} + +VOID MbbUsbDeviceCyclePort(_In_ PUSB_DEVICE_CONTEXT usbDeviceContext) +{ + NTSTATUS Status = WdfUsbTargetDeviceCyclePortSynchronously(usbDeviceContext->BusObject->WdfUsbDevice); + if (!NT_SUCCESS(Status)) + { + } +} + +void ResetDataPipeWorkItem(_In_ WDFWORKITEM WorkItem) +{ + PUSB_DEVICE_CONTEXT usbDeviceContext = GetUsbDeviceContext(WdfWorkItemGetParentObject(WorkItem)); + + ExWaitForRundownProtectionRelease(&usbDeviceContext->BulkPipeResetRundown); + ExRundownCompleted(&usbDeviceContext->BulkPipeResetRundown); + + MbbUsbDeviceStopDataPipes(usbDeviceContext); + + MbbUsbDeviceResetBulkPipe(usbDeviceContext, TRUE); + + MbbUsbDeviceCyclePort(usbDeviceContext); + + MbbUsbDeviceStartDataPipes(usbDeviceContext); + + ExReInitializeRundownProtection(&usbDeviceContext->BulkPipeResetRundown); + + InterlockedExchange(&usbDeviceContext->BulkPipeResetFlag, FALSE); +} |
