Skip to content

Commit

Permalink
Went to the simplest approach.
Browse files Browse the repository at this point in the history
- Look for intelliouse taillight arrival
- Start a worker thread to thunk to pageable code
- Set the taillight black
  • Loading branch information
ManOnTheMountainTech committed Feb 22, 2024
1 parent 31deac7 commit f4c40c2
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 30 deletions.
4 changes: 4 additions & 0 deletions TailLight/SetBlack.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

NTSTATUS CreateWorkItemForIoTargetOpenDevice(WDFDEVICE device);
NTSTATUS SetBlackAsync(WDFDEVICE device);
250 changes: 250 additions & 0 deletions TailLight/SetTaillightBlack.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
#include "driver.h"
#include <Hidport.h>

#include "debug.h"
#include "SetBlack.h"

EVT_WDF_REQUEST_COMPLETION_ROUTINE SetBlackCompletionRoutine;
EVT_WDF_WORKITEM SetBlackWorkItem;

NTSTATUS CreateWorkItemForIoTargetOpenDevice(WDFDEVICE device)
/*++
Routine Description:
Creates a WDF workitem to do the SetBlack() call after the driver
stack has initialized.
Arguments:
Device - Handle to a pre-allocated WDF work item.
Requirements:
Must be synchronized to the device.
--*/
{

//TRACE_FN_ENTRY

WDFWORKITEM hWorkItem = 0;
NTSTATUS status = STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE;
{
WDF_WORKITEM_CONFIG workItemConfig;
WDF_OBJECT_ATTRIBUTES workItemAttributes;
WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes);
workItemAttributes.ParentObject = device;

DEVICE_CONTEXT* pDeviceContext = WdfObjectGet_DEVICE_CONTEXT(device);

// It's possible to get called twice. Been there, done that?
if (pDeviceContext->fSetBlackSuccess) {
return STATUS_SUCCESS;
}

WDF_WORKITEM_CONFIG_INIT(&workItemConfig, SetBlackWorkItem);

status = WdfWorkItemCreate(&workItemConfig,
&workItemAttributes,
&hWorkItem);

if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_IHVDRIVER_ID,
DPFLTR_ERROR_LEVEL,
"TailLight: Workitem creation failure 0x%x\n",
status));
return status; // Maybe better luck next time.
}

InterlockedIncrement((PLONG)(&pDeviceContext->fSetBlackSuccess));
}

WdfWorkItemEnqueue(hWorkItem);

//TRACE_FN_EXIT

return status;
}

static NTSTATUS TryToOpenIoTarget(WDFIOTARGET target,
DEVICE_CONTEXT& DeviceContext) {

PAGED_CODE();

WDF_IO_TARGET_OPEN_PARAMS openParams = {};
WDF_IO_TARGET_OPEN_PARAMS_INIT_CREATE_BY_NAME(
&openParams,
&DeviceContext.PdoName,
FILE_WRITE_ACCESS);

openParams.ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ;

NTSTATUS status = STATUS_UNSUCCESSFUL;

// Ensure freed if fails.
status = WdfIoTargetOpen(target, &openParams);
if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_IHVDRIVER_ID,
DPFLTR_ERROR_LEVEL,
"TailLight: 0x%x while opening the I/O target from worker thread\n",
status));
NukeWdfHandle<WDFIOTARGET>(target);
}

return status;
}

void SetBlackCompletionRoutine(
_In_ WDFREQUEST Request,
_In_ WDFIOTARGET Target,
_In_ PWDF_REQUEST_COMPLETION_PARAMS Params,
_In_ WDFCONTEXT Context)
{
UNREFERENCED_PARAMETER(Target);
UNREFERENCED_PARAMETER(Params);
UNREFERENCED_PARAMETER(Context);

NTSTATUS status = STATUS_UNSUCCESSFUL;
status = WdfRequestGetStatus(Request);
KdPrint(("TailLight: %s WdfRequestSend status: 0x%x\n", __func__, status));

// One-shot and top of stack, so delete and pray.
WdfObjectDelete(Request);
}

VOID SetBlackWorkItem(
WDFWORKITEM workItem)
/*++
Routine Description:
Creates a WDF workitem to do the SetBlack() call after the driver
stack has initialized.
Arguments:
workItem - Handle to a pre-allocated WDF work item.
--*/
{
TRACE_FN_ENTRY

NTSTATUS status = STATUS_UNSUCCESSFUL;
WDFDEVICE device = static_cast<WDFDEVICE>(WdfWorkItemGetParentObject(workItem));

status = SetBlackAsync(device);
NukeWdfHandle(workItem);

//TRACE_FN_EXIT
}

