Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
337 changes: 291 additions & 46 deletions FrameworkArgb/Device.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,15 @@ Module Name:
--*/

#include "driver.h"
#include "EcCommunication.h"
#include "device.tmh"

#define LAMP_ARRAY_ATTRIBUTES_REPORT_ID 0x01
#define LAMP_ATTRIBUTES_REQUEST_REPORT_ID 0x02
#define LAMP_ATTRIBUTES_RESPONSE_REPORT_ID 0x03
#define LAMP_MULTI_UPDATE_REPORT_ID 0x04
#define LAMP_RANGE_UPDATE_REPORT_ID 0x05
#define LAMP_ARRAY_CONTROL_REPORT_ID 0x06

//
// This is the default report descriptor for the virtual Hid device returned
// by the mini driver in response to IOCTL_HID_GET_REPORT_DESCRIPTOR.
//
// It's taken straight from the HID specification for LampArray devices, no changes needed.
//
HID_REPORT_DESCRIPTOR G_DefaultReportDescriptor[] = {
0x05, 0x59, // USAGE_PAGE (LightingAndIllumination)
0x09, 0x01, // USAGE (LampArray)
Expand Down Expand Up @@ -232,52 +228,301 @@ Return Value:
WDFDEVICE device;
NTSTATUS status;

TraceInformation("%!FUNC! Entry");

//
// Mark ourselves as a filter, which also relinquishes power policy ownership
//
WdfFdoInitSetFilter(DeviceInit);

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);

status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);

if (!NT_SUCCESS(status)) {
TraceError("WdfDeviceCreate failed %!STATUS!", status);
return status;
}

//
// Get a pointer to the device context structure that we just associated
// with the device object. We define this structure in the device.h
// header file. DeviceGetContext is an inline function generated by
// using the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in device.h.
// This function will do the type checking and return the device context.
// If you pass a wrong object handle it will return NULL and assert if
// run under framework verifier mode.
//
deviceContext = GetDeviceContext(device);

//
// Initialize the context.
//
deviceContext->Device = device;
deviceContext->CurrentLampId = 0;
deviceContext->AutonomousMode = TRUE;
// 8 LEDs in a circle
// z is 0 for all LEDs, they're all in the same plane
// Bottom LED
deviceContext->LampPositions[0].x = 40000;
deviceContext->LampPositions[0].y = 0;
deviceContext->LampPositions[1].x = 60000;
deviceContext->LampPositions[1].y = 20000;
// Right LED
deviceContext->LampPositions[2].x = 80000;
deviceContext->LampPositions[2].y = 40000;
deviceContext->LampPositions[3].x = 60000;
deviceContext->LampPositions[3].y = 60000;
// Top LED
deviceContext->LampPositions[4].x = 40000;
deviceContext->LampPositions[4].y = 80000;
deviceContext->LampPositions[5].x = 20000;
deviceContext->LampPositions[5].y = 60000;
// Left LED
deviceContext->LampPositions[6].x = 0;
deviceContext->LampPositions[6].y = 40000;
deviceContext->LampPositions[7].x = 20000;
deviceContext->LampPositions[7].y = 20000;

hidAttributes = &deviceContext->HidDeviceAttributes;
RtlZeroMemory(hidAttributes, sizeof(HID_DEVICE_ATTRIBUTES));
hidAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
hidAttributes->VendorID = FWK_ARGB_HID_VID;
hidAttributes->ProductID = FWK_ARGB_HID_PID;
hidAttributes->VersionNumber = FWK_ARGB_HID_VERSION;

deviceContext->CrosEcHandle = INVALID_HANDLE_VALUE;
status = ConnectToEc(&deviceContext->CrosEcHandle);
if (!NT_SUCCESS(status)) {
TraceError("COMBO %!FUNC! ConnectToEc failed %!STATUS!", status);
return status;
}

status = QueueCreate(device,
&deviceContext->DefaultQueue);
if (!NT_SUCCESS(status)) {
TraceError("QueueCreate failed %!STATUS!", status);
return status;
}

status = ManualQueueCreate(device,
&deviceContext->ManualQueue);
if (!NT_SUCCESS(status)) {
TraceError("ManualQueueCreate failed %!STATUS!", status);
return status;
}

//
// Use default "HID Descriptor" and "HID Report Descriptor" (hardcoded)
//
deviceContext->HidDescriptor = G_DefaultHidDescriptor;
deviceContext->ReportDescriptor = G_DefaultReportDescriptor;

return status;
}

