This document describes how to implement calibration support in a KMDF-based HID minidriver for a touch controller connected over I²C. It covers design goals, data flow, required HID usages and reports, driver components, calibration algorithms, persistent storage, and testing/validation steps.
Ensure your affine transform scales each touch point independently. The HID protocol for multi-touch (Usage Page 0x0D, Usage 0x05) requires that each contact’s Tip Switch and X/Y arrays be transformed individually. Use a parallel loop (KeAcquireSpinLock for each touch frame) to maintain performance.
A best-in-class KMDF minidriver adds post-calibration filtering: kmdf hid minidriver for touch i2c device calibration best
In a KMDF driver, I2C communication is handled asynchronously via the SPB (Simple Peripheral Bus) target.
Write a user-mode app that draws a 3x3 grid. Touch each point. Measure the delta between expected and reported position. A best calibration yields < 0.5mm average error on a 10-inch screen. This document describes how to implement calibration support
Below is a simplified structure of the calibration logic inside your EvtIoDeviceControl handler for IOCTL_TOUCH_CALIBRATE.
NTSTATUS TouchCalibrate_EvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode) PTOUCH_CALIBRATION_INPUT input = NULL; WDFMEMORY memory; NTSTATUS status = STATUS_SUCCESS;// 1. Retrieve raw/display point pairs from user-mode app status = WdfRequestRetrieveInputMemory(Request, &memory); input = (PTOUCH_CALIBRATION_INPUT)WdfMemoryGetBuffer(memory, NULL); // 2. Compute affine matrix using Least Squares double matrix[6]; status = ComputeCalibrationMatrix(input->RawPoints, input->DisplayPoints, input->NumPoints, matrix); // 3. Persist to registry status = StoreCalibrationRegistry(matrix); // 4. Send HID Feature Report to I2C device (Report ID 0x03) UCHAR featureReport[32] = 0; featureReport[0] = 0x03; // Report ID for calibration RtlCopyMemory(&featureReport[1], matrix, sizeof(matrix)); status = WriteI2C_HIDFeatureReport(DeviceContext, featureReport, 32); // 5. Complete request WdfRequestComplete(Request, status); return status;
A HID Minidriver (also called a HID Transport Driver) sits below the class driver (HIDClass.sys). Its job is to communicate directly with the I²C controller, retrieve HID reports from the touch device, and forward them up the stack. Ensure your affine transform scales each touch point
Touch Device (I2C) → KMDF HID Minidriver → HIDClass.sys → Touch Input Stack → User Mode