234 lines
7.5 KiB
C
234 lines
7.5 KiB
C
/*
|
|
********************************************************************************
|
|
*
|
|
* READ.C
|
|
*
|
|
*
|
|
* VXDCLNT - Sample Ring-0 HID device mapper for Memphis
|
|
*
|
|
* Copyright 1997 Microsoft Corp.
|
|
*
|
|
* (ep)
|
|
*
|
|
********************************************************************************
|
|
*/
|
|
|
|
|
|
#include "vxdclnt.h"
|
|
|
|
|
|
|
|
/*
|
|
* WorkItemCallback_Read
|
|
*
|
|
*/
|
|
VOID WorkItemCallback_Read(PVOID context)
|
|
{
|
|
deviceContext *device = (deviceContext *)context;
|
|
NTSTATUS Status;
|
|
|
|
DBGOUT(("==> WorkItemCallback_Read()"));
|
|
|
|
device->dataLength.LowPart = device->dataLength.HighPart = 0;
|
|
device->readPending = TRUE;
|
|
|
|
/*
|
|
* Do an asynchronous read on the device device.
|
|
* When the device has a delta value to report, we will be called back
|
|
* via ReadCompletion().
|
|
*/
|
|
Status = _NtKernReadFile(
|
|
device->devHandle,
|
|
NULL,
|
|
ReadCompletion,
|
|
(PVOID)device, // context for callback
|
|
(PIO_STATUS_BLOCK)&device->ioStatusBlock,
|
|
(PVOID)device->report,
|
|
device->hidCapabilities.InputReportByteLength,
|
|
&device->dataLength,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status) && (Status != STATUS_PENDING)) {
|
|
/*
|
|
* Read failed. Since device is no longer usable, shut it down.
|
|
*/
|
|
DBGERR(("_NtKernReadFile error (Status=%xh) - SHUTTING DOWN THIS DEVICE", (UINT)Status));
|
|
device->readPending = FALSE;
|
|
DequeueDevice(device);
|
|
DestroyDevice(device);
|
|
}
|
|
|
|
DBGOUT(("<== WorkItemCallback_Read()"));
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* DispatchNtReadFile
|
|
*
|
|
*
|
|
*/
|
|
VOID _cdecl DispatchNtReadFile(deviceContext *device)
|
|
{
|
|
DBGOUT(("==> DispatchNtReadFile()"));
|
|
/*
|
|
* Queue a work item to do the read; this way we'll be on a worker thread
|
|
* instead of (possibly) the NTKERN thread when we call NtReadFile().
|
|
* This prevents a contention bug.
|
|
*/
|
|
_NtKernQueueWorkItem(&device->workItemRead, DelayedWorkQueue);
|
|
|
|
DBGOUT(("<== DispatchNtReadFile()"));
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* ReadCompletion
|
|
*
|
|
*
|
|
*/
|
|
VOID ReadCompletion(IN PVOID Context, IN PIO_STATUS_BLOCK IoStatusBlock, IN ULONG Reserved)
|
|
{
|
|
ULONG dX = 0, dY = 0, Buttons = 0, scrollWheel=0;
|
|
NTSTATUS ntStatus;
|
|
deviceContext *device = (deviceContext *)Context;
|
|
UINT numActualButtons;
|
|
|
|
DBGOUT(("==> ReadCompletion()"));
|
|
|
|
device->readPending = FALSE;
|
|
|
|
/*
|
|
* If this callback got to us after we've shut down, just delete this device context.
|
|
*/
|
|
if (ShutDown){
|
|
TryDestroyAll();
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* If the read succeeded, parse out the report information.
|
|
*/
|
|
if (NT_SUCCESS(IoStatusBlock->Status)){
|
|
|
|
|
|
/*
|
|
* <<COMPLETE>>
|
|
*
|
|
* What types of usage-values will you parse out of the device report?
|
|
* This is device specific.
|
|
* The code below would be appropriate for a 2-dimensional pointing
|
|
* device with buttons (e.g. a mouse or touch screen).
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* Parse the device "report" for the values we want.
|
|
*
|
|
* For each value, try HIDPARSE's scaled function first;
|
|
* failing that, try the non-scaled function.
|
|
* (the scaled functions can fail for some devices that don't
|
|
* report their min and max values correctly).
|
|
*/
|
|
|
|
ntStatus = pHidP_GetScaledUsageValue(HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_X,
|
|
(PLONG)&dX,
|
|
device->hidDescriptor,
|
|
(PUCHAR)device->report,
|
|
device->hidCapabilities.InputReportByteLength);
|
|
if (NT_ERROR(ntStatus)){
|
|
DBGERR(("pHidP_GetScaledUsageValue failed"));
|
|
|
|
ntStatus = pHidP_GetUsageValue(HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_X,
|
|
&dX,
|
|
device->hidDescriptor,
|
|
(PUCHAR)device->report,
|
|
device->hidCapabilities.InputReportByteLength);
|
|
if (NT_ERROR(ntStatus)){
|
|
DBGERR(("pHidP_GetUsageValue failed"));
|
|
}
|
|
}
|
|
|
|
ntStatus = pHidP_GetScaledUsageValue(HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_Y,
|
|
(PLONG)&dY,
|
|
device->hidDescriptor,
|
|
(PUCHAR)device->report,
|
|
device->hidCapabilities.InputReportByteLength);
|
|
if (NT_ERROR(ntStatus)){
|
|
DBGERR(("pHidP_GetScaledUsageValue failed"));
|
|
|
|
ntStatus = pHidP_GetUsageValue(HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_Y,
|
|
&dY,
|
|
device->hidDescriptor,
|
|
(PUCHAR)device->report,
|
|
device->hidCapabilities.InputReportByteLength);
|
|
if (NT_ERROR(ntStatus)){
|
|
DBGERR(("pHidP_GetUsageValue failed"));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Parse the button values
|
|
*/
|
|
numActualButtons = device->buttonListLength;
|
|
pHidP_GetUsages(HidP_Input,
|
|
HID_USAGE_PAGE_BUTTON,
|
|
0,
|
|
device->buttonValues,
|
|
&numActualButtons,
|
|
device->hidDescriptor,
|
|
(PUCHAR)device->report,
|
|
device->hidCapabilities.InputReportByteLength);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* <<COMPLETE>>
|
|
*
|
|
* What are you going to do with the parsed data from the device?
|
|
* This is device specific.
|
|
*
|
|
*/
|
|
|
|
|
|
}
|
|
else {
|
|
DBGERR(("ReadCompletion returned ERROR %xh.", (UINT)IoStatusBlock->Status));
|
|
|
|
/*
|
|
* Remove this device and then try to re-open it.
|
|
*/
|
|
DequeueDevice(device);
|
|
DestroyDevice(device);
|
|
ConnectNTDeviceDrivers();
|
|
}
|
|
|
|
|
|
/*
|
|
* Set up the next read of the device device.
|
|
*/
|
|
DispatchNtReadFile(device);
|
|
|
|
DBGOUT(("<== ReadCompletion()"));
|
|
}
|