NTSTATUS
GetStringId(
_In_ WDFREQUEST Request,
_Out_ ULONG* StringId,
_Out_ ULONG* LanguageId
)
/*++

Routine Description:

Helper routine to decode IOCTL_HID_GET_INDEXED_STRING and IOCTL_HID_GET_STRING.

Arguments:

Request - Pointer to Request Packet.

Return Value:

NT status code.

--*/
{
NTSTATUS status;
ULONG inputValue;

#ifdef _KERNEL_MODE

WDF_REQUEST_PARAMETERS requestParameters;

//
// IOCTL_HID_GET_STRING: // METHOD_NEITHER
// IOCTL_HID_GET_INDEXED_STRING: // METHOD_OUT_DIRECT
//
// The string id (or string index) is passed in Parameters.DeviceIoControl.
// Type3InputBuffer. However, Parameters.DeviceIoControl.InputBufferLength
// was not initialized by hidclass.sys, therefore trying to access the
// buffer with WdfRequestRetrieveInputMemory will fail
//
// Another problem with IOCTL_HID_GET_INDEXED_STRING is that METHOD_OUT_DIRECT
// expects the input buffer to be Irp->AssociatedIrp.SystemBuffer instead of
// Type3InputBuffer. That will also fail WdfRequestRetrieveInputMemory.
//
// The solution to the above two problems is to get Type3InputBuffer directly
//
// Also note that instead of the buffer's content, it is the buffer address
// that was used to store the string id (or index)
//

WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
WdfRequestGetParameters(Request, &requestParameters);

inputValue = PtrToUlong(
requestParameters.Parameters.DeviceIoControl.Type3InputBuffer);

status = STATUS_SUCCESS;

#else

WDFMEMORY inputMemory;
size_t inputBufferLength;
PVOID inputBuffer;

//
// mshidumdf.sys updates the IRP and passes the string id (or index) through
// the input buffer correctly based on the IOCTL buffer type
//

status = WdfRequestRetrieveInputMemory(Request, &inputMemory);
if (!NT_SUCCESS(status)) {
TraceError("WdfRequestRetrieveInputMemory failed 0x%x\n", status);
return status;
}
inputBuffer = WdfMemoryGetBuffer(inputMemory, &inputBufferLength);

//
// make sure buffer is big enough.
//
if (inputBufferLength < sizeof(ULONG))
{
status = STATUS_INVALID_BUFFER_SIZE;
TraceError("GetStringId: invalid input buffer. size %d, expect %d\n",
(int)inputBufferLength, (int)sizeof(ULONG));
return status;
}

inputValue = (*(PULONG)inputBuffer);

#endif

//
// The least significant two bytes of the INT value contain the string id.
//
* StringId = (inputValue & 0x0ffff);

//
// The most significant two bytes of the INT value contain the language
// ID (for example, a value of 1033 indicates English).
//
*LanguageId = (inputValue >> 16);

return status;
}


NTSTATUS
GetIndexedString(
_In_ WDFREQUEST Request
)
/*++

Routine Description:

Handles IOCTL_HID_GET_INDEXED_STRING

Arguments:

Request - Pointer to Request Packet.

Return Value:

NT status code.

--*/
{
NTSTATUS status;
ULONG languageId, stringIndex;

status = GetStringId(Request, &stringIndex, &languageId);

// While we don't use the language id, some minidrivers might.
//
UNREFERENCED_PARAMETER(languageId);

if (NT_SUCCESS(status)) {
//
// Get a pointer to the device context structure that we just associated
// with the device object. We define this structure in the device.h
// header file. DeviceGetContext is an inline function generated by
// using the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in device.h.
// This function will do the type checking and return the device context.
// If you pass a wrong object handle it will return NULL and assert if
// run under framework verifier mode.
//
deviceContext = DeviceGetContext(device);

//
// Initialize the context.
//
deviceContext->Device = device;
deviceContext->DeviceData = 0;

hidAttributes = &deviceContext->HidDeviceAttributes;
RtlZeroMemory(hidAttributes, sizeof(HID_DEVICE_ATTRIBUTES));
hidAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
hidAttributes->VendorID = FWK_ARGB_HID_VID;
hidAttributes->ProductID = FWK_ARGB_HID_PID;
hidAttributes->VersionNumber = FWK_ARGB_HID_VERSION;

//
// Create a device interface so that applications can find and talk
// to us.
//
status = WdfDeviceCreateDeviceInterface(
device,
&GUID_DEVINTERFACE_FrameworkArgb,
NULL // ReferenceString
);

if (NT_SUCCESS(status)) {
//
// Initialize the I/O Package and any Queues
//
status = FrameworkArgbQueueInitialize(device);

if (stringIndex != FWK_ARGB_DEVICE_STRING_INDEX)
{
status = STATUS_INVALID_PARAMETER;
TraceError("GetString: unkown string index %d\n", stringIndex);
return status;
}

status = RequestCopyFromBuffer(Request, FWK_ARGB_DEVICE_STRING, sizeof(FWK_ARGB_DEVICE_STRING));
}
return status;
}


NTSTATUS
GetString(
_In_ WDFREQUEST Request
)
/*++

Routine Description:

Handles IOCTL_HID_GET_STRING.

Arguments:

Request - Pointer to Request Packet.

Return Value:

NT status code.

--*/
{
NTSTATUS status;
ULONG languageId, stringId;
size_t stringSizeCb;
PWSTR string;

status = GetStringId(Request, &stringId, &languageId);

// While we don't use the language id, some minidrivers might.
//
UNREFERENCED_PARAMETER(languageId);

if (!NT_SUCCESS(status)) {
return status;
}

switch (stringId) {
case HID_STRING_ID_IMANUFACTURER:
stringSizeCb = sizeof(FWK_ARGB_MANUFACTURER_STRING);
string = FWK_ARGB_MANUFACTURER_STRING;
break;
case HID_STRING_ID_IPRODUCT:
stringSizeCb = sizeof(FWK_ARGB_PRODUCT_STRING);
string = FWK_ARGB_PRODUCT_STRING;
break;
case HID_STRING_ID_ISERIALNUMBER:
stringSizeCb = sizeof(FWK_ARGB_SERIAL_NUMBER_STRING);
string = FWK_ARGB_SERIAL_NUMBER_STRING;
break;
default:
status = STATUS_INVALID_PARAMETER;
TraceError("GetString: unkown string id %d\n", stringId);
return status;
}

status = RequestCopyFromBuffer(Request, string, stringSizeCb);
return status;
}
Loading