windows-nt/Source/XPSP1/NT/drivers/wdm/input/samples/vxdclnt/read.c
2020-09-26 16:20:57 +08:00

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()"));
}