NTSTATUS SetBlackAsync(WDFDEVICE device) {

TRACE_FN_ENTRY

NTSTATUS status = STATUS_FAILED_DRIVER_ENTRY;
WDFIOTARGET hidTarget = NULL;

DEVICE_CONTEXT* pDeviceContext = NULL;

pDeviceContext =
WdfObjectGet_DEVICE_CONTEXT(device);

if (pDeviceContext == NULL) {
return STATUS_DEVICE_NOT_READY;
}
{
// Ensure freed if fails.
status = WdfIoTargetCreate(
device,
WDF_NO_OBJECT_ATTRIBUTES,
&hidTarget);

if (!NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_IHVDRIVER_ID,
DPFLTR_ERROR_LEVEL,
"TailLight: 0x%x while creating I/O target from worker thread\n",
status));
return status;
}

status = TryToOpenIoTarget(hidTarget, *pDeviceContext);
}

if (NT_SUCCESS(status)) {

WDFREQUEST request = NULL;

status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES,
hidTarget,
&request);

if (!NT_SUCCESS(status)) {
KdPrint(("TailLight: WdfRequestCreate failed 0x%x\n", status));
goto ExitAndFree;
}

WdfRequestSetCompletionRoutine(
request,
SetBlackCompletionRoutine,
WDF_NO_CONTEXT);

TailLightReport report = {};
report.Blue = 0x0;
report.Green = 0x0;
report.Red = 0x0;

// Set up a WDF memory object for the IOCTL request
WDF_OBJECT_ATTRIBUTES mem_attrib = {};
WDF_OBJECT_ATTRIBUTES_INIT(&mem_attrib);
mem_attrib.ParentObject = request; // auto-delete with request*/

WDFMEMORY InBuffer = 0;
BYTE* pInBuffer = nullptr;

status = WdfMemoryCreate(&mem_attrib,
NonPagedPoolNx,
POOL_TAG,
sizeof(TailLightReport),
&InBuffer,
(void**)&pInBuffer);

if (!NT_SUCCESS(status)) {
KdPrint(("TailLight: WdfMemoryCreate failed: 0x%x\n", status));
goto ExitAndFree;
}

// TODO: Wondering if we just cant cast pInBuffr as a TailLightReport
RtlCopyMemory(pInBuffer, &report, sizeof(TailLightReport));

// Format the request as write operation
status = WdfIoTargetFormatRequestForIoctl(hidTarget,
request,
IOCTL_HID_SET_FEATURE,
InBuffer,
NULL,
0,
0);

if (!NT_SUCCESS(status)) {
KdPrint(("TailLight: WdfIoTargetFormatRequestForIoctl failed: 0x%x\n", status));
goto ExitAndFree;
}

pDeviceContext->previousThread = KeGetCurrentThread();

if (!WdfRequestSend(request, hidTarget, WDF_NO_SEND_OPTIONS)) {
WdfObjectDelete(request);
request = NULL;
}
}

ExitAndFree:
if (hidTarget != NULL) {
WdfObjectDelete(hidTarget);
hidTarget = NULL;
}

TRACE_FN_EXIT

return status;
}
3 changes: 3 additions & 0 deletions TailLight/TailLight.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ copy "$(WDKBinRoot_x64)\certmgr.exe" $(PackageDir)</Command>
<ClCompile Include="device.cpp" />
<ClCompile Include="driver.cpp" />
<ClCompile Include="eventlog.cpp" />
<ClCompile Include="SetTaillightBlack.cpp" />
<ClCompile Include="vfeature.cpp" />
<ClCompile Include="wmi.cpp" />
<ResourceCompile Include="module.rc" />
Expand All @@ -119,9 +120,11 @@ copy "$(WDKBinRoot_x64)\certmgr.exe" $(PackageDir)</Command>
</ItemGroup>
<ItemGroup>
<ClInclude Include="CppAllocator.hpp" />
<ClInclude Include="debug.h" />
<ClInclude Include="device.h" />
<ClInclude Include="driver.h" />
<ClInclude Include="eventlog.h" />
<ClInclude Include="SetBlack.h" />
<ClInclude Include="TailLight.h" />
<ClInclude Include="vfeature.h" />
<ClInclude Include="wmi.h" />
Expand Down
10 changes: 10 additions & 0 deletions TailLight/debug.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#pragma once

#define TRACE_FN_ENTRY KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "TailLight: Entry %s\n", __func__));
#define TRACE_FN_EXIT KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "TailLight: Exit: %s\n", __func__));
#define TRACE_REQUEST_BOOL(ret) KdPrint(("TailLight: WdfRequestSend returned bool: 0x%x\n", ret));
#define TRACE_REQUEST_FAILURE(status) KdPrint(("TailLight: WdfRequestSend failed. Status=: 0x%x\n", ret));

NTSTATUS DumpTarget(WDFIOTARGET target, WDFMEMORY& memory);
Loading

0 comments on commit f4c40c2

Please sign in to comment.