NTSTATUS I2COpen( _In_ PDEVICE_CONTEXT DeviceContext ) /*++ Routine Description: This routine opens a handle to the I2C controller. Arguments: DeviceContext - a pointer to the device context Return Value: NTSTATUS --*/ { TRACE_FUNC_ENTRY(TRACE_I2C); PAGED_CODE(); NTSTATUS status; WDF_IO_TARGET_OPEN_PARAMS openParams; WDF_OBJECT_ATTRIBUTES requestAttributes; WDF_OBJECT_ATTRIBUTES workitemAttributes; WDF_WORKITEM_CONFIG workitemConfig; // Create the device path using the connection ID. DECLARE_UNICODE_STRING_SIZE(DevicePath, RESOURCE_HUB_PATH_SIZE); RESOURCE_HUB_CREATE_PATH_FROM_ID( &DevicePath, DeviceContext->I2CConnectionId.LowPart, DeviceContext->I2CConnectionId.HighPart); TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_I2C, "Opening handle to I2C target via %wZ", &DevicePath); status = WdfIoTargetCreate(DeviceContext->Device, WDF_NO_OBJECT_ATTRIBUTES, &DeviceContext->I2CIoTarget); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfIoTargetCreate failed - %!STATUS!", status); goto Exit; } // Open a handle to the I2C controller. WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( &openParams, &DevicePath, (GENERIC_READ | GENERIC_WRITE)); openParams.ShareAccess = 0; openParams.CreateDisposition = FILE_OPEN; openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; status = WdfIoTargetOpen(DeviceContext->I2CIoTarget, &openParams); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "Failed to open I2C I/O target - %!STATUS!", status); goto Exit; } // Create a WDFMEMORY object. Do call WdfMemoryAssignBuffer before use it, status = WdfMemoryCreatePreallocated( WDF_NO_OBJECT_ATTRIBUTES, static_cast<PVOID>(&status), // initial value does not matter sizeof(status), &DeviceContext->I2CMemory); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfMemoryCreatePreallocated failed with status %!STATUS!", status); goto Exit; } WDF_OBJECT_ATTRIBUTES_INIT(&requestAttributes); requestAttributes.ParentObject = DeviceContext->I2CIoTarget; for (ULONG i = 0; i < I2CRequestSourceMax; i++) { status = WdfRequestCreate(&requestAttributes, DeviceContext->I2CIoTarget, &DeviceContext->OutgoingRequests[i]); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfRequestCreate failed with status %!STATUS!", status); goto Exit; } } WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&workitemAttributes, WORKITEM_CONTEXT); workitemAttributes.ParentObject = DeviceContext->I2CIoTarget; WDF_WORKITEM_CONFIG_INIT(&workitemConfig, EvtWorkItemGetStatus); status = WdfWorkItemCreate(&workitemConfig, &workitemAttributes, &DeviceContext->I2CWorkItemGetStatus); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfWorkItemCreate failed with status %!STATUS!", status); goto Exit; } WDF_WORKITEM_CONFIG_INIT(&workitemConfig, EvtWorkItemGetControl); status = WdfWorkItemCreate(&workitemConfig, &workitemAttributes, &DeviceContext->I2CWorkItemGetControl); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfWorkItemCreate failed with status %!STATUS!", status); goto Exit; } Exit: TRACE_FUNC_EXIT(TRACE_I2C); return status; }
NTSTATUS Toastmon_OpenDevice( WDFDEVICE Device, PUNICODE_STRING SymbolicLink, WDFIOTARGET *Target ) /*++ Routine Description: Open the I/O target and preallocate any resources required to communicate with the target device. Arguments: Return Value: NTSTATUS --*/ { NTSTATUS status = STATUS_SUCCESS; PTARGET_DEVICE_INFO targetDeviceInfo = NULL; WDF_IO_TARGET_OPEN_PARAMS openParams; WDFIOTARGET ioTarget; WDF_OBJECT_ATTRIBUTES attributes; PDEVICE_EXTENSION deviceExtension = GetDeviceExtension(Device); WDF_TIMER_CONFIG wdfTimerConfig; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TARGET_DEVICE_INFO); status = WdfIoTargetCreate(deviceExtension->WdfDevice, &attributes, &ioTarget); if (!NT_SUCCESS(status)) { KdPrint(("WdfIoTargetCreate failed 0x%x\n", status)); return status; } targetDeviceInfo = GetTargetDeviceInfo(ioTarget); targetDeviceInfo->DeviceExtension = deviceExtension; // // Warning: It's not recommended to open the targetdevice // from a pnp notification callback routine, because if // the target device initiates any kind of PnP action as // a result of this open, the PnP manager could deadlock. // You should queue a workitem to do that. // For example, SWENUM devices in conjunction with KS // initiate an enumeration of a device when you do the // open on the device interface. // We can open the target device here because we know the // toaster function driver doesn't trigger any pnp action. // WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( &openParams, SymbolicLink, STANDARD_RIGHTS_ALL); openParams.ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ; // // Framework provides default action for all of these if you don't register // these callbacks -it will close the handle to the target when the device is // being query-removed and reopen it if the query-remove fails. // In this sample, we use a periodic timers to post requests to the target. // So we need to register these callbacks so that we can start and stop // the timer when the state of the target device changes. Since we are // registering these callbacks, we are now responsbile for closing and // reopening the target. // openParams.EvtIoTargetQueryRemove = ToastMon_EvtIoTargetQueryRemove; openParams.EvtIoTargetRemoveCanceled = ToastMon_EvtIoTargetRemoveCanceled; openParams.EvtIoTargetRemoveComplete = ToastMon_EvtIoTargetRemoveComplete; status = WdfIoTargetOpen(ioTarget, &openParams); if (!NT_SUCCESS(status)) { KdPrint(("WdfIoTargetOpen failed with status 0x%x\n", status)); WdfObjectDelete(ioTarget); return status; } KdPrint(("Target Device 0x%x, PDO 0x%x, Fileobject 0x%x, Filehandle 0x%x\n", WdfIoTargetWdmGetTargetDeviceObject(ioTarget), WdfIoTargetWdmGetTargetPhysicalDevice(ioTarget), WdfIoTargetWdmGetTargetFileObject(ioTarget), WdfIoTargetWdmGetTargetFileHandle(ioTarget))); // // Create two requests - one for read and one for write. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = ioTarget; status = WdfRequestCreate(&attributes, ioTarget, &targetDeviceInfo->ReadRequest); if (!NT_SUCCESS(status)) { WdfObjectDelete(ioTarget); return status; } WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = ioTarget; status = WdfRequestCreate(&attributes, ioTarget, &targetDeviceInfo->WriteRequest); if (!NT_SUCCESS(status)) { WdfObjectDelete(ioTarget); return status; } // // Create a passive timer to post requests to the I/O target. // WDF_TIMER_CONFIG_INIT(&wdfTimerConfig, Toastmon_EvtTimerPostRequests); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TIMER_CONTEXT); // // Make IoTarget as parent of the timer to prevent the ioTarget // from deleted until the dpc has runto completion. // attributes.ParentObject = ioTarget; // // By specifying WdfExecutionLevelPassive the framework will invoke // the timer callback Toastmon_EvtTimerPostRequests at PASSIVE_LEVEL. // attributes.ExecutionLevel = WdfExecutionLevelPassive; // // Setting the AutomaticSerialization to FALSE prevents // WdfTimerCreate to fail if the parent device object's // execution level is set to WdfExecutionLevelPassive. // wdfTimerConfig.AutomaticSerialization = FALSE; status = WdfTimerCreate(&wdfTimerConfig, &attributes, &targetDeviceInfo->TimerForPostingRequests ); if(!NT_SUCCESS(status)) { KdPrint(("WdfTimerCreate failed 0x%x\n", status)); WdfObjectDelete(ioTarget); return status; } GetTimerContext(targetDeviceInfo->TimerForPostingRequests)->IoTarget = ioTarget; // // Start the passive timer. The first timer will be queued after 1ms interval and // after that it will be requeued in the timer callback function. // The value of 1 ms (lowest timer resoltion allowed on NT) is chosen here so // that timer would fire right away. // WdfTimerStart(targetDeviceInfo->TimerForPostingRequests, WDF_REL_TIMEOUT_IN_MS(1)); *Target = ioTarget; return status; }
NTSTATUS FireflySetFeature( IN PDEVICE_CONTEXT DeviceContext, IN UCHAR PageId, IN USHORT FeatureId, IN BOOLEAN EnableFeature ) /*++ Routine Description: This routine sets the HID feature by sending HID ioctls to our device. These IOCTLs will be handled by HIDUSB and converted into USB requests and send to the device. Arguments: DeviceContext - Context for our device PageID - UsagePage of the light control feature. FeatureId - Usage ID of the feature. EnanbleFeature - True to turn the light on, Falst to turn if off. Return Value: NT Status code --*/ { WDF_MEMORY_DESCRIPTOR inputDescriptor, outputDescriptor; NTSTATUS status; HID_COLLECTION_INFORMATION collectionInformation = {0}; PHIDP_PREPARSED_DATA preparsedData; HIDP_CAPS caps; USAGE usage; ULONG usageLength; PCHAR report; WDFIOTARGET hidTarget; WDF_IO_TARGET_OPEN_PARAMS openParams; PAGED_CODE(); // // Preinit for error. // preparsedData = NULL; report = NULL; hidTarget = NULL; status = WdfIoTargetCreate(WdfObjectContextGetObject(DeviceContext), WDF_NO_OBJECT_ATTRIBUTES, &hidTarget); if (!NT_SUCCESS(status)) { KdPrint(("FireFly: WdfIoTargetCreate failed 0x%x\n", status)); return status; } // // Open it up, write access only! // WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( &openParams, &DeviceContext->PdoName, FILE_WRITE_ACCESS); // // We will let the framework to respond automatically to the pnp // state changes of the target by closing and opening the handle. // openParams.ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ; status = WdfIoTargetOpen(hidTarget, &openParams); if (!NT_SUCCESS(status)) { KdPrint(("FireFly: WdfIoTargetOpen failed 0x%x\n", status)); goto ExitAndFree; } WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor, (PVOID) &collectionInformation, sizeof(HID_COLLECTION_INFORMATION)); // // Now get the collection information for this device // status = WdfIoTargetSendIoctlSynchronously(hidTarget, NULL, IOCTL_HID_GET_COLLECTION_INFORMATION, NULL, &outputDescriptor, NULL, NULL); if (!NT_SUCCESS(status)) { KdPrint(("FireFly: WdfIoTargetSendIoctlSynchronously failed 0x%x\n", status)); goto ExitAndFree; } preparsedData = (PHIDP_PREPARSED_DATA) ExAllocatePoolWithTag( NonPagedPool, collectionInformation.DescriptorSize, 'ffly'); if (preparsedData == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto ExitAndFree; } WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor, (PVOID) preparsedData, collectionInformation.DescriptorSize); status = WdfIoTargetSendIoctlSynchronously(hidTarget, NULL, IOCTL_HID_GET_COLLECTION_DESCRIPTOR, NULL, &outputDescriptor, NULL, NULL); if (!NT_SUCCESS(status)) { KdPrint(("FireFly: WdfIoTargetSendIoctlSynchronously failed 0x%x\n", status)); goto ExitAndFree; } // // Now get the capabilities. // RtlZeroMemory(&caps, sizeof(HIDP_CAPS)); status = HidP_GetCaps(preparsedData, &caps); if (!NT_SUCCESS(status)) { goto ExitAndFree; } // // Create a report to send to the device. // report = (PCHAR) ExAllocatePoolWithTag( NonPagedPool, caps.FeatureReportByteLength, 'ffly'); if (report == NULL) { goto ExitAndFree; } // // Start with a zeroed report. If we are disabling the feature, this might // be all we need to do. // RtlZeroMemory(report, caps.FeatureReportByteLength); status = STATUS_SUCCESS; if (EnableFeature) { // // Edit the report to reflect the enabled feature // usage = FeatureId; usageLength = 1; status = HidP_SetUsages( HidP_Feature, PageId, 0, &usage, // pointer to the usage list &usageLength, // number of usages in the usage list preparsedData, report, caps.FeatureReportByteLength ); if (!NT_SUCCESS(status)) { KdPrint(("FireFly: HidP_SetUsages failed 0x%x\n", status)); goto ExitAndFree; } } WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDescriptor, report, caps.FeatureReportByteLength); status = WdfIoTargetSendIoctlSynchronously(hidTarget, NULL, IOCTL_HID_SET_FEATURE, &inputDescriptor, NULL, NULL, NULL); if (!NT_SUCCESS(status)) { KdPrint(("FireFly: WdfIoTargetSendIoctlSynchronously failed 0x%x\n", status)); goto ExitAndFree; } ExitAndFree: if (preparsedData != NULL) { ExFreePool(preparsedData); preparsedData = NULL; } if (report != NULL) { ExFreePool(report); report = NULL; } if (hidTarget != NULL) { WdfObjectDelete(hidTarget); } return status; }