/*++ 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; }
// Exstact the device id of the current device from the request // Return id // Returns 0xFFFF if error or id out of range USHORT GetIdFromRawPdoRequest( WDFREQUEST Request, PVOID pExt ) { WDFFILEOBJECT FileObj = NULL; PFILEOBJECT_EXTENSION pExtension = (PFILEOBJECT_EXTENSION)pExt; USHORT id = 0xFFFF; // Get the context, id and the status FileObj = WdfRequestGetFileObject(Request); if (FileObj) { pExtension = GetFileObjectContext(FileObj); if (pExtension) id = (UCHAR)pExtension->id; //else // id = 0; } //else // id = 0; //if (id > MAX_N_DEVICES) // id = 0; return id; }
VOID NfcCxSCPresentAbsentDispatcherRequestCanceled( _In_ WDFREQUEST Request ) /*++ Routine Description: Called when a pending request has been canceled. Arguments: Request - The request Return Value: NTSTATUS --*/ { TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE); WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); WDFDEVICE device = WdfFileObjectGetDevice(fileObject); PNFCCX_FILE_CONTEXT fileContext = NfcCxFileGetContext(fileObject); PNFCCX_FDO_CONTEXT fdoContext = NfcCxFdoGetContext(device); PNFCCX_SC_REQUEST_CONTEXT requestContext = NfcCxSCGetRequestContext(Request); PNFCCX_SC_PRESENT_ABSENT_DISPATCHER dispatcher = requestContext->Dispatcher; // Remove this request from the dispatcher void* previousRequest = InterlockedCompareExchangePointer((void**)&dispatcher->CurrentRequest, /*exchange*/ nullptr, /*compare*/ Request); // Check if another thread has already completed the request. if (previousRequest != Request) { // Request already completed by a different thread. // Nothing to do. goto Done; } // Release power reference (if required). if (dispatcher->PowerManaged) { NfcCxPowerFileRemoveReference(fdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity); } // Complete the request. TRACE_LINE(LEVEL_ERROR, "Smartcard Present/Absent request canceled. %!STATUS!", STATUS_CANCELLED); WdfRequestComplete(Request, STATUS_CANCELLED); Done: // Release the cancel callback's extra ref-count WdfObjectDereference(Request); TRACE_FUNCTION_EXIT(LEVEL_VERBOSE); }
void AndroidUsbFileObject::OnEvtIoDeviceControl(WDFREQUEST request, size_t output_buf_len, size_t input_buf_len, ULONG ioctl_code) { ASSERT_IRQL_LOW_OR_DISPATCH(); ASSERT(WdfRequestGetFileObject(request) == wdf_file()); WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); }
void AndroidUsbFileObject::OnEvtIoWrite(WDFREQUEST request, size_t length) { ASSERT_IRQL_LOW_OR_DISPATCH(); ASSERT(WdfRequestGetFileObject(request) == wdf_file()); // Complete zero writes with success if (0 == length) { WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0); return; } WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); }
static VOID XenBus_ProcessReadRequest(WDFQUEUE queue, WDFREQUEST request, size_t length) { NTSTATUS status; WDFFILEOBJECT file_object = WdfRequestGetFileObject(request); PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object); ULONG dst_length = (ULONG)length; ULONG dst_offset = 0; ULONG copy_length; xenbus_read_queue_item_t *list_entry; PVOID buffer; UNREFERENCED_PARAMETER(queue); status = WdfRequestRetrieveOutputBuffer(request, length, &buffer, NULL); if (!NT_SUCCESS(status)) { KdPrint((__DRIVER_NAME, " WdfRequestRetrieveOutputBuffer failed status = %08x\n", status)); WdfRequestSetInformation(request, 0); return; } ASSERT(NT_SUCCESS(status)); // lazy? while(dst_offset < dst_length && (list_entry = (xenbus_read_queue_item_t *)RemoveHeadList(&xpdid->xenbus.read_list_head)) != (xenbus_read_queue_item_t *)&xpdid->xenbus.read_list_head) { copy_length = min(list_entry->length - list_entry->offset, dst_length - dst_offset); memcpy((PUCHAR)buffer + dst_offset, (PUCHAR)list_entry->data + list_entry->offset, copy_length); list_entry->offset += copy_length; dst_offset += copy_length; if (list_entry->offset == list_entry->length) { ExFreePoolWithTag(list_entry->data, XENPCI_POOL_TAG); ExFreePoolWithTag(list_entry, XENPCI_POOL_TAG); } else { InsertHeadList(&xpdid->xenbus.read_list_head, (PLIST_ENTRY)list_entry); } } WdfRequestSetInformation(request, dst_offset); FUNCTION_EXIT(); }
static VOID XenBus_EvtIoRead(WDFQUEUE queue, WDFREQUEST request, size_t length) { NTSTATUS status; WDFFILEOBJECT file_object = WdfRequestGetFileObject(request); PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object); KIRQL old_irql; UNREFERENCED_PARAMETER(queue); FUNCTION_ENTER(); status = WdfRequestForwardToIoQueue(request, xpdid->xenbus.io_queue); if (!NT_SUCCESS(status)) { KdPrint((__DRIVER_NAME " could not forward request (%08x)\n", status)); } KeAcquireSpinLock(&xpdid->lock, &old_irql); if (!IsListEmpty(&xpdid->xenbus.read_list_head)) { status = WdfIoQueueRetrieveNextRequest(xpdid->xenbus.io_queue, &request); if (NT_SUCCESS(status)) { KdPrint((__DRIVER_NAME " found pending read\n")); XenBus_ProcessReadRequest(xpdid->xenbus.io_queue, request, length); KeReleaseSpinLock(&xpdid->lock, old_irql); WdfRequestComplete(request, STATUS_SUCCESS); } else { KdPrint((__DRIVER_NAME " no pending read (%08x)\n", status)); KeReleaseSpinLock(&xpdid->lock, old_irql); } } else { KdPrint((__DRIVER_NAME " no data to read\n")); KeReleaseSpinLock(&xpdid->lock, old_irql); } FUNCTION_EXIT(); return; }
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); }
/*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ VOID PSDrv_EvtIoDeviceControl(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode) { WDFDEVICE device; PVOID ioBuffer; size_t bufLength; NTSTATUS status; PDEVICE_CONTEXT pDevContext; PFILE_CONTEXT pFileContext; ULONG length = 0; PSUSBDRV_PIPE_PROPERTY* pPipeProp; PSUSBDRV_CONTROL_TRANSFER* pControlTransfer; PSUSBDRV_DRIVER_VERSION* pDriverVersion; PSUSBDRV_INTERFACE_PROPERTY* pInterfaceProperty; unsigned int* pnDeviceSpeed; WDFMEMORY WdfMem = NULL; PUCHAR pControlBuffer; WDFMEMORY WdfMemOut = NULL; WDF_USB_INTERFACE_SELECT_SETTING_PARAMS selectSettingParams; UNREFERENCED_PARAMETER(InputBufferLength); PSDrv_DbgPrint(3, ("PSDrv_EvtIoDeviceControl - begins\n")); PAGED_CODE(); // initialize variables device = WdfIoQueueGetDevice(Queue); pDevContext = GetDeviceContext(device); switch(IoControlCode) { case IOCTL_PSDRV_RESET_PIPE: PSDrv_DbgPrint(3, ("IOControl: ResetPipe\n")); pFileContext = GetFileContext(WdfRequestGetFileObject(Request)); if (pFileContext->Pipe == NULL) { PSDrv_DbgPrint(3, ("Invalid pipe!\n")); status = STATUS_INVALID_PARAMETER; } else { status = ResetPipe(pFileContext->Pipe); } break; case IOCTL_PSDRV_ABORT_PIPE: PSDrv_DbgPrint(3, ("IOControl: AbortPipe\n")); pFileContext = GetFileContext(WdfRequestGetFileObject(Request)); if (pFileContext->Pipe == NULL) { PSDrv_DbgPrint(3, ("Invalid pipe!\n")); status = STATUS_INVALID_PARAMETER; } else { status = AbortPipe(pFileContext->Pipe); } break; case IOCTL_PSDRV_GET_CONFIG_DESCRIPTOR: PSDrv_DbgPrint(3, ("IOControl: GetConfigDescriptor\n")); if (pDevContext->UsbConfigurationDescriptor) { length = pDevContext->UsbConfigurationDescriptor->wTotalLength; status = WdfRequestRetrieveOutputBuffer(Request, length, &ioBuffer, &bufLength); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } RtlCopyMemory(ioBuffer, pDevContext->UsbConfigurationDescriptor, length); status = STATUS_SUCCESS; } else { PSDrv_DbgPrint(3, ("UsbConfigurationDescriptor is NULL!\n")); status = STATUS_INVALID_DEVICE_STATE; } break; case IOCTL_PSDRV_RESET_DEVICE: PSDrv_DbgPrint(3, ("IOControl: ResetDevice\n")); status = ResetDevice(device); break; case IOCTL_PSDRV_CONTROL_TRANSFER: PSDrv_DbgPrint(3, ("IOControl: ControlTransfer\n")); //Get a pointer to the input buffer status = WdfRequestRetrieveInputMemory(Request, &WdfMem); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputMemory failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (WdfMem == NULL) { PSDrv_DbgPrint(1, ("WdfMem is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pControlTransfer = WdfMemoryGetBuffer(WdfMem, NULL); if (pControlTransfer == NULL) { PSDrv_DbgPrint(1, ("pControlTransfer is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } //Get a pointer to the output buffer if (OutputBufferLength != 0) { status = WdfRequestRetrieveOutputMemory(Request, &WdfMemOut); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputMemory failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (WdfMemOut == NULL) { PSDrv_DbgPrint(1, ("WdfMemOut is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pControlBuffer = WdfMemoryGetBuffer(WdfMemOut, NULL); if (pControlBuffer == NULL) { PSDrv_DbgPrint(1, ("pControlBuffer is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } } else { PSDrv_DbgPrint(1, ("This control request has no buffer...\n")); pControlBuffer = NULL; } // Call the control transfer function status = ControlTransfer(pDevContext, pControlTransfer, pControlBuffer, OutputBufferLength, &length); break; case IOCTL_PSDRV_SET_PIPE_PROPERTY: PSDrv_DbgPrint(3, ("IOControl: SetPipeProperty\n")); status = WdfRequestRetrieveInputMemory(Request, &WdfMem); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputMemory failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (WdfMem == NULL) { PSDrv_DbgPrint(1, ("WdfMem is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pPipeProp = WdfMemoryGetBuffer(WdfMem, NULL); if (pPipeProp == NULL) { PSDrv_DbgPrint(1, ("pPipeProp is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pFileContext = GetFileContext(WdfRequestGetFileObject(Request)); if (pFileContext->Pipe == NULL) { PSDrv_DbgPrint(3, ("Invalid pipe!\n")); status = STATUS_INVALID_PARAMETER; } else { status = SetPipeProperty(pFileContext, pPipeProp); } break; case IOCTL_PSDRV_SET_INTERFACE: PSDrv_DbgPrint(3, ("IOControl: SetInterface\n")); status = WdfRequestRetrieveInputMemory(Request, &WdfMem); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputMemory failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (WdfMem == NULL) { PSDrv_DbgPrint(1, ("WdfMem is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pInterfaceProperty = WdfMemoryGetBuffer(WdfMem, NULL); if (pInterfaceProperty == NULL) { PSDrv_DbgPrint(1, ("pInterfaceProperty is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } PSDrv_DbgPrint(3, ("SetInterface: Going to change AltIF to %d...\n", pInterfaceProperty->nAltIF)); WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&selectSettingParams, pInterfaceProperty->nAltIF); status = WdfUsbInterfaceSelectSetting(pDevContext->UsbInterface, WDF_NO_OBJECT_ATTRIBUTES, &selectSettingParams); if (status == STATUS_SUCCESS) { pDevContext->nCurrIf = 0; pDevContext->nCurrAltIf = pInterfaceProperty->nAltIF; PSDrv_DbgPrint(3, ("SetInterface: AltIF is now %d...\n", pInterfaceProperty->nAltIF)); } break; case IOCTL_PSDRV_GET_INTERFACE: PSDrv_DbgPrint(3, ("IOControl: GetInterface\n")); length = sizeof(PSUSBDRV_INTERFACE_PROPERTY); status = WdfRequestRetrieveOutputBuffer(Request, length, &pInterfaceProperty, &bufLength); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } pInterfaceProperty->nIF = pDevContext->nCurrIf; pInterfaceProperty->nAltIF = pDevContext->nCurrAltIf; status = STATUS_SUCCESS; break; case IOCTL_PSDRV_GET_DRIVER_VERSION: PSDrv_DbgPrint(3, ("IOControl: GetDriverVersion\n")); length = sizeof(PSUSBDRV_DRIVER_VERSION); status = WdfRequestRetrieveOutputBuffer(Request, length, &pDriverVersion, &bufLength); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } pDriverVersion->nMajor = PSUSBDRV_MAJOR_VERSION; pDriverVersion->nMinor = PSUSBDRV_MINOR_VERSION; pDriverVersion->nMaintenance = PSUSBDRV_MAINTENANCE_VERSION; pDriverVersion->nBuild = PSUSBDRV_BUILD_VERSION; status = STATUS_SUCCESS; break; case IOCTL_PSDRV_GET_DEVICE_SPEED: PSDrv_DbgPrint(3, ("IOControl: GetDeviceSpeed\n")); length = sizeof(unsigned int); status = WdfRequestRetrieveOutputBuffer(Request, length, &pnDeviceSpeed, &bufLength); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (pDevContext->IsDeviceHighSpeed == TRUE) { *pnDeviceSpeed = PSUSBDRV_DEVICE_HIGH_SPEED; } else { *pnDeviceSpeed = PSUSBDRV_DEVICE_FULL_SPEED; } break; default: PSDrv_DbgPrint(3, ("Unknown IOControl! (ControlCode = %x)\n", IoControlCode)); status = STATUS_INVALID_DEVICE_REQUEST; break; } WdfRequestCompleteWithInformation(Request, status, length); PSDrv_DbgPrint(3, ("PSDrv_EvtIoDeviceControl - ends\n")); return; }
/*++ 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; }
VOID VIOSerialPortRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue)); size_t length; NTSTATUS status; PVOID systemBuffer; BOOLEAN nonBlock; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "-->%s\n", __FUNCTION__); nonBlock = ((WdfFileObjectGetFlags(WdfRequestGetFileObject(Request)) & FO_SYNCHRONOUS_IO) != FO_SYNCHRONOUS_IO); status = WdfRequestRetrieveOutputBuffer(Request, Length, &systemBuffer, &length); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } WdfSpinLockAcquire(pdoData->port->InBufLock); if (!VIOSerialPortHasDataLocked(pdoData->port)) { if (!pdoData->port->HostConnected) { WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); } else { ASSERT (pdoData->port->PendingReadRequest == NULL); status = WdfRequestMarkCancelableEx(Request, VIOSerialPortReadRequestCancel); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); } else { pdoData->port->PendingReadRequest = Request; } } } else { length = (ULONG)VIOSerialFillReadBufLocked(pdoData->port, systemBuffer, length); if (length) { WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR)length); } else { WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); } } WdfSpinLockRelease(pdoData->port->InBufLock); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ,"<-- %s\n", __FUNCTION__); return; }
void DeviceContext::DeviceIo( _In_ WDFREQUEST Request, _In_ size_t /*OutputBufferLength*/, _In_ size_t /*InputBufferLength*/, _In_ ULONG IoControlCode ) { TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE); WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); FileObjectContext* fileContext = FileObjectGetContext(fileObject); using CommandFunctionType = NTSTATUS (DeviceContext::*)(_In_ WDFREQUEST Request); CommandFunctionType commandFunction = nullptr; switch (fileContext->GetType()) { case FileObjectContext::Type::NciSim: switch (IoControlCode) { case IOCTL_NCISIM_GET_NEXT_CALLBACK: commandFunction = &DeviceContext::CommandGetNextCallback; break; case IOCTL_NCISIM_NCI_READ: commandFunction = &DeviceContext::CommandNciRead; break; case IOCTL_NCISIM_HARDWARE_EVENT: commandFunction = &DeviceContext::CommandHardwareEvent; break; case IOCTL_NCISIM_SEQUENCE_HANDLER_COMPLETE: commandFunction = &DeviceContext::CommandSequenceHandlerComplete; break; case IOCTL_NCISIM_NCI_WRITE_COMPLETE: commandFunction = &DeviceContext::CommandNciWriteComplete; break; } break; } NTSTATUS commandStatus = STATUS_SUCCESS; if (commandFunction) { commandStatus = (this->*commandFunction)(Request); } else { commandStatus = STATUS_INVALID_DEVICE_STATE; TRACE_LINE(LEVEL_ERROR, "Unsupported IOCTL (%d): 0x%08X. %!STATUS!", int(fileContext->GetType()), IoControlCode, commandStatus); } if (!NT_SUCCESS(commandStatus)) { TRACE_LINE(LEVEL_ERROR, "Request failed. %!STATUS!", commandStatus); WdfRequestComplete(Request, commandStatus); return; } TRACE_FUNCTION_SUCCESS(LEVEL_VERBOSE); }
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; }
VCHIQ_PAGED_SEGMENT_BEGIN /*++ Routine Description: VchiqIoDeviceControl handles VCHIQ IOCTL. Arguments: DeviceContextPtr - Pointer to device context WdfRequest - A handle to a framework request object. OutputBufferLength - The length, in bytes, of the request's output buffer, if an output buffer is available. InputBufferLength - The length, in bytes, of the request's input buffer, if an input buffer is available. IoControlCode - The driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: None --*/ _Use_decl_annotations_ VOID VchiqIoDeviceControl ( WDFQUEUE Queue, WDFREQUEST WdfRequest, size_t OutputBufferLength, size_t InputBufferLength, ULONG IoControlCode ) { NTSTATUS status; VCHIQ_FILE_CONTEXT* vchiqFileContextPtr; WDFDEVICE device = WdfIoQueueGetDevice(Queue); DEVICE_CONTEXT* deviceContextPtr = VchiqGetDeviceContext(device); PAGED_CODE(); if (deviceContextPtr->VCConnected == FALSE) { VCHIQ_LOG_WARNING("VCHIQ interface not ready"); status = STATUS_DEVICE_NOT_READY; goto CompleteRequest; } // First process IOCTL that does not require a file context switch (IoControlCode) { case IOCTL_VCHIQ_CONNECT: { // Connect is a simple ioctl to ensure that we have establish // connection with VC firmware. Connection is establish by // initiating the slots which if we reach this point has // already been initialize. We just send a message to notify // the firmware too WDFFILEOBJECT wdfFileObject = WdfRequestGetFileObject(WdfRequest); if (wdfFileObject == NULL) { WDF_REQUEST_PARAMETERS wdfRequestParameters; WdfRequestGetParameters(WdfRequest, &wdfRequestParameters); VCHIQ_LOG_ERROR( "Fail to retrieve file object. \ (WdfRequest = 0x%p, Type = 0x%lx)", WdfRequest, (ULONG)wdfRequestParameters.Type); status = STATUS_INTERNAL_ERROR; goto CompleteRequest; } // Create a file context here as vchiq_arm would immediately begin // to send IOCTL to wait for completion message vchiqFileContextPtr = VchiqGetFileContext(wdfFileObject); if (vchiqFileContextPtr != NULL) { VCHIQ_LOG_ERROR( "Caller has already connected to a service"); status = STATUS_UNSUCCESSFUL; goto CompleteRequest; } status = VchiqAllocateFileObjContext( deviceContextPtr, wdfFileObject, &vchiqFileContextPtr); if (!NT_SUCCESS (status)) { VCHIQ_LOG_ERROR( "VchiqAllocateFileObjContext failed (%!STATUS!)", status); goto CompleteRequest; } status = VchiqQueueMessageAsync( deviceContextPtr, vchiqFileContextPtr, VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0); if (!NT_SUCCESS (status)) { VCHIQ_LOG_ERROR( "VchiqQueueMessageAsync failed (%!STATUS!)", status); goto CompleteRequest; } goto CompleteRequest; } case IOCTL_VCHIQ_GET_CONFIG: { VCHIQ_CONFIG vchiqCurrentConfig = { VCHIQ_MAX_MSG_SIZE, VCHIQ_MAX_MSG_SIZE, VCHIQ_NUM_SERVICE_BULKS, VCHIQ_MAX_SERVICES, VCHIQ_VERSION, VCHIQ_VERSION_MIN }; VCHIQ_GET_CONFIG* clientConfigPtr; status = WdfRequestRetrieveInputBuffer( WdfRequest, sizeof(*clientConfigPtr), &clientConfigPtr, NULL); if (!NT_SUCCESS(status)) { VCHIQ_LOG_ERROR( "WdfRequestRetrieveInputBuffer failed (%!STATUS!)", status); goto CompleteRequest; } // Ensure that the buffer provided is not too big. if (clientConfigPtr->ConfigSize > sizeof(VCHIQ_CONFIG)) { VCHIQ_LOG_WARNING("Config buffer too big"); status = STATUS_INVALID_PARAMETER; goto CompleteRequest; } VCHIQ_CONFIG* configurationPtr; size_t bufferSize; configurationPtr = WdfMemoryGetBuffer( clientConfigPtr->WdfMemoryConfiguration, &bufferSize); if ((configurationPtr == NULL) || (bufferSize != sizeof(*configurationPtr))) { VCHIQ_LOG_ERROR( "Caller provided invalid VCHIQ_CONFIG buffer 0x%08x %d", (ULONG)configurationPtr, bufferSize); status = STATUS_INVALID_PARAMETER; goto CompleteRequest; } RtlCopyMemory( configurationPtr, &vchiqCurrentConfig, sizeof(*clientConfigPtr->PConfig)); status = STATUS_SUCCESS; } goto CompleteRequest; case IOCTL_VCHIQ_LIB_VERSION: { ULONG* libVersion; status = WdfRequestRetrieveInputBuffer( WdfRequest, sizeof(*libVersion), &libVersion, NULL); if (!NT_SUCCESS(status)) { VCHIQ_LOG_ERROR( "WdfRequestRetrieveInputBuffer failed (%!STATUS!)", status); goto CompleteRequest; } if (*libVersion < VCHIQ_VERSION_MIN) { VCHIQ_LOG_ERROR( "Library version %d unsupported", *libVersion); status = STATUS_NOT_SUPPORTED; goto CompleteRequest; } status = STATUS_SUCCESS; } goto CompleteRequest; case IOCTL_VCHIQ_CREATE_SERVICE: default: { WDFFILEOBJECT wdfFileObject = WdfRequestGetFileObject(WdfRequest); if (wdfFileObject == NULL) { WDF_REQUEST_PARAMETERS wdfRequestParameters; WdfRequestGetParameters(WdfRequest, &wdfRequestParameters); VCHIQ_LOG_ERROR( "Fail to retrieve file object. \ (WdfRequest = 0x%p, Type = 0x%lx)", WdfRequest, (ULONG)wdfRequestParameters.Type); status = STATUS_INTERNAL_ERROR; goto CompleteRequest; } vchiqFileContextPtr = VchiqGetFileContext(wdfFileObject); if ((vchiqFileContextPtr == NULL) && (IoControlCode == IOCTL_VCHIQ_CREATE_SERVICE)) { // Functional test does not call connect prior to a create // service call, so we allocate a file context here instead status = VchiqAllocateFileObjContext( deviceContextPtr, wdfFileObject, &vchiqFileContextPtr); if (!NT_SUCCESS (status)) { VCHIQ_LOG_ERROR( "VchiqAllocateFileObjContext failed (%!STATUS!)", status); goto CompleteRequest; } } else if (vchiqFileContextPtr == NULL) { VCHIQ_LOG_ERROR( "Caller has not connected to a service %d", ((IoControlCode >> 2) & 0x0FFF)); status = STATUS_UNSUCCESSFUL; goto CompleteRequest; } } }
static VOID XenBus_EvtIoWrite(WDFQUEUE queue, WDFREQUEST request, size_t length) { NTSTATUS status; PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfIoQueueGetDevice(queue)); WDFFILEOBJECT file_object = WdfRequestGetFileObject(request); PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object); KIRQL old_irql; WDFREQUEST read_request; PUCHAR buffer; PUCHAR src_ptr; ULONG src_len; PUCHAR dst_ptr; ULONG copy_len; struct xsd_sockmsg *rep; xenbus_read_queue_item_t *list_entry; watch_context_t *watch_context; PCHAR watch_path; PCHAR watch_token; PCHAR msg; FUNCTION_ENTER(); status = WdfRequestRetrieveInputBuffer(request, length, &buffer, NULL); ASSERT(NT_SUCCESS(status)); src_ptr = (PUCHAR)buffer; src_len = (ULONG)length; dst_ptr = xpdid->xenbus.u.buffer + xpdid->xenbus.len; while (src_len != 0) { KdPrint((__DRIVER_NAME " %d bytes of write buffer remaining\n", src_len)); /* get a complete msg header */ if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg)) { copy_len = min(sizeof(xpdid->xenbus.u.msg) - xpdid->xenbus.len, src_len); if (!copy_len) continue; memcpy(dst_ptr, src_ptr, copy_len); dst_ptr += copy_len; src_ptr += copy_len; src_len -= copy_len; xpdid->xenbus.len += copy_len; } /* exit if we can't get that */ if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg)) continue; /* get a complete msg body */ if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg) + xpdid->xenbus.u.msg.len) { copy_len = min(sizeof(xpdid->xenbus.u.msg) + xpdid->xenbus.u.msg.len - xpdid->xenbus.len, src_len); if (!copy_len) continue; memcpy(dst_ptr, src_ptr, copy_len); dst_ptr += copy_len; src_ptr += copy_len; src_len -= copy_len; xpdid->xenbus.len += copy_len; } /* exit if we can't get that */ if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg) + xpdid->xenbus.u.msg.len) { continue; } switch (xpdid->xenbus.u.msg.type) { case XS_WATCH: case XS_UNWATCH: KeAcquireSpinLock(&xpdid->lock, &old_irql); watch_context = (watch_context_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(watch_context_t), XENPCI_POOL_TAG); watch_path = (PCHAR)(xpdid->xenbus.u.buffer + sizeof(struct xsd_sockmsg)); watch_token = (PCHAR)(xpdid->xenbus.u.buffer + sizeof(struct xsd_sockmsg) + strlen(watch_path) + 1); RtlStringCbCopyA(watch_context->path, ARRAY_SIZE(watch_context->path), watch_path); RtlStringCbCopyA(watch_context->token, ARRAY_SIZE(watch_context->path), watch_token); watch_context->file_object = file_object; if (xpdid->xenbus.u.msg.type == XS_WATCH) InsertTailList(&xpdid->xenbus.watch_list_head, &watch_context->entry); KeReleaseSpinLock(&xpdid->lock, old_irql); if (xpdid->xenbus.u.msg.type == XS_WATCH) msg = XenBus_AddWatch(xpdd, XBT_NIL, watch_path, XenPci_IoWatch, watch_context); else msg = XenBus_RemWatch(xpdd, XBT_NIL, watch_path, XenPci_IoWatch, watch_context); KeAcquireSpinLock(&xpdid->lock, &old_irql); if (msg != NULL) { rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg) + strlen(msg) + 1, XENPCI_POOL_TAG); rep->type = XS_ERROR; rep->req_id = xpdid->xenbus.u.msg.req_id; rep->tx_id = xpdid->xenbus.u.msg.tx_id; rep->len = (ULONG)(strlen(msg) + 0); RtlStringCbCopyA((PCHAR)(rep + 1), strlen(msg) + 1, msg); if (xpdid->xenbus.u.msg.type == XS_WATCH) RemoveEntryList(&watch_context->entry); } else { if (xpdid->xenbus.u.msg.type == XS_WATCH) { WdfObjectReference(file_object); } else { RemoveEntryList(&watch_context->entry); WdfObjectDereference(file_object); } rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg), XENPCI_POOL_TAG); rep->type = xpdid->xenbus.u.msg.type; rep->req_id = xpdid->xenbus.u.msg.req_id; rep->tx_id = xpdid->xenbus.u.msg.tx_id; rep->len = 0; } KeReleaseSpinLock(&xpdid->lock, old_irql); break; default: rep = XenBus_Raw(xpdd, &xpdid->xenbus.u.msg); break; } xpdid->xenbus.len = 0; KeAcquireSpinLock(&xpdid->lock, &old_irql); list_entry = (xenbus_read_queue_item_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(xenbus_read_queue_item_t), XENPCI_POOL_TAG); list_entry->data = rep; list_entry->length = sizeof(*rep) + rep->len; list_entry->offset = 0; InsertTailList(&xpdid->xenbus.read_list_head, (PLIST_ENTRY)list_entry); // Check if someone was waiting for the answer already status = WdfIoQueueRetrieveNextRequest(xpdid->xenbus.io_queue, &read_request); if (NT_SUCCESS(status)) { WDF_REQUEST_PARAMETERS parameters; KdPrint((__DRIVER_NAME " post-write: found pending read\n")); WDF_REQUEST_PARAMETERS_INIT(¶meters); WdfRequestGetParameters(read_request, ¶meters); XenBus_ProcessReadRequest(xpdid->xenbus.io_queue, read_request, parameters.Parameters.Read.Length); WdfRequestComplete(read_request, STATUS_SUCCESS); } else { KdPrint((__DRIVER_NAME " post-write: no pending read (%08x)\n", status)); } KeReleaseSpinLock(&xpdid->lock, old_irql); } KdPrint((__DRIVER_NAME " completing request with length %d\n", length)); WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, length); FUNCTION_EXIT(); }
VOID NdisProtEvtIoWrite( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: Dispatch routine to handle Request_MJ_WRITE. 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 --*/ { ULONG DataLength; NTSTATUS NtStatus; PNDISPROT_OPEN_CONTEXT pOpenContext; PNET_BUFFER_LIST pNetBufferList; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; PVOID CancelId; ULONG SendFlags = 0; PMDL pMdl = NULL; WDFFILEOBJECT fileObject; PREQUEST_CONTEXT reqContext; WDF_OBJECT_ATTRIBUTES attributes; UNREFERENCED_PARAMETER(Queue); fileObject = WdfRequestGetFileObject(Request); pOpenContext = GetFileObjectContext(fileObject)->OpenContext; do { // // Create a context to track the length of transfer and NDIS packet // associated with this request. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); NtStatus = WdfObjectAllocateContext(Request, &attributes, &reqContext); if(!NT_SUCCESS(NtStatus)){ DEBUGP(DL_WARN, ("Write: WdfObjectAllocateContext failed: %x\n", NtStatus)); NtStatus = STATUS_INVALID_HANDLE; break; } reqContext->Length = (ULONG) Length; if (pOpenContext == NULL) { DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n", fileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } NPROT_STRUCT_ASSERT(pOpenContext, oc); NtStatus = WdfRequestRetrieveInputWdmMdl(Request, &pMdl); if (!NT_SUCCESS(NtStatus)) { DEBUGP(DL_FATAL, ("Write: WdfRequestRetrieveInputWdmMdl failed %x\n", NtStatus)); break; } // // Try to get a virtual address for the MDL. // pEthHeader = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority | MdlMappingNoExecute); if (pEthHeader == NULL) { DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for" " Request %p, MDL %p\n", Request, pMdl)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Sanity-check the length. // DataLength = MmGetMdlByteCount(pMdl); if (DataLength < sizeof(NDISPROT_ETH_HEADER)) { DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n", DataLength)); NtStatus = STATUS_BUFFER_TOO_SMALL; break; } if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER))) { DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)" " larger than max frame size (%d)\n", pOpenContext, DataLength, pOpenContext->MaxFrameSize)); NtStatus = STATUS_INVALID_BUFFER_SIZE; break; } // // To prevent applications from sending packets with spoofed // mac address, we will do the following check to make sure the source // address in the packet is same as the current MAC address of the NIC. // if ((WdfRequestGetRequestorMode(Request) == UserMode) && !NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN)) { DEBUGP(DL_WARN, ("Write: Failing with invalid Source address")); NtStatus = STATUS_INVALID_PARAMETER; break; } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE); if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_FATAL, ("Write: Open %p is not bound" " or in low power state\n", pOpenContext)); NtStatus = STATUS_INVALID_HANDLE; break; } if ((pOpenContext->State == NdisprotPaused) || (pOpenContext->State == NdisprotPausing)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_INFO, ("Device is paused.\n")); NtStatus = STATUS_UNSUCCESSFUL; break; } NPROT_ASSERT(pOpenContext->SendNetBufferListPool != NULL); pNetBufferList = NdisAllocateNetBufferAndNetBufferList( pOpenContext->SendNetBufferListPool, sizeof(NPROT_SEND_NETBUFLIST_RSVD), //Request control offset delta 0, // back fill size pMdl, 0, // Data offset DataLength); if (pNetBufferList == NULL) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send net buffer list\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } pOpenContext->PendedSendCount++; NPROT_REF_OPEN(pOpenContext); // pended send // // Initialize the NetBufferList ref count. This NetBufferList will be freed // when this count goes to zero. // NPROT_SEND_NBL_RSVD(pNetBufferList)->RefCount = 1; // // We set up a cancel ID on each send NetBufferList (which maps to a Write IRP), // and save the NetBufferList pointer in the IRP. If the IRP gets cancelled, we use // NdisCancelSendNetBufferLists() to cancel the NetBufferList. // // Note that this sample code does not implement the cancellation logic. An actual // driver may find value in implementing this. // CancelId = NPROT_GET_NEXT_CANCEL_ID(); NDIS_SET_NET_BUFFER_LIST_CANCEL_ID(pNetBufferList, CancelId); reqContext->NetBufferList = (PVOID)pNetBufferList; NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); // // Set a back pointer from the packet to the IRP. // NPROT_REQUEST_FROM_SEND_NBL(pNetBufferList) = Request; NtStatus = STATUS_PENDING; pNetBufferList->SourceHandle = pOpenContext->BindingHandle; NPROT_ASSERT (pMdl->Next == NULL); SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK; NdisSendNetBufferLists( pOpenContext->BindingHandle, pNetBufferList, NDIS_DEFAULT_PORT_NUMBER, SendFlags); } while (FALSE); if (NtStatus != STATUS_PENDING) { WdfRequestComplete(Request, NtStatus); } return; }
VOID NdisProtEvtIoDeviceControl( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ { NTSTATUS NtStatus; NDIS_STATUS Status; PNDISPROT_OPEN_CONTEXT pOpenContext; ULONG BytesReturned; PVOID sysBuffer; WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); size_t bufSize; UNREFERENCED_PARAMETER(Queue); UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); DEBUGP(DL_LOUD, ("IoControl: Irp %p\n", Request)); pOpenContext = GetFileObjectContext(fileObject)->OpenContext; BytesReturned = 0; switch (IoControlCode) { case IOCTL_NDISPROT_BIND_WAIT: // // Block until we have seen a NetEventBindsComplete event, // meaning that we have finished binding to all running // adapters that we are supposed to bind to. // // If we don't get this event in 5 seconds, time out. // NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); if (NPROT_WAIT_EVENT(&Globals.BindsComplete, 5000)) { NtStatus = STATUS_SUCCESS; } else { NtStatus = STATUS_TIMEOUT; } DEBUGP(DL_INFO, ("IoControl: BindWait returning %x\n", NtStatus)); break; case IOCTL_NDISPROT_QUERY_BINDING: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); NtStatus = WdfRequestRetrieveOutputBuffer(Request, sizeof(NDISPROT_QUERY_BINDING), &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveOutputBuffer failed %x\n", NtStatus)); break; } Status = ndisprotQueryBinding( sysBuffer, (ULONG) bufSize, (ULONG) bufSize, &BytesReturned ); NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); DEBUGP(DL_LOUD, ("IoControl: QueryBinding returning %x\n", NtStatus)); break; case IOCTL_NDISPROT_OPEN_DEVICE: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); if (pOpenContext != NULL) { NPROT_STRUCT_ASSERT(pOpenContext, oc); DEBUGP(DL_WARN, ("IoControl: OPEN_DEVICE: FileObj %p already" " associated with open %p\n", fileObject, pOpenContext)); NtStatus = STATUS_DEVICE_BUSY; break; } NtStatus = WdfRequestRetrieveInputBuffer(Request, 0, &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveInputBuffer failed %x\n", NtStatus)); break; } NtStatus = ndisprotOpenDevice( sysBuffer, (ULONG)bufSize, fileObject, &pOpenContext ); if (NT_SUCCESS(NtStatus)) { DEBUGP(DL_VERY_LOUD, ("IoControl OPEN_DEVICE: Open %p <-> FileObject %p\n", pOpenContext, fileObject)); } break; case IOCTL_NDISPROT_QUERY_OID_VALUE: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); NtStatus = WdfRequestRetrieveOutputBuffer(Request, sizeof(NDISPROT_QUERY_OID), &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveOutputBuffer failed %x\n", NtStatus)); break; } if (pOpenContext != NULL) { Status = ndisprotQueryOidValue( pOpenContext, sysBuffer, (ULONG)bufSize, &BytesReturned ); NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); } else { NtStatus = STATUS_DEVICE_NOT_CONNECTED; } break; case IOCTL_NDISPROT_SET_OID_VALUE: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); NtStatus = WdfRequestRetrieveInputBuffer(Request, sizeof(NDISPROT_SET_OID), &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveInputBuffer failed %x\n", NtStatus)); break; } if (pOpenContext != NULL) { Status = ndisprotSetOidValue( pOpenContext, sysBuffer, (ULONG)bufSize ); BytesReturned = 0; NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); } else { NtStatus = STATUS_DEVICE_NOT_CONNECTED; } break; case IOCTL_NDISPROT_INDICATE_STATUS: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); if (pOpenContext != NULL) { NtStatus = WdfRequestForwardToIoQueue(Request, pOpenContext->StatusIndicationQueue ); if(NT_SUCCESS(NtStatus)) { NtStatus = STATUS_PENDING; } } else { NtStatus = STATUS_DEVICE_NOT_CONNECTED; } break; default: NtStatus = STATUS_NOT_SUPPORTED; break; } if (NtStatus != STATUS_PENDING) { WdfRequestCompleteWithInformation(Request, NtStatus, BytesReturned); } return; }
NTSTATUS NfcCxSCPresentAbsentDispatcherSetRequest( _In_ PNFCCX_FDO_CONTEXT FdoContext, _In_ PNFCCX_SC_PRESENT_ABSENT_DISPATCHER Dispatcher, _In_ WDFREQUEST Request ) /*++ Routine Description: Stores a request in the dispatcher. If a request is already pending in the dispatcher, the new request will be completed with STATUS_DEVICE_BUSY. Arguments: FdoContext - Pointer to the FDO Context Dispatcher - Pointer to the Dispatcher. Request - The request to store in the dispatcher. Return Value: NTSTATUS --*/ { NTSTATUS status; bool powerReferenceAcquired = false; bool cancelCallbackSet = false; TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE); WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); PNFCCX_FILE_CONTEXT fileContext = NfcCxFileGetContext(fileObject); // Pre-check if there is a current request. if (ReadPointerAcquire((void**)&Dispatcher->CurrentRequest) != nullptr) { status = STATUS_DEVICE_BUSY; TRACE_LINE(LEVEL_ERROR, "An Is Present/Absent request is already pending. %!STATUS!", status); goto Done; } // Allocate and initialize the request context PNFCCX_SC_REQUEST_CONTEXT requestContext = nullptr; WDF_OBJECT_ATTRIBUTES contextAttributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&contextAttributes, NFCCX_SC_REQUEST_CONTEXT); status = WdfObjectAllocateContext(Request, &contextAttributes, (void**)&requestContext); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "Failed to set request's context. %!STATUS!", status); goto Done; } requestContext->Dispatcher = Dispatcher; // Add a power reference (if required). if (Dispatcher->PowerManaged) { status = NfcCxPowerFileAddReference(FdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_VERBOSE, "Failed to acquire power reference. %!STATUS!", status); goto Done; } powerReferenceAcquired = true; } // Setup cancel callback. status = WdfRequestMarkCancelableEx(Request, NfcCxSCPresentAbsentDispatcherRequestCanceled); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "Failed to set request canceled callback. %!STATUS!", status); goto Done; } // Add a ref-count to the request, which is owned by the cancel callback. WdfObjectReference(Request); cancelCallbackSet = true; // Try to set the current request. void* previousRequest = InterlockedCompareExchangePointer((void**)&Dispatcher->CurrentRequest, /*exchange*/ Request, /*compare*/ nullptr); // Check if we already have a pending request. if (previousRequest != nullptr) { status = STATUS_DEVICE_BUSY; TRACE_LINE(LEVEL_ERROR, "An Is Present/Absent request is already pending. %!STATUS!", status); goto Done; } Done: if (!NT_SUCCESS(status)) { if (cancelCallbackSet) { NTSTATUS unmarkStatus = WdfRequestUnmarkCancelable(Request); if (unmarkStatus != STATUS_CANCELLED) { // Cancel callback will not be called. // So release cancel callback's request ref-count. WdfObjectDereference(Request); } } if (powerReferenceAcquired) { NfcCxPowerFileRemoveReference(FdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity); } } TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status); 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; kJtag_DbgPrint(3, ("kJtag_DispatchReadWrite - begins\n")); // // First validate input parameters. // deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { kJtag_DbgPrint(1, ("Transfer length > circular buffer\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { kJtag_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)){ kJtag_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)){ kJtag_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) { kJtag_DbgPrint(3, ("Read operation\n")); status = WdfUsbTargetPipeFormatRequestForRead(pipe, Request, reqMemory, &offset); } else { kJtag_DbgPrint(3, ("Write operation\n")); status = WdfUsbTargetPipeFormatRequestForWrite(pipe, Request, reqMemory, &offset); } if (!NT_SUCCESS(status)) { kJtag_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) { kJtag_DbgPrint(1, ("WdfRequestSend failed\n")); status = WdfRequestGetStatus(Request); goto Exit; } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); } kJtag_DbgPrint(3, ("kJtag_DispatchReadWrite - ends\n")); return; }
VOID NfcCxSCPresentAbsentDispatcherCompleteRequest( _In_ PNFCCX_FDO_CONTEXT FdoContext, _In_ PNFCCX_SC_PRESENT_ABSENT_DISPATCHER Dispatcher ) /*++ Routine Description: If there is a request in the dispatcher, the request is completed. Arguments: FdoContext - Pointer to the FDO Context Dispatcher - Pointer to the Dispatcher Return Value: VOID --*/ { NTSTATUS status = STATUS_SUCCESS; TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE); // Remove the current request from the dispatcher. WDFREQUEST request = (WDFREQUEST)InterlockedExchangePointer((void**)&Dispatcher->CurrentRequest, nullptr); // Check if another thread has already completed the request. if (request == nullptr) { // Nothing to do. goto Done; } WDFFILEOBJECT fileObject = WdfRequestGetFileObject(request); PNFCCX_FILE_CONTEXT fileContext = NfcCxFileGetContext(fileObject); // Try to unset the request's cancel callback. status = WdfRequestUnmarkCancelable(request); if (status != STATUS_CANCELLED) { // The cancel callback will not be called. // So we have to release its ref-count for it. WdfObjectDereference(request); if (!NT_SUCCESS(status)) { // Something is pretty wrong. NT_ASSERT(false); TRACE_LINE(LEVEL_ERROR, "Failed to unset request canceled callback. %!STATUS!", status); goto Done; } } // Release power reference (if required). if (Dispatcher->PowerManaged) { NfcCxPowerFileRemoveReference(FdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity); } // Complete the request WdfRequestComplete(request, STATUS_SUCCESS); Done: TRACE_FUNCTION_EXIT(LEVEL_VERBOSE); return; }
/* ** Driver TODO: Complete the implementation of EvtIoDeviceControl for your specific device (if necessary) ** ** 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 magnetic stripe reader 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). */ VOID EvtIoDeviceControl(_In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode) { UNREFERENCED_PARAMETER(Queue); NTSTATUS status = STATUS_SUCCESS; ULONG_PTR information = 0; WDFDEVICE device = WdfIoQueueGetDevice(Queue); WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); // These are the set of IOCTLs that your device should handle to work with the Windows.Devices.PointOfService APIs. switch (IoControlCode) { // The first three IOCTLs shouldn't require additional processing other than handing them off to PosCx case IOCTL_POINT_OF_SERVICE_CLAIM_DEVICE: status = PosCxClaimDevice(device, Request); break; case IOCTL_POINT_OF_SERVICE_RELEASE_DEVICE: status = PosCxReleaseDevice(device, fileObject); break; case IOCTL_POINT_OF_SERVICE_RETAIN_DEVICE: status = PosCxRetainDevice(device, Request); break; case IOCTL_POINT_OF_SERVICE_MSR_RETRIEVE_DEVICE_AUTHENTICATION: status = ProcessRetrieveDeviceAuthentication(device, fileObject, Request, &information); break; case IOCTL_POINT_OF_SERVICE_MSR_AUTHENTICATE_DEVICE: status = ProcessAuthenticateDevice(device, fileObject, Request); break; case IOCTL_POINT_OF_SERVICE_MSR_DEAUTHENTICATE_DEVICE: status = ProcessDeauthenticateDevice(device, fileObject, Request); break; case IOCTL_POINT_OF_SERVICE_MSR_UPDATE_KEY: status = ProcessUpdateKey(device, fileObject, Request); break; case IOCTL_POINT_OF_SERVICE_GET_PROPERTY: status = ProcessGetPropertyRequest(Request, InputBufferLength, &information); break; case IOCTL_POINT_OF_SERVICE_SET_PROPERTY: status = ProcessSetPropertyRequest(Request, InputBufferLength, &information); break; case IOCTL_POINT_OF_SERVICE_RETRIEVE_STATISTICS: status = ProcessRetrieveStatisticsRequest(Request, OutputBufferLength, &information); break; case IOCTL_POINT_OF_SERVICE_RESET_STATISTICS: status = ProcessResetStatisticsRequest(Request); break; case IOCTL_POINT_OF_SERVICE_UPDATE_STATISTICS: status = ProcessUpdateStatisticsRequest(Request); break; case IOCTL_POINT_OF_SERVICE_CHECK_HEALTH: status = ProcessCheckHealthRequest(Request, &information); break; // The Get Device Basics IOCTL is always the first IOCTL called by an application using the Windows.Devices.PointOfService APIs. // Use it to determine when to call PosCxMarkPosApp (see notes about apps marked this way in IoRead.cpp) case IOCTL_POINT_OF_SERVICE_GET_DEVICE_BASICS: status = ProcessGetDeviceBasicsRequest(Request, &information); (void)PosCxMarkPosApp(device, fileObject, TRUE); break; default: // Your device may support additional IOCTLs. In this sample, we return failure for anything else. status = STATUS_NOT_SUPPORTED; break; } if (status != STATUS_PENDING) { WdfRequestCompleteWithInformation(Request, status, information); } }
// handles operations that must be performed when an application requests access to a device. VOID vJoy_EvtDeviceFileCreate( __in WDFDEVICE Device, __in WDFREQUEST Request, __in WDFFILEOBJECT FileObject ) { WDFFILEOBJECT FileObj; PCUNICODE_STRING pName; UNICODE_STRING TmpUstr; NTSTATUS status = STATUS_SUCCESS; int id=0; WCHAR RefStr[100]; PFILEOBJECT_EXTENSION pExtension=NULL; PDEVICE_EXTENSION pDevContext = NULL; PRPDO_DEVICE_DATA pPdoData=NULL; size_t len; DWORD_PTR ProcessId; PAGED_CODE (); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Entered vJoy_EvtDeviceFileCreate\n"); // Get file object then get its filename FileObj = WdfRequestGetFileObject(Request); if (!FileObj) goto going_out; pName = WdfFileObjectGetFileName(FileObj); if (!pName) goto going_out; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: File name=%wZ\n", pName); // Extract id from interface number status = RtlStringCchLengthW(VJOY_INTERFACE, 100, &len); if (!NT_SUCCESS(status)) goto going_out; status = RtlStringCchCopyNW(RefStr, 100, pName->Buffer+len+1,4); // Copy the numeric part of the string (000) if (!NT_SUCCESS(status)) goto going_out; RtlInitUnicodeString(&TmpUstr, RefStr); // Convert "000" to UNICODE_STRING status = RtlUnicodeStringToInteger(&TmpUstr, 10, &id); // Convert "000" to integer (0) if (!NT_SUCCESS(status)) goto going_out; if (id>0) { // Verify that this interface has a corresponding device TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: ID=%d\n", id); pPdoData = PdoGetData(Device); pDevContext = GetDeviceContext(pPdoData->hParentDevice); if (!pDevContext) goto going_out; if (!pDevContext->positions[id - 1]) goto going_out; // Get the file object context space // Test that this interface is not in use // and store there the parent (Raw PDO) context pExtension = GetFileObjectContext(FileObject); if (!pExtension) goto going_out; pExtension->pParentRawDeviceContext = pPdoData; if (pPdoData->UsedInterfacesMask & (1 << (id - 1))) { WdfRequestComplete(Request, STATUS_ACCESS_DENIED); ProcessId = (DWORD_PTR)PsGetCurrentProcessId(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: PID=%d Failed (Access Denied)\n", ProcessId); return; } ///// This is a successful file creation - Now record the file details // vJoy Device ID else pPdoData->UsedInterfacesMask |= 1 << (id - 1); // Put id in file object context space pExtension->id = id; // Update // Get the id of the calling process ProcessId = (DWORD_PTR)PsGetCurrentProcessId(); pExtension->CallingProcessId = (DWORD)(ProcessId & 0xFFFFFFFF); TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT, "vJoy_EvtDeviceFileCreate: PID=%d\n", pExtension->CallingProcessId); // Put the file object in the FDO extension pDevContext->DeviceFileObject[id - 1] = FileObject; // Activate FFB Queues FfbActiveSet(TRUE, id, pDevContext); WdfRequestComplete(Request, status); return; } // if (id>0) // Case of General purpose and non device-specific Interface else // if (id<1) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate(2nd case): ID=%d\n", id); #if 0 pPdoData = PdoGetData(Device); pDevContext = GetDeviceContext(pPdoData->hParentDevice); if (!pDevContext) goto going_out; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate(2nd case): Completing Request\n"); #endif // 0 WdfRequestComplete(Request, status); return; }; // if (id<1) going_out: ProcessId = (DWORD_PTR)PsGetCurrentProcessId(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: PID=%d Failed (Invalid Handle)\n", ProcessId); WdfRequestComplete(Request, STATUS_INVALID_HANDLE); }
VOID BthEchoCliRemoteConnectCompletion( __in WDFREQUEST Request, __in WDFIOTARGET Target, __in PWDF_REQUEST_COMPLETION_PARAMS Params, __in WDFCONTEXT Context ) /*++ Description: Completion routine for Create request which we format as open channel BRB and send down the stack. We complete the Create request in this routine. We receive open channel BRB as the context. This BRB is part of the request context and doesn't need to be freed explicitly. Connection is part of the context in the BRB. Arguments: Request - Create request that we formatted with open channel BRB Target - Target to which we sent the request Params - Completion params Context - We receive BRB as the context Return Value: NTSTATUS Status code. --*/ { NTSTATUS status; struct _BRB_L2CA_OPEN_CHANNEL *brb; PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx; PBTHECHO_CONNECTION connection; DevCtx = GetClientDeviceContext(WdfIoTargetGetDevice(Target)); status = Params->IoStatus.Status; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, "Connection completion, status: %!STATUS!", status); brb = (struct _BRB_L2CA_OPEN_CHANNEL *) Context; connection = (PBTHECHO_CONNECTION) brb->Hdr.ClientContext[0]; // // In the client we don't check for ConnectionStateDisconnecting state // because only file close generates disconnect which // cannot happen before create completes. And we complete Create // only after we process this completion. // if(NT_SUCCESS(status)) { connection->OutMTU = brb->OutResults.Params.Mtu; connection->InMTU = brb->InResults.Params.Mtu; connection->ChannelHandle = brb->ChannelHandle; connection->RemoteAddress = brb->BtAddress; connection->ConnectionState = ConnectionStateConnected; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, "Connection established to server"); // // Call the function in device.c (BthEchoCliConnectionStateConnected) // for any post processing after connection has been established // status = BthEchoCliConnectionStateConnected(WdfRequestGetFileObject(Request), connection); if (!NT_SUCCESS(status)) { // // If such post processing fails we disconnect // BthEchoConnectionObjectRemoteDisconnect( &(DevCtx->Header), connection ); } } else { connection->ConnectionState = ConnectionStateConnectFailed; } // // Complete the Create request // WdfRequestComplete(Request, status); return; }
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); } } }