/*
 * hid/inject_timer.h
 *
 * Periodic WDF timer that drives input injection from shared memory
 * into hidclass.sys at DISPATCH_LEVEL.
 *
 * Design rationale:
 *
 *   A real USB HID mouse/keyboard raises an interrupt every poll
 *   interval; the host's xHCI stack completes the URB at DISPATCH_
 *   LEVEL and hidclass.sys delivers the report on the same IRQL.
 *   When the injection path runs at PASSIVE_LEVEL (as it did in the
 *   IOCTL-based prototype) the timing signature visible to user-mode
 *   is conspicuously wrong — every report is delayed by dispatcher
 *   queueing and surrounded by PASSIVE-level thread scheduling
 *   artifacts. Moving injection onto a DISPATCH_LEVEL periodic timer
 *   closes that gap.
 *
 *   The timer fires every VHID_SHARED_HEARTBEAT_MS (= 1 ms) and
 *   consults the shared-memory seq counters. No seq change = no
 *   report emitted. When Seq advances, the callback snapshots the
 *   payload fields and posts exactly one HID report through the
 *   DISPATCH-safe ring buffer in report_queue.c; that buffer then
 *   completes the next pending IOCTL_HID_READ_REPORT IRP owned by
 *   hidclass.sys, mirroring what a USB completion would do.
 *
 *   The timer parent is the device so KMDF destroys it as part of
 *   normal FDO teardown. AutomaticSerialization is FALSE because the
 *   callback only touches DISPATCH-safe state (the ring's spinlock,
 *   Interlocked on shared-memory seq counters) and we do not want a
 *   serialization wait-lock to convert this to PASSIVE on devices
 *   whose execution-level is configured otherwise.
 */

#pragma once
#ifndef VHID_HID_INJECT_TIMER_H_
#define VHID_HID_INJECT_TIMER_H_

#include "driver.h"

/*
 * Build and start the periodic timer against the device context.
 * Called from SelfManagedIoInit so it runs exactly once per start,
 * after PrepareHardware has succeeded and before any reports can be
 * posted. Caller must ensure DevCtx->Shared.View is non-NULL.
 */
_IRQL_requires_(PASSIVE_LEVEL)
NTSTATUS
VhidkmInjectTimerStart(
    _In_ PVHIDKM_DEVICE_CONTEXT DevCtx
    );

/*
 * Stop and flush the timer. Safe to call repeatedly; if the timer
 * was never successfully started the handle is NULL and this is a
 * no-op. Does not free the timer object — KMDF handles that when
 * the parent device is destroyed.
 */
_IRQL_requires_(PASSIVE_LEVEL)
VOID
VhidkmInjectTimerStop(
    _In_ PVHIDKM_DEVICE_CONTEXT DevCtx
    );

#endif /* VHID_HID_INJECT_TIMER_H_ */
