WDF_USB_PIPE_TYPE CyFindUsbPipeType(__in UCHAR ucEndpointAddress,__in PDEVICE_CONTEXT pDevContext,__out WDFUSBPIPE* UsbPipeHandle) { WDFUSBPIPE UsbPipe; WDF_USB_PIPE_INFORMATION UsbPipeInfo; UCHAR ucIndex; for(ucIndex=0;ucIndex<pDevContext->ucActiveNumOfPipe;ucIndex++) { WDF_USB_PIPE_INFORMATION_INIT(&UsbPipeInfo); UsbPipe = WdfUsbInterfaceGetConfiguredPipe( pDevContext->UsbInterfaceConfig.Types.SingleInterface.ConfiguredUsbInterface, ucIndex, &UsbPipeInfo ); if(ucEndpointAddress == UsbPipeInfo.EndpointAddress ) { *UsbPipeHandle = UsbPipe; CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "Endpoint:0x%x found\n",ucEndpointAddress); return UsbPipeInfo.PipeType; } } CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "Endpoint 0x%x does not exist \n",ucEndpointAddress); return WdfUsbPipeTypeInvalid; }
/*++ Routine Description: Called by the framework when it receives Write requests. Arguments: Queue - Default queue handle Request - Handle to the read/write request Length - Length of the data buffer associated with the request. The default property of the queue is to not dispatch zero length read & write requests to the driver and complete is with status success. So we will never get a zero length request. --*/ VOID PSDrv_EvtIoWrite(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; PAGED_CODE(); // Get the pipe associate with this request. fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; if (pipe == NULL) { PSDrv_DbgPrint(1, ("PSDrv_EvtIoWrite: Invalid pipe!\n")); WdfRequestCompleteWithInformation(Request, STATUS_INVALID_PARAMETER, 0); return; } WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if((WdfUsbPipeTypeBulk == pipeInfo.PipeType) || (WdfUsbPipeTypeInterrupt == pipeInfo.PipeType)) { ReadWriteBulkEndPoints(Queue, Request, (ULONG)Length, WdfRequestTypeWrite); return; } else if(WdfUsbPipeTypeIsochronous == pipeInfo.PipeType) { ReadWriteIsochEndPoints(Queue, Request, (ULONG)Length, WdfRequestTypeWrite); return; } return; }
VOID Rio500_EvtIoWrite( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t Length ) /*++ Routine Description: Called by the framework when it receives Write requests. Arguments: Queue - Default queue handle Request - Handle to the read/write request Lenght - Length of the data buffer associated with the request. The default property of the queue is to not dispatch zero lenght read & write requests to the driver and complete is with status success. So we will never get a zero length request. Return Value: VOID --*/ { WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; PAGED_CODE(); // // Get the pipe associate with this request. // WDFDEVICE device = WdfIoQueueGetDevice(Queue); PDEVICE_CONTEXT pDevContext = GetDeviceContext(device); pipe = pDevContext->WritePipe; if (pipe == NULL) { Rio500_DbgPrint(1, ("Write pipe handle is NULL\n")); WdfRequestCompleteWithInformation(Request, STATUS_INVALID_PARAMETER, 0); return; } WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if (WdfUsbPipeTypeBulk == pipeInfo.PipeType) { ReadWriteBulkEndPoints(Queue, Request, (ULONG)Length, WdfRequestTypeWrite); return; } Rio500_DbgPrint(1, ("ISO transfer is not supported for buffered I/O transfer\n")); WdfRequestCompleteWithInformation(Request, STATUS_INVALID_DEVICE_REQUEST, 0); }
static VOID UsbChief_EvtIoRead(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; UNREFERENCED_PARAMETER(Queue); PAGED_CODE(); UsbChief_DbgPrint(DEBUG_RW, ("EvtIoRead %d\n", Length)); fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; if (pipe == NULL) { UsbChief_DbgPrint(0, ("pipe handle is NULL\n")); WdfRequestCompleteWithInformation(Request, STATUS_INVALID_PARAMETER, 0); return; } WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); UsbChief_ReadEndPoint(Queue, Request, (ULONG) Length); }
NTSTATUS Interface_InitContext(__in PDEVICE_CONTEXT deviceContext, __in PINTERFACE_CONTEXT interfaceContext) { NTSTATUS status = STATUS_SUCCESS; UCHAR pipeIndex; if (interfaceContext->Interface == WDF_NO_HANDLE) { // interface indexes are assigned only once during configuration. // memory may be corrupt // invalid config descriptor? // WDF decided not to give us an interface handle for some unknown reason USBERR("WdfUsbTargetDeviceGetInterface returned a null interface handle at index %u\n", interfaceContext->InterfaceIndex); return STATUS_FILE_CORRUPT_ERROR; } // get the configured alt setting index for this inteface interfaceContext->SettingIndex = WdfUsbInterfaceGetConfiguredSettingIndex(interfaceContext->Interface); // get the interface descriptor WdfUsbInterfaceGetDescriptor( interfaceContext->Interface, interfaceContext->SettingIndex, &interfaceContext->InterfaceDescriptor); // get the number of configured pipes interfaceContext->PipeCount = WdfUsbInterfaceGetNumConfiguredPipes(interfaceContext->Interface); // get the pipe handles and information for(pipeIndex = 0; pipeIndex < interfaceContext->PipeCount; pipeIndex++) { WDF_USB_PIPE_INFORMATION pipeInfo; WDFUSBPIPE pipe; PPIPE_CONTEXT pipeContext; // get the pipe handle and information WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); pipe = WdfUsbInterfaceGetConfiguredPipe(interfaceContext->Interface, pipeIndex, &pipeInfo); if (!pipe) { USBERR("WdfUsbInterfaceGetConfiguredPipe returned a null pipe handle at index %u\n", pipeIndex); // make sure we can't use this pipe interfaceContext->PipeCount = pipeIndex; status = STATUS_INSUFFICIENT_RESOURCES; return status; } // get the pipe context by endpoint id from the master pipe list // this is never null pipeContext = GetPipeContextByID(deviceContext, pipeInfo.EndpointAddress); // set the pipe context by index in the interface context interfaceContext->PipeContextByIndex[pipeIndex] = pipeContext; // update the pipe information // this needs to be done BEFORE calling Policy_InitPipe RtlCopyMemory(&pipeContext->PipeInformation, &pipeInfo, sizeof(WDF_USB_PIPE_INFORMATION)); // set the default pipe polices // NOTE: This is done only once for any given endpoint ID Policy_InitPipe(deviceContext, pipeContext); // always update the pipe handle pipeContext->Pipe = pipe; pipeInfo.MaximumTransferSize = Pipe_CalcMaxTransferSize(IsHighSpeedDevice(deviceContext), pipeInfo.PipeType, pipeInfo.MaximumPacketSize, pipeInfo.MaximumTransferSize); pipeContext->PipeInformation.MaximumTransferSize = pipeInfo.MaximumTransferSize; USBDBG("configured %s pipe: PipeID=%02Xh MaximumPacketSize=%u MaximumTransferSize=%u PipeType=%s\n", GetEndpointDirString(pipeInfo.EndpointAddress), pipeInfo.EndpointAddress, pipeInfo.MaximumPacketSize, pipeInfo.MaximumTransferSize, GetPipeTypeString(pipeInfo.PipeType)); } return status; }
VOID UsbSamp_EvtReadWriteCompletion( _In_ WDFREQUEST Request, _In_ WDFIOTARGET Target, PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, _In_ WDFCONTEXT Context ) /*++ Routine Description: This is the completion routine for reads/writes If the irp completes with success, we check if we need to recirculate this irp for another stage of transfer. Arguments: Context - Driver supplied context Device - Device handle Request - Request handle Params - request completion params Return Value: None --*/ { WDFUSBPIPE pipe; ULONG stageLength = 0; NTSTATUS status; PREQUEST_CONTEXT rwContext; ULONG bytesReadWritten; WDFMEMORY_OFFSET offset; PCHAR operation; PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; PPIPE_CONTEXT pipeContext; WDF_USB_PIPE_INFORMATION pipeInfo; ULONG maxTransferSize; PDEVICE_CONTEXT deviceContext; usbCompletionParams = CompletionParams->Parameters.Usb.Completion; rwContext = GetRequestContext(Request); deviceContext = Context; if (rwContext->Read) { operation = "Read"; bytesReadWritten = (ULONG)usbCompletionParams->Parameters.PipeRead.Length; } else { operation = "Write"; bytesReadWritten = (ULONG)usbCompletionParams->Parameters.PipeWrite.Length; } pipe = (WDFUSBPIPE) Target; pipeContext = GetPipeContext(pipe); WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe,&pipeInfo); status = CompletionParams->IoStatus.Status; if (!NT_SUCCESS(status)){ // // Queue a workitem to reset the pipe because the completion could be // running at DISPATCH_LEVEL. // TODO: preallocate per pipe workitem to avoid allocation failure. QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe); goto End; } rwContext->Numxfer += bytesReadWritten; // // If there is anything left to transfer. // if (rwContext->Length == 0) { // // this is the last transfer // WdfRequestSetInformation(Request, rwContext->Numxfer); goto End; } // // Start another transfer // UsbSamp_DbgPrint(3, ("Stage next %s transfer...\n", operation)); // // The transfer request is for totalLength. // We can perform a max of maxTransfersize in each stage. // maxTransferSize = GetMaxTransferSize(pipe, deviceContext); if (rwContext->Length > maxTransferSize) { stageLength = maxTransferSize; } else { stageLength = rwContext->Length; } offset.BufferOffset = rwContext->Numxfer; offset.BufferLength = stageLength; rwContext->Length -= stageLength; if (rwContext->Read) { status = WdfUsbTargetPipeFormatRequestForRead( pipe, Request, usbCompletionParams->Parameters.PipeRead.Buffer, &offset); } else { status = WdfUsbTargetPipeFormatRequestForWrite( pipe, Request, usbCompletionParams->Parameters.PipeWrite.Buffer, &offset); } if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("WdfUsbTargetPipeFormat%sRequest failed 0x%x\n", operation, status)); goto End; } #if (NTDDI_VERSION >= NTDDI_WIN8) // // If the request is for a super speed bulk pipe with streams, // configure its urb's PipeHandle with its associated stream's PipeHandle // if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && pipeContext->StreamConfigured == TRUE) { ConfigureStreamPipeHandleForRequest(Request, pipe); } #endif WdfRequestSetCompletionRoutine( Request, UsbSamp_EvtReadWriteCompletion, deviceContext); // // Send the request asynchronously. // if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { UsbSamp_DbgPrint(1, ("WdfRequestSend for %s failed\n", operation)); status = WdfRequestGetStatus(Request); goto End; } // // Else when the request completes, this completion routine will be // called again. // return; End: // // We are here because the request failed or some other call failed. // Dump the request context, complete the request and return. // DbgPrintRWContext(rwContext); UsbSamp_DbgPrint(3, ("%s request completed with status 0x%x\n", operation, status)); WdfRequestComplete(Request, status); return; }
VOID ReadWriteBulkEndPoints( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG Length, _In_ WDF_REQUEST_TYPE RequestType ) /*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or RP_MJ_WRITE request. This read/write is performed in stages of maximum transfer size. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ { size_t totalLength = Length; size_t stageLength = 0; NTSTATUS status; PVOID virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDFMEMORY reqMemory; WDFMEMORY_OFFSET offset; WDF_OBJECT_ATTRIBUTES objectAttribs; PDEVICE_CONTEXT deviceContext; PPIPE_CONTEXT pipeContext; ULONG maxTransferSize; UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - begins\n")); // // First validate input parameters. // deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { UsbSamp_DbgPrint(1, ("Transfer length > circular buffer\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { UsbSamp_DbgPrint(1, ("RequestType has to be either Read or Write\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } // // Get the pipe associate with this request. // fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; pipeContext = GetPipeContext(pipe); WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); rwContext = GetRequestContext(Request); if (RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputBuffer(Request, Length, &virtualAddress, &totalLength); rwContext->Read = TRUE; } else { //Write status = WdfRequestRetrieveInputBuffer(Request, Length, &virtualAddress, &totalLength); rwContext->Read = FALSE; } if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputBuffer failed\n")); goto Exit; } // // The transfer request is for totalLength. // We can perform a max of maxTransfersize in each stage. // maxTransferSize = GetMaxTransferSize(pipe, deviceContext); if (totalLength > maxTransferSize) { stageLength = maxTransferSize; } else { stageLength = totalLength; } WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreatePreallocated(&objectAttribs, virtualAddress, totalLength, &reqMemory); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfMemoryCreatePreallocated failed\n")); goto Exit; } offset.BufferOffset = 0; offset.BufferLength = stageLength; // // The framework format call validates to make sure that you are reading or // writing to the right pipe type, sets the appropriate transfer flags, // creates an URB and initializes the request. // if (RequestType == WdfRequestTypeRead) { UsbSamp_DbgPrint(3, ("Read operation\n")); status = WdfUsbTargetPipeFormatRequestForRead(pipe, Request, reqMemory, &offset); } else { UsbSamp_DbgPrint(3, ("Write operation\n")); status = WdfUsbTargetPipeFormatRequestForWrite(pipe, Request, reqMemory, &offset); } if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("WdfUsbTargetPipeFormatRequest failed 0x%x\n", status)); goto Exit; } #if (NTDDI_VERSION >= NTDDI_WIN8) // // If the request is for a super speed bulk pipe with streams, // configure its urb's PipeHandle with its associated stream's PipeHandle // if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && pipeContext->StreamConfigured == TRUE) { ConfigureStreamPipeHandleForRequest(Request, pipe); } #endif WdfRequestSetCompletionRoutine( Request, UsbSamp_EvtReadWriteCompletion, deviceContext); // // set REQUEST_CONTEXT parameters. // rwContext->Length = (ULONG)totalLength - (ULONG)stageLength; rwContext->Numxfer = 0; // // Send the request asynchronously. // if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { UsbSamp_DbgPrint(1, ("WdfRequestSend failed\n")); status = WdfRequestGetStatus(Request); goto Exit; } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); } UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - ends\n")); return; }
VOID ReadWriteBulkEndPoints( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG Length, _In_ WDF_REQUEST_TYPE RequestType ) /*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or WdfRequestTypeWrite request. This read/write is performed in stages of maximum transfer size. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ { PMDL newMdl=NULL, requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG totalLength = Length; ULONG stageLength = 0; ULONG urbFlags = 0; NTSTATUS status; ULONG_PTR virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDF_OBJECT_ATTRIBUTES objectAttribs; USBD_PIPE_HANDLE usbdPipeHandle; PDEVICE_CONTEXT deviceContext; ULONG maxTransferSize; PPIPE_CONTEXT pipeContext; UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - begins\n")); // // First validate input parameters. // deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { UsbSamp_DbgPrint(1, ("Transfer length > circular buffer\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { UsbSamp_DbgPrint(1, ("RequestType has to be either Read or Write\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } // // Get the pipe associate with this request. // fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; pipeContext = GetPipeContext(pipe); WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if ((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) { UsbSamp_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt\n")); status = STATUS_INVALID_DEVICE_REQUEST; goto Exit; } rwContext = GetRequestContext(Request); if (RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed %x\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_IN; rwContext->Read = TRUE; UsbSamp_DbgPrint(3, ("Read operation\n")); } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed %x\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_OUT; rwContext->Read = FALSE; UsbSamp_DbgPrint(3, ("Write operation\n")); } urbFlags |= USBD_SHORT_TRANSFER_OK; virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); // // The transfer request is for totalLength. // We can perform a max of maxTransfersize in each stage. // maxTransferSize = GetMaxTransferSize(pipe, deviceContext); if (totalLength > maxTransferSize) { stageLength = maxTransferSize; } else { stageLength = totalLength; } newMdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL); if (newMdl == NULL) { UsbSamp_DbgPrint(1, ("Failed to alloc mem for mdl\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } // // map the portion of user-buffer described by an mdl to another mdl // IoBuildPartialMdl(requestMdl, newMdl, (PVOID) virtualAddress, stageLength); WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfUsbTargetDeviceCreateUrb(deviceContext->WdfUsbTargetDevice, &objectAttribs, &urbMemory, &urb); if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("WdfUsbTargetDeviceCreateUrb failed %x\n", status)); goto Exit; } #if (NTDDI_VERSION >= NTDDI_WIN8) if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && pipeContext->StreamConfigured == TRUE) { // // For super speed bulk pipe with streams, we specify one of its associated // usbd pipe handles to format an URB for sending or receiving data. // The usbd pipe handle is returned by the HCD via sucessful open-streams request // usbdPipeHandle = GetStreamPipeHandleFromBulkPipe(pipe); } else { usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); } #else usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); #endif UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, urbFlags, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL ); if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, UsbSamp_EvtReadWriteCompletion, deviceContext); // // set REQUEST_CONTEXT parameters. // rwContext->UrbMemory = urbMemory; rwContext->Mdl = newMdl; rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; rwContext->VirtualAddress = virtualAddress + stageLength; if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { status = WdfRequestGetStatus(Request); NT_ASSERT(!NT_SUCCESS(status)); } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - ends\n")); return; }
void AndroidUsbDeviceObject::OnGetEndpointInformationCtl( WDFREQUEST request, size_t input_buf_len, size_t output_buf_len) { ASSERT_IRQL_LOW_OR_DISPATCH(); // Check the buffers first if (input_buf_len < sizeof(AdbQueryEndpointInformation)) { WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE); return; } if (output_buf_len < sizeof(AdbEndpointInformation)) { WdfRequestCompleteWithInformation(request, STATUS_BUFFER_TOO_SMALL, sizeof(AdbEndpointInformation)); return; } // Get the output buffer NTSTATUS status; AdbEndpointInformation* ret_info = reinterpret_cast<AdbEndpointInformation*> (OutAddress(request, &status)); ASSERT(NT_SUCCESS(status) && (NULL != ret_info)); if (!NT_SUCCESS(status)) { WdfRequestComplete(request, status); return; } // Get the input buffer AdbQueryEndpointInformation* in = reinterpret_cast<AdbQueryEndpointInformation*> (InAddress(request, &status)); ASSERT(NT_SUCCESS(status) && (NULL != in)); if (!NT_SUCCESS(status)) { WdfRequestComplete(request, status); return; } // Lets see what exactly is queried UCHAR endpoint_index = in->endpoint_index; if (ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) endpoint_index = bulk_write_pipe_index(); else if (ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) endpoint_index = bulk_read_pipe_index(); // Make sure index is valid and within interface range if ((INVALID_UCHAR == endpoint_index) || (endpoint_index >= configured_pipes_num())) { WdfRequestComplete(request, STATUS_NOT_FOUND); return; } // Get endpoint information WDF_USB_PIPE_INFORMATION pipe_info; WDF_USB_PIPE_INFORMATION_INIT(&pipe_info); WDFUSBPIPE wdf_pipe_obj = WdfUsbInterfaceGetConfiguredPipe(wdf_usb_interface(), endpoint_index, &pipe_info); if (NULL == wdf_pipe_obj) { WdfRequestComplete(request, STATUS_NOT_FOUND); return; } // Copy endpoint info to the output ret_info->max_packet_size = pipe_info.MaximumPacketSize; ret_info->endpoint_address = pipe_info.EndpointAddress; ret_info->polling_interval = pipe_info.Interval; ret_info->setting_index = pipe_info.SettingIndex; ret_info->endpoint_type = static_cast<AdbEndpointType>(pipe_info.PipeType); ret_info->max_transfer_size = pipe_info.MaximumTransferSize; WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, sizeof(AdbEndpointInformation)); }
void AndroidUsbDeviceObject::OnEvtDeviceFileCreate(WDFREQUEST request, WDFFILEOBJECT wdf_fo) { ASSERT_IRQL_PASSIVE(); ASSERT(IsInterfaceSelected()); if (!IsInterfaceSelected()) { WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE); return; } PUNICODE_STRING file_name = WdfFileObjectGetFileName(wdf_fo); ASSERT(NULL != file_name); if (NULL == file_name) { WdfRequestComplete(request, STATUS_OBJECT_NAME_INVALID); return; } WDFUSBPIPE wdf_pipe_obj = NULL; WDF_USB_PIPE_INFORMATION pipe_info; // TODO: Share / access check here? // Lets see if this is a device open if (0 != file_name->Length) { // This is a pipe open. Lets retrieve pipe index from the name UCHAR pipe_index = GetPipeIndexFromFileName(file_name); if (INVALID_UCHAR == pipe_index) { GoogleDbgPrint("\n!!!!! There is no pipe index for file %wZ", file_name); WdfRequestComplete(request, STATUS_OBJECT_NAME_INVALID); return; } // Make sure that pipe index doesn't exceed number of pipes if (pipe_index >= configured_pipes_num()) { WdfRequestComplete(request, STATUS_OBJECT_NAME_NOT_FOUND); return; } // Retrieve the pipe along with the pipe info WDF_USB_PIPE_INFORMATION_INIT(&pipe_info); wdf_pipe_obj = WdfUsbInterfaceGetConfiguredPipe(wdf_usb_interface(), pipe_index, &pipe_info); if (NULL == wdf_pipe_obj) { GoogleDbgPrint("\n!!!!! There is no pipe for index %u for file %wZ", pipe_index, file_name); WdfRequestComplete(request, STATUS_OBJECT_NAME_NOT_FOUND); return; } } // If we're here this must be either device open or pipe open ASSERT((NULL != wdf_pipe_obj) || (0 == file_name->Length)); // Create our file object extension for this file AndroidUsbFileObject* wdf_file_ext = NULL; NTSTATUS status; if (0 == file_name->Length) { // This is a device FO. Create wrapper for device FO ASSERT(NULL == wdf_pipe_obj); wdf_file_ext = new(NonPagedPool, GANDR_POOL_TAG_DEVICE_FO) AndroidUsbDeviceFileObject(this, wdf_fo); ASSERT(NULL != wdf_file_ext); if (NULL == wdf_file_ext) { WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); return; } // Initialize extension status = wdf_file_ext->Initialize(); if (!NT_SUCCESS(status)) { delete wdf_file_ext; WdfRequestComplete(request, status); return; } } else { // This is a pipe file. Create and initialize appropriate extension for it. status = CreatePipeFileObjectExt(wdf_fo, wdf_pipe_obj, &pipe_info, &wdf_file_ext); ASSERT((NULL != wdf_file_ext) || !NT_SUCCESS(status)); if (!NT_SUCCESS(status)) { WdfRequestComplete(request, status); return; } } ASSERT(GetAndroidUsbFileObjectFromHandle(wdf_fo) == wdf_file_ext); WdfRequestComplete(request, STATUS_SUCCESS); }
NTSTATUS ConfigureUsbPipes(PDEVICE_CONTEXT DeviceContext) { NTSTATUS status = STATUS_SUCCESS; BYTE index = 0; WDF_USB_PIPE_INFORMATION pipeConfig; WDFUSBPIPE pipe = NULL; BYTE numEndpoints; // For debug numEndpoints = WdfUsbInterfaceGetNumEndpoints( DeviceContext->UsbInterface, 0 ); KdPrint((__DRIVER_NAME " Found %i EndPoints\n", numEndpoints)); // For debug DeviceContext->UsbInterruptPipe = NULL; DeviceContext->UsbBulkInPipe = NULL; DeviceContext->UsbBulkOutPipe = NULL; WDF_USB_PIPE_INFORMATION_INIT(&pipeConfig); // Init pipe config // // Scan all pipe from USB Interface // do { pipe = WdfUsbInterfaceGetConfiguredPipe(DeviceContext->UsbInterface, index, &pipeConfig); if (NULL == pipe) break; // For debug KdPrint((__DRIVER_NAME " Pipe[%i].PacketSize = %i\n", index, pipeConfig.MaximumPacketSize)); // For debug /*None of our data transfers will have a guarantee that the requested data size is a multiple of the packet size.*/ WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); if(WdfUsbPipeTypeInterrupt == pipeConfig.PipeType) // Interrupt pipe { KdPrint((__DRIVER_NAME " Found Interrupt Pipe at index %i\n", index)); DeviceContext->UsbInterruptPipe = pipe; } else if(WdfUsbPipeTypeBulk == pipeConfig.PipeType) // Bulk pipe { if(TRUE == WdfUsbTargetPipeIsInEndpoint(pipe)) // In EndPoint of Bulk { KdPrint((__DRIVER_NAME " Found In Endpoint Pipe at index %i\n", index)); DeviceContext->UsbBulkInPipe = pipe; } else if(TRUE == WdfUsbTargetPipeIsOutEndpoint(pipe)) { KdPrint((__DRIVER_NAME " Found Out Endpoint Pipe at index %i\n", index)); DeviceContext->UsbBulkOutPipe = pipe; // Out EndPoint of Bulk } } index++; // Encreate index of Pipe } while (NULL != pipe); // Check for all 3 pipe: interrupt, Bulk In, Bulk Out for our device if((NULL == DeviceContext->UsbInterruptPipe) || (NULL == DeviceContext->UsbBulkInPipe) || (NULL == DeviceContext->UsbBulkOutPipe)) { KdPrint((__DRIVER_NAME "Not all expected USB pipes were found.\n")); return STATUS_INVALID_PARAMETER; } return status; }
NTSTATUS SelectInterfaces( __in WDFDEVICE Device ) /*++ Routine Description: This helper routine selects the configuration, interface and creates a context for every pipe (end point) in that interface. Arguments: Device - Handle to a framework device Return Value: NT status value --*/ { WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; UCHAR index; UCHAR numberConfiguredPipes; PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", status); // // Since the Osr USB fx2 device is capable of working at high speed, the only reason // the device would not be working at high speed is if the port doesn't // support it. If the port doesn't support high speed it is a 1.1 port // if ((pDeviceContext->UsbDeviceTraits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) { GUID activity = DeviceToActivityId(Device); TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " On a 1.1 USB port on Windows Vista" " this is expected as the OSR USB Fx2 board's Interrupt EndPoint descriptor" " doesn't conform to the USB specification. Windows Vista detects this and" " returns an error. \n" ); EventWriteSelectConfigFailure( &activity, pDeviceContext->DeviceName, pDeviceContext->Location, status ); } return status; } pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; numberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; // // Get pipe handles // for(index=0; index < numberConfiguredPipes; index++) { WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); pipe = WdfUsbInterfaceGetConfiguredPipe( pDeviceContext->UsbInterface, index, //PipeIndex, &pipeInfo ); // // Tell the framework that it's okay to read less than // MaximumPacketSize // WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "Interrupt Pipe is 0x%p\n", pipe); pDeviceContext->InterruptPipe = pipe; } if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && WdfUsbTargetPipeIsInEndpoint(pipe)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "BulkInput Pipe is 0x%p\n", pipe); pDeviceContext->BulkReadPipe = pipe; } if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && WdfUsbTargetPipeIsOutEndpoint(pipe)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "BulkOutput Pipe is 0x%p\n", pipe); pDeviceContext->BulkWritePipe = pipe; } } // // If we didn't find all the 3 pipes, fail the start. // if(!(pDeviceContext->BulkWritePipe && pDeviceContext->BulkReadPipe && pDeviceContext->InterruptPipe)) { status = STATUS_INVALID_DEVICE_STATE; TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Device is not configured properly %!STATUS!\n", status); return status; } return status; }
static VOID UsbChief_ReadEndPoint(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG totalLength) { PMDL newMdl=NULL, requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG stageLength = 0; NTSTATUS status; ULONG_PTR virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDF_OBJECT_ATTRIBUTES objectAttribs; USBD_PIPE_HANDLE usbdPipeHandle; PDEVICE_CONTEXT deviceContext; UsbChief_DbgPrint(DEBUG_RW, ("UsbChief_DispatchReadWrite - begins\n")); deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); rwContext = GetRequestContext(Request); status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)){ UsbChief_DbgPrint(0, ("WdfRequestRetrieveOutputWdmMdl failed %x\n", status)); goto Exit; } virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); if (totalLength > MAX_TRANSFER_SIZE) stageLength = MAX_TRANSFER_SIZE; else stageLength = totalLength; newMdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL); if (!newMdl) { UsbChief_DbgPrint(0, ("Failed to alloc mem for mdl\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } IoBuildPartialMdl(requestMdl, newMdl, (PVOID)virtualAddress, stageLength); WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreate(&objectAttribs, NonPagedPool, POOL_TAG, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urbMemory, (PVOID*) &urb); if (!NT_SUCCESS(status)) { UsbChief_DbgPrint(0, ("Failed to alloc mem for urb\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL ); if (!NT_SUCCESS(status)) { UsbChief_DbgPrint(0, ("Failed to format requset for urb\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, UsbChief_ReadCompletion, NULL); rwContext->UrbMemory = urbMemory; rwContext->Mdl = newMdl; rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; rwContext->VirtualAddress = virtualAddress + stageLength; if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } }
/*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or WdfRequestTypeWrite request. This read/write is performed in stages of MAX_TRANSFER_SIZE. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ VOID ReadWriteBulkEndPoints(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG Length, IN WDF_REQUEST_TYPE RequestType) { PMDL newMdl = NULL; PMDL requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG totalLength = Length; ULONG stageLength = 0; ULONG urbFlags = 0; NTSTATUS status; ULONG_PTR virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDF_OBJECT_ATTRIBUTES objectAttribs; USBD_PIPE_HANDLE usbdPipeHandle; PDEVICE_CONTEXT deviceContext; WDF_REQUEST_SEND_OPTIONS sendOptions; PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - begins\n")); // First validate input parameters. deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { PSDrv_DbgPrint(1, ("Transfer length (%d) is bigger then MaximumTransferSize (%d)!\n", totalLength, deviceContext->MaximumTransferSize)); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { PSDrv_DbgPrint(1, ("RequestType has to be either Read or Write! (RequestType = %d)\n", RequestType)); status = STATUS_INVALID_PARAMETER; goto Exit; } // Get the pipe associate with this request. fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) { PSDrv_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt! (PipeType = %d)\n", pipeInfo.PipeType)); status = STATUS_INVALID_DEVICE_REQUEST; goto Exit; } rwContext = GetRequestContext(Request); if(RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_IN; rwContext->Read = TRUE; PSDrv_DbgPrint(3, ("This is a read operation...\n")); } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_OUT; rwContext->Read = FALSE; PSDrv_DbgPrint(3, ("This is a write operation...\n")); } urbFlags |= USBD_SHORT_TRANSFER_OK; virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); // The transfer request is for totalLength. We can perform a max of MAX_TRANSFER_SIZE in each stage. if (totalLength > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } else { stageLength = totalLength; } newMdl = IoAllocateMdl((PVOID)virtualAddress, totalLength, FALSE, FALSE, NULL); if (newMdl == NULL) { PSDrv_DbgPrint(1, ("IoAllocateMdl failed! (newMdl is NULL)\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } // Map the portion of user-buffer described by an mdl to another mdl IoBuildPartialMdl(requestMdl, newMdl, (PVOID)virtualAddress, stageLength); WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreate(&objectAttribs, NonPagedPool, POOL_TAG, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urbMemory, (PVOID*)&urb); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfMemoryCreate for urbMemory failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, urbFlags, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL); // Set REQUEST_CONTEXT parameters. rwContext->UrbMemory = urbMemory; rwContext->Mdl = newMdl; rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; rwContext->VirtualAddress = virtualAddress + stageLength; // Set the timeout if (fileContext->nTimeOut != 0) { WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(fileContext->nTimeOut)); PSDrv_DbgPrint(3, ("Pipe timeout is set to: %d\n", fileContext->nTimeOut)); if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), &sendOptions)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } else { if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - ends\n")); return; }
NTSTATUS AndroidUsbDeviceObject::SelectInterfaces() { ASSERT_IRQL_PASSIVE(); ASSERT(IsDeviceConfigured()); if (!IsDeviceConfigured()) return STATUS_INTERNAL_ERROR; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS config_params; PWDF_USB_INTERFACE_SETTING_PAIR pairs = NULL; // TODO: We need to find a way (possibly by looking at each // interface descriptor) to get index of the ADB interface in multiinterface // configuration. UCHAR adb_interface_index = 0; if (IsSingleInterfaceDevice()) { // Our device has only one interface, so we don't have to bother with // multiple interfaces at all. GoogleDbgPrint("\n********** Device reports single interface"); // Select single interface configuration WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&config_params); } else { // Configure multiple interfaces ULONG num_interf = GetInterfaceCount(); GoogleDbgPrint("\n********** Device reports %u interfaces", num_interf); // Allocate pairs for each interface pairs = new(PagedPool, GANDR_POOL_TAG_INTERF_PAIRS) WDF_USB_INTERFACE_SETTING_PAIR[num_interf]; ASSERT(NULL != pairs); if (NULL == pairs) return STATUS_INSUFFICIENT_RESOURCES; adb_interface_index = 1; // Initialize each interface pair for (UCHAR pair = 0; pair < num_interf; pair++) { pairs[pair].SettingIndex = 0; pairs[pair].UsbInterface = WdfUsbTargetDeviceGetInterface(wdf_target_device(), pair); ASSERT(NULL != pairs[pair].UsbInterface); if (NULL == pairs[pair].UsbInterface) { delete[] pairs; return STATUS_INTERNAL_ERROR; } } // Select multiinterface configuration WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&config_params, (UCHAR)num_interf, pairs); } NTSTATUS status = WdfUsbTargetDeviceSelectConfig(wdf_target_device(), WDF_NO_OBJECT_ATTRIBUTES, &config_params); if (NULL != pairs) delete[] pairs; // ASSERT(NT_SUCCESS(status)); if (!NT_SUCCESS(status)) return status; #if DBG PrintSelectedConfig(&config_params); #endif // DBG wdf_usb_interface_ = WdfUsbTargetDeviceGetInterface(wdf_target_device(), adb_interface_index); ASSERT(NULL != wdf_usb_interface_); if (NULL == wdf_usb_interface_) return STATUS_INTERNAL_ERROR; configured_pipes_num_ = WdfUsbInterfaceGetNumEndpoints(wdf_usb_interface(), 0); ASSERT(0 != configured_pipes_num_); // Cache selected interface descriptor BYTE setting_index = WdfUsbInterfaceGetConfiguredSettingIndex(wdf_usb_interface()); WdfUsbInterfaceGetDescriptor(wdf_usb_interface(), setting_index, &interface_descriptor_); #if DBG PrintInterfaceDescriptor(interface_descriptor()); #endif // DBG // Iterate over pipes, decoding and saving info about bulk r/w pipes for // easier and faster addressing later on when they get opened for (UCHAR pipe = 0; pipe < configured_pipes_num(); pipe++) { WDF_USB_PIPE_INFORMATION pipe_info; WDF_USB_PIPE_INFORMATION_INIT(&pipe_info); WDFUSBPIPE wdf_pipe_obj = WdfUsbInterfaceGetConfiguredPipe(wdf_usb_interface(), pipe, &pipe_info); ASSERT(NULL != wdf_pipe_obj); if (NULL != wdf_pipe_obj) { if ((WdfUsbPipeTypeBulk == pipe_info.PipeType) && WDF_USB_PIPE_DIRECTION_IN(pipe_info.EndpointAddress)) { // This is a bulk read pipe ASSERT(!IsBulkReadPipeKnown()); bulk_read_pipe_index_ = pipe; } else { ASSERT(!IsBulkWritePipeKnown()); bulk_write_pipe_index_ = pipe; } } #if DBG PrintPipeInformation(&pipe_info, pipe); #endif // DBG } // At the end we must have calculated indexes for both, // bulk read and write pipes ASSERT(!NT_SUCCESS(status) || (IsBulkReadPipeKnown() && IsBulkWritePipeKnown())); return status; }
/////////////////////////////////////////////////////////////////////////////// // // BasicUsbEvtDevicePrepareHardware // // This routine is called by the framework when a device of // the type we support is coming online. Our job will be to // create our WDFUSBDEVICE and configure it. // // INPUTS: // // Device - One of our WDFDEVICE objects // // ResourceList - We're a USB device, so not used // // ResourceListTranslated - We're a USB device, so not // used // // OUTPUTS: // // None. // // RETURNS: // // STATUS_SUCCESS, otherwise an error indicating why the driver could not // load. // // IRQL: // // This routine is called at IRQL == PASSIVE_LEVEL. // // NOTES: // // /////////////////////////////////////////////////////////////////////////////// NTSTATUS BasicUsbEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ) { NTSTATUS status; PBASICUSB_DEVICE_CONTEXT devContext; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS selectConfigParams; WDFUSBINTERFACE configuredInterface; WDF_USB_PIPE_INFORMATION pipeInfo; UCHAR numPipes; UCHAR pipeIndex; WDFUSBPIPE configuredPipe; WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); #if DBG DbgPrint("BasicUsbEvtDevicePrepareHardware\n"); #endif devContext = BasicUsbGetContextFromDevice(Device); // // First thing to do is create our WDFUSBDEVICE. This is the // special USB I/O target that we'll be using to configure our // device and to send control requests. // // Under very rare cirumstances (i.e. resource rebalance of the // host controller) it's possible to come through here multiple // times. We could handle this by having an // EvtDeviceReleaseHardware and cleaning up the USB device // target, but we'll just leave it around and avoid creating it // multiple times with this check. No race condition as our // Prepare and Release can't run in parallel for the same device // if (devContext->BasicUsbUsbDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &devContext->BasicUsbUsbDevice); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfUsbTargetDeviceCreate failed 0x%0x\n", status); #endif return status; } } // // Now that our WDFUSBDEVICE is created, it's time to select // our configuration and enable our interface. // // // The OSRFX2 device only has a single interface, so we'll // initialize our select configuration parameters structure // using the specially provided macro // WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &selectConfigParams); // // And actually select our configuration. // status = WdfUsbTargetDeviceSelectConfig(devContext->BasicUsbUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &selectConfigParams); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfUsbTargetDeviceSelectConfig failed 0x%0x\n", status); #endif return status; } // // Our single interface has been configured. Let's grab the // WDFUSBINTERFACE object so that we can get our pipes. // configuredInterface = selectConfigParams.Types.SingleInterface.ConfiguredUsbInterface; // // How many pipes were configure? // numPipes = selectConfigParams.Types.SingleInterface.NumberConfiguredPipes; // // For all the pipes that were configured.... // for(pipeIndex = 0; pipeIndex < numPipes; pipeIndex++) { // // We'll need to find out the type the pipe, which we'll do // by supplying a pipe information structure when calling // WdfUsbInterfaceGetConfiguredPipe // WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); // // Get the configured pipe. // configuredPipe = WdfUsbInterfaceGetConfiguredPipe(configuredInterface, pipeIndex, &pipeInfo); // // For this device, we're looking for three pipes: // // 1) A Bulk IN pipe // 2) A Bulk OUT pipe // 3) An Interrupt IN pipe // // // First, let's see what type of pipe it is... // switch (pipeInfo.PipeType) { case WdfUsbPipeTypeBulk: { // // Bulk pipe. Determine if it's an IN pipe or not. // if (WdfUsbTargetPipeIsInEndpoint(configuredPipe)) { // // Bulk IN pipe. Should only ever get one of these... // ASSERT(devContext->BulkInPipe == NULL); devContext->BulkInPipe = configuredPipe; } else { // // HAS to be an OUT... // ASSERT(WdfUsbTargetPipeIsOutEndpoint(configuredPipe)); // // Bulk OUT pipe. Should only ever get one of these... // ASSERT(devContext->BulkOutPipe == NULL); devContext->BulkOutPipe = configuredPipe; } break; } case WdfUsbPipeTypeInterrupt: { // // We're only expecting an IN interrupt pipe // ASSERT(WdfUsbTargetPipeIsInEndpoint(configuredPipe)); // // And we're only expected one of them // ASSERT(devContext->InterruptInPipe == NULL); devContext->InterruptInPipe = configuredPipe; break; } default: { // // Don't know what it is, don't care what it is... // #if DBG DbgPrint("Unexpected pipe type? 0x%x\n", pipeInfo.PipeType); #endif break; } } } // // We hopefully have found everything we need... // if (devContext->BulkInPipe == NULL || devContext->BulkOutPipe == NULL || devContext->InterruptInPipe == NULL) { #if DBG DbgPrint("Didn't find expected pipes. BIN=0x%p, BOUT=0x%p, IIN=0x%p\n", devContext->BulkInPipe, devContext->BulkOutPipe, devContext->InterruptInPipe); #endif return STATUS_DEVICE_CONFIGURATION_ERROR; } // // By default, KMDF will not allow any non-MaxPacketSize // aligned I/O to be done against IN pipes. This is to avoid // hitting "babble" conditions, which occur when the device // sends more data than what you've asked it for. // // Our device doesn't babble, so we don't need this check on // our IN pipes. // WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(devContext->BulkInPipe); WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(devContext->InterruptInPipe); // // For fun, we're going to hang a continuous reader out on the // interrupt endpoint. By doing so, we'll get called at // BasicUsbInterruptPipeReadComplete every time someone toggles // the switches on the switch pack. // // // Initialize the continuous reader config structure, specifying // our callback, our context, and the size of the transfers. // WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, BasicUsbInterruptPipeReadComplete, devContext, sizeof(UCHAR)); // // And create the continuous reader. // // Note that the continuous reader is not started by default, so // we'll need to manually start it when we are called at // EvtD0Entry. // status = WdfUsbTargetPipeConfigContinuousReader(devContext->InterruptInPipe, &contReaderConfig); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfUsbTargetPipeConfigContinuousReader failed 0x%0x\n", status); #endif return status; } return STATUS_SUCCESS; }
// 并行处理 VOID CY001Drv::DeviceIoControlParallel(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode) { NTSTATUS status = STATUS_SUCCESS; ULONG ulRetLen = 0; size_t size = 0; void* pBufferInput = NULL; void* pBufferOutput = NULL; KDBG(DPFLTR_INFO_LEVEL, "[DeviceIoControlParallel] CtlCode:0x%0.8X", IoControlCode); // 取得输入缓冲区,判断其有效性 if(InputBufferLength){ status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &pBufferInput, &size); if(status != STATUS_SUCCESS || pBufferInput == NULL || size < InputBufferLength){ WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } } // 取得输出缓冲区,判断其有效性 if(OutputBufferLength){ status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &pBufferOutput, &size); if(status != STATUS_SUCCESS || pBufferOutput == NULL || size < OutputBufferLength){ WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } } // // 下面是主处理过程。 // switch(IoControlCode) { // 取得驱动的版本信息 case IOCTL_GET_DRIVER_VERSION: { PDRIVER_VERSION pVersion = (PDRIVER_VERSION)pBufferOutput; ULONG length; char tcsBuffer[120]; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_GET_DRIVER_VERSION"); if(OutputBufferLength < sizeof(DRIVER_VERSION)){ status = STATUS_BUFFER_TOO_SMALL; break; } pVersion->DriverType = DR_WDF; pVersion->FirmwareType = FW_NOT_CY001; ulRetLen = sizeof(DRIVER_VERSION);// 告示返回长度 // 根据String描述符,判断Firmware代码是否已经被加载。 GetStringDes(2, 0, tcsBuffer, 120, &length); if(length){ WCHAR* pCyName = L"CY001 V"; size_t len; int nIndex; if(length < 8) break; RtlStringCchLengthW(pCyName, 7, &len); for(nIndex = 0; nIndex < len; nIndex++){ if(pCyName[nIndex] != ((WCHAR*)tcsBuffer)[nIndex]) break; } if(nIndex == len) pVersion->FirmwareType = FW_CY001; // 完全相符,说明新版Firmware已经加载到开发板。 } break; } // 收到App发送过来的一个同步Request,我们应该把它保存到同步Queue中,等到有同步事件发生的时候再从Queue中取出并完成。 case IOCTL_USB_SYNC: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC"); status = WdfRequestForwardToIoQueue(Request, m_hAppSyncManualQueue); // 直接返回,不调用WdfRequestComplete函数。 // 请求者将不会为此而等待;请求的完成在将来的某个时刻。 // 这就是所谓的异步处理之要义了。 if(NT_SUCCESS(status)) return; break; // 清空同步队列中的所有请求 case IOCTL_USB_SYNC_RELEASE: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC"); ClearSyncQueue(); break; // 应用程序退出,取消所有被阻塞的请求。 case IOCTL_APP_EXIT_CANCEL: // 取消USB设备的所有IO操作。它将连带取消所有Pipe的IO操作。 //WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(m_hUsbDevice), WdfIoTargetCancelSentIo); break; // 取得当前的配置号.总是设置为0,因为在WDF框架中,0以外的配置是不被支持的。 case IOCTL_USB_GET_CURRENT_CONFIG: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CURRENT_CONFIG"); if(InputBufferLength < 4){ status = STATUS_INVALID_PARAMETER; break; } *(PULONG)pBufferInput = 0;// 直接赋值0,即总是选择0号配置。也可以发送URB到总线获取当前配置选项。 ulRetLen = sizeof(ULONG); break; } case IOCTL_USB_ABORTPIPE: { ULONG pipenum = *((PULONG) pBufferOutput); KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_ABORTPIPE"); status = AbortPipe(pipenum); } break; // 获取Pipe信息 case IOCTL_USB_GET_PIPE_INFO: { // 遍历获取Pipe信息,复制到输出缓冲中。 BYTE byCurSettingIndex = 0; BYTE byPipeNum = 0; BYTE index; USB_INTERFACE_DESCRIPTOR interfaceDescriptor; WDF_USB_PIPE_INFORMATION pipeInfor; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_PIPE_INFO"); // 取得Pipe数。根据Pipe数计算缓冲区长度 byCurSettingIndex = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); WdfUsbInterfaceGetDescriptor(m_hUsbInterface, byCurSettingIndex, &interfaceDescriptor); byPipeNum = WdfUsbInterfaceGetNumConfiguredPipes(m_hUsbInterface); if(OutputBufferLength < byPipeNum * sizeof(pipeInfor)){ status = STATUS_BUFFER_TOO_SMALL; // 缓冲区不足 }else{ ulRetLen = byPipeNum*sizeof(pipeInfor); // 遍历获取全部管道信息,拷贝到输出缓冲中。 // 应用程序得到输出缓冲的时候,也应该使用WDF_USB_PIPE_INFORMATION结构体解析缓冲区。 for(index = 0; index < byPipeNum; index++) { WDF_USB_PIPE_INFORMATION_INIT(&pipeInfor); WdfUsbInterfaceGetEndpointInformation(m_hUsbInterface, byCurSettingIndex, index, &pipeInfor); RtlCopyMemory((PUCHAR)pBufferOutput + index*pipeInfor.Size, &pipeInfor, sizeof(pipeInfor)); } } } break; // 获取设备描述符 case IOCTL_USB_GET_DEVICE_DESCRIPTOR: { USB_DEVICE_DESCRIPTOR UsbDeviceDescriptor; WdfUsbTargetDeviceGetDeviceDescriptor(m_hUsbDevice, &UsbDeviceDescriptor); KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_DEVICE_DESCRIPTOR"); // 判断输入缓冲区的长度是否足够长 if(OutputBufferLength < UsbDeviceDescriptor.bLength) status = STATUS_BUFFER_TOO_SMALL; else{ RtlCopyMemory(pBufferOutput, &UsbDeviceDescriptor, UsbDeviceDescriptor.bLength); ulRetLen = UsbDeviceDescriptor.bLength; } break; } // 获取字符串描述符 case IOCTL_USB_GET_STRING_DESCRIPTOR: { PGET_STRING_DESCRIPTOR Input = (PGET_STRING_DESCRIPTOR)pBufferInput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_STRING_DESCRIPTOR"); status = GetStringDes(Input->Index, Input->LanguageId, pBufferOutput, OutputBufferLength, &ulRetLen); // 由字符长度调整为字节长度 if(NT_SUCCESS(status) && ulRetLen > 0) ulRetLen *= (sizeof(WCHAR)/sizeof(char)); break; } // 获取配置描述信息。 case IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR"); // 首先获得配置描述符的长度。 status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, NULL, (USHORT*)&size); if(!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) break; // 输出缓冲区不够长 if(OutputBufferLength < size) break; // 正式取得配置描述符。 status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, pBufferOutput, (USHORT*)&size); if(!NT_SUCCESS(status)) break; ulRetLen = size; break; } // 根据可选值配置接口 case IOCTL_USB_SET_INTERFACE: { BYTE byAlterSetting = *(BYTE*)pBufferInput; BYTE byCurSetting = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); // 当前Alternate值 KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SETINTERFACE"); if(InputBufferLength < 1 || OutputBufferLength < 1) { status = STATUS_BUFFER_TOO_SMALL; break; } // 如果传入的可选值与当前的不同,则重新配置接口; // 否则直接返回。 if(byCurSetting != byAlterSetting) { WDF_USB_INTERFACE_SELECT_SETTING_PARAMS par; WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&par, byAlterSetting); status = WdfUsbInterfaceSelectSetting(m_hUsbInterface, NULL, &par); } *(BYTE*)pBufferOutput = byCurSetting; break; } // 固件Rest。自定义命令,与Port Rest是两码事。 case IOCTL_USB_FIRMWRAE_RESET: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_FIRMWRAE_RESET"); if(InputBufferLength < 1 || pBufferInput == NULL) status = STATUS_INVALID_PARAMETER; else status = FirmwareReset(*(char*)pBufferInput); break; } // 重置USB总线端口 case IOCTL_USB_PORT_RESET: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PORT_RESET"); WdfUsbTargetDeviceResetPortSynchronously(m_hUsbDevice); break; } // 管道重置 case IOCTL_USB_PIPE_RESET: { UCHAR uchPipe; WDFUSBPIPE pipe = NULL; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_RESET"); if(InputBufferLength < 1){ status = STATUS_INVALID_PARAMETER; break; } // 根据ID找到对应的Pipe uchPipe = *(UCHAR*)pBufferInput; pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL); if(pipe == NULL){ status = STATUS_INVALID_PARAMETER; break; } status = WdfUsbTargetPipeResetSynchronously(pipe, NULL, NULL); break; } // 中断管道,放弃管道当前正在进行的操作 case IOCTL_USB_PIPE_ABORT: { UCHAR uchPipe; WDFUSBPIPE pipe = NULL; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_ABORT"); if(InputBufferLength < 1){ status = STATUS_INVALID_PARAMETER; break; } // 根据ID找到对应的Pipe uchPipe = *(UCHAR*)pBufferInput; pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL); if(pipe == NULL){ status = STATUS_INVALID_PARAMETER; break; } status = WdfUsbTargetPipeAbortSynchronously(pipe, NULL, NULL); break; } // 取得驱动错误信息,驱动总是把最后一次发现的错误保存在设备对象的环境块中。 // 这个逻辑虽然实现了,但目前的版本中,应用程序并没有利用这个接口。 case IOCTL_USB_GET_LAST_ERROR: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_LAST_ERROR"); if (OutputBufferLength >= sizeof(ULONG)) *((PULONG)pBufferOutput) = m_ulLastUSBErrorStatusValue; else status = STATUS_BUFFER_TOO_SMALL; ulRetLen = sizeof(ULONG); break; } // Clear feature命令 case IOCTL_USB_SET_CLEAR_FEATURE: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_CLEAR_FEATURE"); status = UsbSetOrClearFeature(Request); break; } // 为USB设备加载固件程序。带有偏移量参数,用这个分支;不带偏移量,可用下一个分支。 // 带偏移量的情况下,固件代码是一段一段地加载; // 不带偏移量的情况,固件代码作为一整块一次性被加载。 case IOCTL_FIRMWARE_UPLOAD_OFFSET: { void* pData = pBufferOutput; WORD offset = 0; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD_OFFSET"); if(InputBufferLength < sizeof(WORD)){ status = STATUS_INVALID_PARAMETER; break; } offset = *(WORD*)pBufferInput; status = FirmwareUpload((PUCHAR)pData, OutputBufferLength, offset); break; } // 为USB设备加载固件程序。 case IOCTL_FIRMWARE_UPLOAD: { void* pData = pBufferOutput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD"); status = FirmwareUpload((PUCHAR)pData, InputBufferLength, 0); break; } // 读取开发板设备的RAM内容。RAM也就是内存。 // 每次从同一地址读取的内容可能不尽相同,开发板中固件程序在不断运行,RAM被用来储数据(包括临时数据)。 case IOCTL_FIRMWARE_READ_RAM: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_READ_RAM"); status = ReadRAM(Request, &ulRetLen);// inforVal中保存读取的长度 break; } // 其他的请求 default: { // 一律转发到SerialQueue中去。 WdfRequestForwardToIoQueue(Request, m_hIoCtlSerialQueue); // 命令转发之后,这里必须直接返回,千万不可调用WdfRequestComplete函数。 // 否则会导致一个Request被完成两次的错误。 return; } } // 完成请求 WdfRequestCompleteWithInformation(Request, status, ulRetLen); }
NTSTATUS SelectInterfaces( _In_ WDFDEVICE Device ) /*++ Routine Description: This helper routine selects the configuration, interface and creates a context for every pipe (end point) in that interface. Arguments: Device - Handle to a framework device Return Value: NT status value --*/ { WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; NTSTATUS status = STATUS_SUCCESS; PDEVICE_CONTEXT pDeviceContext; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; UCHAR index; UCHAR numberConfiguredPipes; WDFUSBINTERFACE usbInterface; PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); usbInterface = WdfUsbTargetDeviceGetInterface(pDeviceContext->UsbDevice, 0); if (NULL == usbInterface) { status = STATUS_UNSUCCESSFUL; TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceGetInterface 0 failed %!STATUS! \n", status); return status; } configParams.Types.SingleInterface.ConfiguredUsbInterface = usbInterface; configParams.Types.SingleInterface.NumberConfiguredPipes = WdfUsbInterfaceGetNumConfiguredPipes(usbInterface); pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; numberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; // // Get pipe handles // for(index=0; index < numberConfiguredPipes; index++) { WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); pipe = WdfUsbInterfaceGetConfiguredPipe( pDeviceContext->UsbInterface, index, //PipeIndex, &pipeInfo ); // // Tell the framework that it's okay to read less than // MaximumPacketSize // WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "Interrupt Pipe is 0x%p\n", pipe); pDeviceContext->InterruptPipe = pipe; } if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && WdfUsbTargetPipeIsInEndpoint(pipe)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "BulkInput Pipe is 0x%p\n", pipe); pDeviceContext->BulkReadPipe = pipe; } if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && WdfUsbTargetPipeIsOutEndpoint(pipe)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "BulkOutput Pipe is 0x%p\n", pipe); pDeviceContext->BulkWritePipe = pipe; } } // // If we didn't find all the 3 pipes, fail the start. // if(!(pDeviceContext->BulkWritePipe && pDeviceContext->BulkReadPipe && pDeviceContext->InterruptPipe)) { status = STATUS_INVALID_DEVICE_STATE; TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Device is not configured properly %!STATUS!\n", status); return status; } return status; }
VOID CyGetActiveAltInterfaceConfig(__in PDEVICE_CONTEXT pDevContext) { WDFUSBPIPE UsbPipe; WDF_USB_PIPE_INFORMATION UsbPipeInfo; UCHAR ucIndex; UCHAR ucNumberConfiguredPipes; ucNumberConfiguredPipes = WdfUsbInterfaceGetNumConfiguredPipes(pDevContext->UsbInterfaceConfig.Types.SingleInterface.ConfiguredUsbInterface); pDevContext->ucActiveNumOfPipe = ucNumberConfiguredPipes; /* Update the number of cofigured pipe */ CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"Number of configured pipe 0x%x\n", pDevContext->ucActiveNumOfPipe); pDevContext->ucActiveInterruptInPipe = 0; // Initialize for(ucIndex=0; ucIndex < ucNumberConfiguredPipes; ucIndex++) { WDF_USB_PIPE_INFORMATION_INIT(&UsbPipeInfo); UsbPipe = WdfUsbInterfaceGetConfiguredPipe( pDevContext->UsbInterfaceConfig.Types.SingleInterface.ConfiguredUsbInterface, ucIndex, &UsbPipeInfo ); WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(UsbPipe); /* disable check for the multiple of maximum packet size for read/write buffer */ pDevContext->WdfUsbPipeArray[ucIndex] = UsbPipe; /* Store pipe handle */ /* display information */ if(WdfUsbPipeTypeInterrupt == UsbPipeInfo.PipeType && (WdfUsbTargetPipeIsInEndpoint(UsbPipe))) { //Update the interrupt IN endpoint information pDevContext->WdfUsbInterruptInPipeArray[pDevContext->ucActiveInterruptInPipe]=UsbPipe; pDevContext->ucActiveInterruptInPipe++; CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Interrupt Pipe is 0x%p\n", UsbPipe); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Interrupt Pipe\n"); } if(WdfUsbPipeTypeBulk == UsbPipeInfo.PipeType) { CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Bulk Pipe is 0x%p\n", UsbPipe); // && WdfUsbTargetPipeIsInEndpoint(pipe CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Bulk Pipe\n"); } if(WdfUsbPipeTypeIsochronous == UsbPipeInfo.PipeType && WdfUsbTargetPipeIsOutEndpoint(UsbPipe)) { CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Isochronous Pipe is 0x%p\n", UsbPipe); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Isochronous Pipe\n"); } CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, " MaximumPacketSize :%x\n", UsbPipeInfo.MaximumPacketSize); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, " EndpointAddress :%x\n", UsbPipeInfo.EndpointAddress); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, " Interval :%x\n", UsbPipeInfo.Interval); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, " SettingIndex :%x\n", UsbPipeInfo.SettingIndex); } }