NTSTATUS BthEchoRepeatReaderInitialize( __in PBTHECHO_CONNECTION Connection, __in PBTHECHO_REPEAT_READER RepeatReader, __in size_t BufferSize ) /*++ Description: This routine initializes repeat reader. Arguments: Connection - Connection with which this repeat reader is associated RepeatReader - Repeat reader BufferSize - Buffer size for read Return Value: NTSTATUS Status code. --*/ { NTSTATUS status; WDF_OBJECT_ATTRIBUTES attributes; // // Create request object for pending read // Set connection object as the parent for the request // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = WdfObjectContextGetObject(Connection); status = WdfRequestCreate( &attributes, Connection->DevCtxHdr->IoTarget, &RepeatReader->RequestPendingRead ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, "Creating request for pending read failed, " "Status code %!STATUS!\n", status ); goto exit; } // // Create memory object for the pending read // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = RepeatReader->RequestPendingRead; status = WdfMemoryCreate( &attributes, NonPagedPool, POOLTAG_BTHECHOSAMPLE, BufferSize, &RepeatReader->MemoryPendingRead, NULL //buffer ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_CONT_READER, "Creating memory for pending read failed, " "Status code %!STATUS!\n", status ); goto exit; } // // Initialize Dpc that we will use for resubmitting pending read // KeInitializeDpc( &RepeatReader->ResubmitDpc, BthEchoRepeatReaderResubmitReadDpc, Connection->DevCtxHdr ); // // Initialize event used to wait for stop. // This even is created as signalled. It gets cleared when // request is submitted. // KeInitializeEvent(&RepeatReader->StopEvent, NotificationEvent, TRUE); RepeatReader->Connection = Connection; exit: if (!NT_SUCCESS(status)) { BthEchoRepeatReaderUninitialize(RepeatReader); } return status; }
NTSTATUS FormatRequestWithBrb( __in WDFIOTARGET IoTarget, __in WDFREQUEST Request, __in PBRB Brb, __in size_t BrbSize ) /*++ Description: This routine formats are WDFREQUEST with the passed in BRB Arguments: IoTarget - Target to which request will be sent Request - Request to be formattted Brb - BRB to format the request with BrbSize - size of the BRB --*/ { NTSTATUS status; WDF_OBJECT_ATTRIBUTES attributes; WDFMEMORY memoryArg1; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = Request; status = WdfMemoryCreatePreallocated( &attributes, Brb, BrbSize, &memoryArg1 ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, "Creating preallocted memory for Brb 0x%p failed, Request to be formatted 0x%p, " "Status code %!STATUS!\n", Brb, Request, status ); goto exit; } status = WdfIoTargetFormatRequestForInternalIoctlOthers( IoTarget, Request, IOCTL_INTERNAL_BTH_SUBMIT_BRB, memoryArg1, NULL, //OtherArg1Offset NULL, //OtherArg2 NULL, //OtherArg2Offset NULL, //OtherArg4 NULL //OtherArg4Offset ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_UTIL, "Formatting request 0x%p with Brb 0x%p failed, Status code %!STATUS!\n", Request, Brb, status ); goto exit; } exit: return status; }
/* ** Driver TODO: Complete the implementation of EvtDriverDeviceAdd for your specific device. ** ** WDF calls this callback when a device instance is added to the driver. Good drivers will do a lot of ** work here to set up everything necessary, such as adding callbacks for PNP power state changes. ** This function defines an IO queue for handling DeviceIoControl and file read requests, both of which are ** important to the POS barcode scanner model. ** ** Note that this is not a complete device add implementation, as the PNP power callbacks are not handled. ** Additionally, driver writers may wish to set up additional queues to serialize device property requests ** (see Ioctl.cpp for more info). */ NTSTATUS EvtDriverDeviceAdd(_In_ WDFDRIVER /* UnusedDriver */, _Inout_ PWDFDEVICE_INIT DeviceInit) { NTSTATUS status = STATUS_SUCCESS; WDF_FILEOBJECT_CONFIG fileConfig; WDF_OBJECT_ATTRIBUTES deviceAttributes; WDF_OBJECT_ATTRIBUTES fileAttributes; WDFDEVICE device; // Handle file events WDF_FILEOBJECT_CONFIG_INIT( &fileConfig, EvtDeviceFileCreate, EvtFileClose, WDF_NO_EVENT_CALLBACK ); WDF_OBJECT_ATTRIBUTES_INIT(&fileAttributes); WdfDeviceInitSetFileObjectConfig( DeviceInit, &fileConfig, &fileAttributes ); // Create Device WDF_OBJECT_ATTRIBUTES_INIT(&deviceAttributes); status = WdfDeviceCreate( &DeviceInit, &deviceAttributes, &device ); if (!NT_SUCCESS(status)) { return status; } // Create a device interface for POS Barcode Scanner so that the device can be enumerated status = WdfDeviceCreateDeviceInterface( device, &GUID_DEVINTERFACE_POS_SCANNER, NULL ); if (!NT_SUCCESS(status)) { return status; } // Initialize the POS library POS_CX_ATTRIBUTES posCxAttributes; POS_CX_ATTRIBUTES_INIT(&posCxAttributes); posCxAttributes.EvtDeviceOwnershipChange = EvtDeviceOwnershipChange; status = PosCxInit(device, &posCxAttributes); if (!NT_SUCCESS(status)) { return status; } // Set up an IO queue to handle DeviceIoControl and ReadFile WDF_IO_QUEUE_CONFIG queueConfig; WDF_OBJECT_ATTRIBUTES attributes; WDFQUEUE queue; WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchSequential); queueConfig.EvtIoDeviceControl = EvtIoDeviceControl; queueConfig.EvtIoRead = EvtIoRead; // Call us in PASSIVE_LEVEL WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ExecutionLevel = WdfExecutionLevelPassive; status = WdfIoQueueCreate( device, &queueConfig, &attributes, &queue ); return status; }
NTSTATUS AndroidUsbPipeFileObject::CommonBulkReadWrite( WDFREQUEST request, PMDL transfer_mdl, ULONG length, bool is_read, ULONG time_out, bool is_ioctl) { ASSERT_IRQL_LOW_OR_DISPATCH(); ASSERT(IsPipeAttached()); if (!IsPipeAttached()) { WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE); return STATUS_INVALID_DEVICE_STATE; } // Quick access check. Might be redundant though... ASSERT((is_read && is_input_pipe()) || (!is_read && is_output_pipe())); if ((is_read && is_output_pipe()) || (!is_read && is_input_pipe())) { WdfRequestComplete(request, STATUS_ACCESS_DENIED); return STATUS_ACCESS_DENIED; } // Set URB flags ULONG urb_flags = USBD_SHORT_TRANSFER_OK | (is_read ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT); // Calculate transfer length for this stage. ULONG stage_len = (length > GetTransferGranularity()) ? GetTransferGranularity() : length; // Get virtual address that we're gonna use in the transfer. // We rely here on the fact that we're in the context of the calling thread. void* virtual_address = MmGetMdlVirtualAddress(transfer_mdl); // Allocate our private MDL for this address which we will use for the transfer PMDL new_mdl = IoAllocateMdl(virtual_address, length, FALSE, FALSE, NULL); ASSERT(NULL != new_mdl); if (NULL == new_mdl) { WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); return STATUS_INSUFFICIENT_RESOURCES; } // Map the portion of user buffer that we're going to transfer at this stage // to our mdl. IoBuildPartialMdl(transfer_mdl, new_mdl, virtual_address, stage_len); // Allocate memory for URB and associate it with this request WDF_OBJECT_ATTRIBUTES mem_attrib; WDF_OBJECT_ATTRIBUTES_INIT(&mem_attrib); mem_attrib.ParentObject = request; WDFMEMORY urb_mem = NULL; PURB urb = NULL; NTSTATUS status = WdfMemoryCreate(&mem_attrib, NonPagedPool, GANDR_POOL_TAG_BULKRW_URB, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urb_mem, reinterpret_cast<PVOID*>(&urb)); ASSERT(NT_SUCCESS(status) && (NULL != urb)); if (!NT_SUCCESS(status)) { IoFreeMdl(new_mdl); WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); return STATUS_INSUFFICIENT_RESOURCES; } // Get USB pipe handle for our pipe and initialize transfer request for it USBD_PIPE_HANDLE usbd_pipe_hndl = usbd_pipe(); ASSERT(NULL != usbd_pipe_hndl); if (NULL == usbd_pipe_hndl) { IoFreeMdl(new_mdl); WdfRequestComplete(request, STATUS_INTERNAL_ERROR); return STATUS_INTERNAL_ERROR; } // Initialize URB with request information UsbBuildInterruptOrBulkTransferRequest( urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbd_pipe_hndl, NULL, new_mdl, stage_len, urb_flags, NULL); // Build transfer request status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(), request, urb_mem, NULL); ASSERT(NT_SUCCESS(status)); if (!NT_SUCCESS(status)) { IoFreeMdl(new_mdl); WdfRequestComplete(request, status); return status; } // Initialize our request context. AndroidUsbWdfRequestContext* context = GetAndroidUsbWdfRequestContext(request); ASSERT(NULL != context); if (NULL == context) { IoFreeMdl(new_mdl); WdfRequestComplete(request, STATUS_INTERNAL_ERROR); return STATUS_INTERNAL_ERROR; } context->object_type = AndroidUsbWdfObjectTypeRequest; context->urb_mem = urb_mem; context->transfer_mdl = transfer_mdl; context->mdl = new_mdl; context->length = length; context->transfer_size = stage_len; context->num_xfer = 0; context->virtual_address = virtual_address; context->is_read = is_read; context->initial_time_out = time_out; context->is_ioctl = is_ioctl; // Set our completion routine WdfRequestSetCompletionRoutine(request, CommonReadWriteCompletionEntry, this); // Init send options (our timeout goes here) WDF_REQUEST_SEND_OPTIONS send_options; if (0 != time_out) { WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&send_options, WDF_REL_TIMEOUT_IN_MS(time_out)); } // Timestamp first WdfRequestSend KeQuerySystemTime(&context->sent_at); // Send request asynchronously. if (WdfRequestSend(request, wdf_pipe_io_target(), (0 == time_out) ? WDF_NO_SEND_OPTIONS : &send_options)) { return STATUS_SUCCESS; } // Something went wrong here status = WdfRequestGetStatus(request); ASSERT(!NT_SUCCESS(status)); GoogleDbgPrint("\n!!!!! CommonBulkReadWrite: WdfRequestGetStatus (is_read = %u) failed: %08X", is_read, status); WdfRequestCompleteWithInformation(request, status, 0); return status; }
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 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 --*/ { size_t totalLength = Length; size_t stageLength = 0; NTSTATUS status; PVOID virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDFMEMORY reqMemory; WDFMEMORY_OFFSET offset; WDF_OBJECT_ATTRIBUTES objectAttribs; PDEVICE_CONTEXT deviceContext; 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; 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; } // // If the totalLength exceeds MAX_TRANSFER_SIZE, we will break // that into multiple transfer of size no more than MAX_TRANSFER_SIZE // in each stage. // if (totalLength > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } 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; } WdfRequestSetCompletionRoutine( Request, ReadWriteCompletion, NULL); // // set REQUEST_CONTEXT parameters. // rwContext->Length = totalLength - 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 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 --*/ { 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; 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; 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 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) { 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 = WdfMemoryCreate(&objectAttribs, NonPagedPool, POOL_TAG, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urbMemory, (PVOID*) &urb); if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("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, 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, ReadWriteCompletion, NULL); // // 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); 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; }