mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
702 lines
24 KiB
702 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
read.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code for translating HID input reports to mouse
|
|
reports, and read initiation and completion code for requests sent to the
|
|
HID class driver. This module is part of the HID Mouse Filter Driver.
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
Jan-1997 : Initial writing, Dan Markarian
|
|
|
|
--*/
|
|
|
|
#include "mouhid.h"
|
|
|
|
|
|
//
|
|
// Private definitions.
|
|
//
|
|
#define MAX_MOUSE_BUTTONS 5
|
|
|
|
USHORT HidP_TranslateUsageToUpFlag[MAX_MOUSE_BUTTONS+1] = { 0,
|
|
MOUSE_BUTTON_1_UP,
|
|
MOUSE_BUTTON_2_UP,
|
|
MOUSE_BUTTON_3_UP,
|
|
MOUSE_BUTTON_4_UP,
|
|
MOUSE_BUTTON_5_UP };
|
|
|
|
USHORT HidP_TranslateUsageToDownFlag[MAX_MOUSE_BUTTONS+1] = { 0,
|
|
MOUSE_BUTTON_1_DOWN,
|
|
MOUSE_BUTTON_2_DOWN,
|
|
MOUSE_BUTTON_3_DOWN,
|
|
MOUSE_BUTTON_4_DOWN,
|
|
MOUSE_BUTTON_5_DOWN };
|
|
|
|
NTSTATUS
|
|
MouHid_ReadComplete (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PDEVICE_EXTENSION Data // (PVOID Context)
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the read IRP completion routine. It is called when the
|
|
HIDCLASS driver satisfies (or rejects) the IRP request we sent it. The
|
|
read report is analysed, and a MOUSE_INPUT_DATA structure is built
|
|
and sent to the mouse class driver via a callback routine.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Context - Pointer to the device context structure describing the HID device.
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS result code.
|
|
|
|
--*/
|
|
{
|
|
LONG axisMotion;
|
|
ULONG i;
|
|
ULONG inputDataConsumed;
|
|
PHID_EXTENSION hid;
|
|
ULONG numUsages;
|
|
KIRQL oldIrql;
|
|
BOOLEAN returnToIdleState = FALSE;
|
|
NTSTATUS status;
|
|
PUSAGE usageList;
|
|
BOOLEAN updateProblemFlags = FALSE;
|
|
ULONGLONG scratch;
|
|
BOOLEAN startRead;
|
|
|
|
Print (DBG_READ_TRACE, ("ReadComplete: Enter."));
|
|
|
|
//
|
|
// Obtain the current status of the IRP.
|
|
//
|
|
status = Irp->IoStatus.Status;
|
|
|
|
//
|
|
// Get a pointer to the device extension.
|
|
//
|
|
hid = Data->HidExtension;
|
|
|
|
//
|
|
// If ReadInterlock is == START_READ, this func has been completed
|
|
// synchronously. Place IMMEDIATE_READ into the interlock to signify this
|
|
// situation; this will notify StartRead to loop when IoCallDriver returns.
|
|
// Otherwise, we have been completed async and it is safe to call StartRead()
|
|
//
|
|
startRead =
|
|
(MOUHID_START_READ !=
|
|
InterlockedCompareExchange(&Data->ReadInterlock,
|
|
MOUHID_IMMEDIATE_READ,
|
|
MOUHID_START_READ));
|
|
|
|
if (Data->EnableCount == 0) {
|
|
goto SetEventAndBreak;
|
|
}
|
|
|
|
//
|
|
// Determine if the IRP request was successful.
|
|
//
|
|
switch (status) {
|
|
case STATUS_SUCCESS:
|
|
//
|
|
// The buffer of the context now contains a single HID packet read
|
|
// from the device. Verify this.
|
|
//
|
|
ASSERT (Irp->IoStatus.Information == hid->Caps.InputReportByteLength);
|
|
|
|
//
|
|
// Clear previous button state (data / flags).
|
|
//
|
|
Data->InputData.ButtonData = 0;
|
|
Data->InputData.ButtonFlags = 0;
|
|
|
|
//
|
|
// Clear last X,Y motion, in case a call to Hidp_GetUsageValue or
|
|
// Hidp_GetScaledUsageValue fails.
|
|
//
|
|
Data->InputData.LastX = 0;
|
|
Data->InputData.LastY = 0;
|
|
|
|
//
|
|
// Obtain the current button usages.
|
|
//
|
|
numUsages = hid->MaxUsages;
|
|
|
|
if (NT_SUCCESS(HidP_GetUsages (
|
|
HidP_Input,
|
|
HID_USAGE_PAGE_BUTTON,
|
|
0, // link collection irrelevant
|
|
hid->CurrentUsageList,
|
|
&numUsages, // max usages in, num usages out
|
|
hid->Ppd,
|
|
hid->InputBuffer,
|
|
hid->Caps.InputReportByteLength))) {
|
|
//
|
|
// Determine the differences between the current and the previous
|
|
// usages. The very first previous usage list buffer is properly
|
|
// initialized at creation (all zeros).
|
|
//
|
|
if (NT_SUCCESS(HidP_UsageListDifference (hid->PreviousUsageList,
|
|
hid->CurrentUsageList,
|
|
hid->BreakUsageList,
|
|
hid->MakeUsageList,
|
|
hid->MaxUsages))) {
|
|
//
|
|
// Determine which buttons went down and set the appropriate
|
|
// flags in the mouse report.
|
|
//
|
|
usageList = hid->MakeUsageList;
|
|
for ( i = 0;
|
|
i < hid->MaxUsages && *usageList;
|
|
i++, usageList++ ) {
|
|
|
|
if (*usageList <= MAX_MOUSE_BUTTONS) {
|
|
Data->InputData.ButtonFlags |=
|
|
HidP_TranslateUsageToDownFlag[*usageList];
|
|
}
|
|
//
|
|
// else there are more buttons on this mouse then we have
|
|
// translation flags for the Raw input user thread
|
|
//
|
|
}
|
|
|
|
//
|
|
// Determine which buttons went up and set the appropriate
|
|
// flags in the mouse report.
|
|
//
|
|
usageList = hid->BreakUsageList;
|
|
for ( i = 0;
|
|
i < hid->MaxUsages && *usageList;
|
|
i++, usageList++ ) {
|
|
|
|
if (*usageList <= MAX_MOUSE_BUTTONS) {
|
|
Data->InputData.ButtonFlags |=
|
|
HidP_TranslateUsageToUpFlag[*usageList];
|
|
}
|
|
}
|
|
|
|
//
|
|
// Swap the previous usage list pointer with the current.
|
|
//
|
|
usageList = hid->PreviousUsageList;
|
|
hid->PreviousUsageList = hid->CurrentUsageList;
|
|
hid->CurrentUsageList = usageList;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Type of processing for X,Y,Z values depends on whether these values
|
|
// have a bad physical minimum or maximum. If they do, we use routines
|
|
// that do not depend on physical min/max.
|
|
//
|
|
|
|
//
|
|
// Determine the current X position and save it in the mouse report.
|
|
//
|
|
if (!(Data->ProblemFlags & PROBLEM_BAD_PHYSICAL_MIN_MAX_X)) {
|
|
status = HidP_GetScaledUsageValue(
|
|
HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_X,
|
|
&Data->InputData.LastX,
|
|
hid->Ppd,
|
|
hid->InputBuffer,
|
|
hid->Caps.InputReportByteLength);
|
|
|
|
//
|
|
// Bad physical minimum/maximum detected, set flag so that we
|
|
// process usage value differently in the future.
|
|
//
|
|
if (status == HIDP_STATUS_BAD_LOG_PHY_VALUES) {
|
|
Data->ProblemFlags |= PROBLEM_BAD_PHYSICAL_MIN_MAX_X;
|
|
updateProblemFlags = TRUE;
|
|
//
|
|
// Correct the MaxX value;
|
|
//
|
|
hid->MaxX = (1 << (hid->BitSize.X - 1)) - 1;
|
|
}
|
|
}
|
|
|
|
if (Data->ProblemFlags & PROBLEM_BAD_PHYSICAL_MIN_MAX_X) {
|
|
|
|
axisMotion = 0;
|
|
|
|
HidP_GetUsageValue(HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_X,
|
|
(PULONG) &axisMotion,
|
|
hid->Ppd,
|
|
hid->InputBuffer,
|
|
hid->Caps.InputReportByteLength);
|
|
|
|
// Sign extend the value manually.
|
|
Data->InputData.LastX
|
|
= axisMotion | ((axisMotion & (hid->MaxX + 1)) ? (~hid->MaxX)
|
|
: 0);
|
|
}
|
|
|
|
if (hid->IsAbsolute) {
|
|
//
|
|
// We need to scale this value from the physical max
|
|
//
|
|
scratch = ((LONGLONG)(Data->InputData.LastX) *
|
|
MOUHID_RIUT_ABSOLUTE_POINTER_MAX) /
|
|
hid->MaxX;
|
|
Data->InputData.LastX = (LONG) scratch;
|
|
}
|
|
|
|
//
|
|
// Determine the current Y position and save it in the mouse report.
|
|
//
|
|
if (!(Data->ProblemFlags & PROBLEM_BAD_PHYSICAL_MIN_MAX_Y)) {
|
|
status = HidP_GetScaledUsageValue(
|
|
HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_Y,
|
|
&Data->InputData.LastY,
|
|
hid->Ppd,
|
|
hid->InputBuffer,
|
|
hid->Caps.InputReportByteLength);
|
|
//
|
|
// Bad physical minimum/maximum detected, set flag so that we
|
|
// process usage value differently in the future.
|
|
//
|
|
if (status == HIDP_STATUS_BAD_LOG_PHY_VALUES) {
|
|
Data->ProblemFlags |= PROBLEM_BAD_PHYSICAL_MIN_MAX_Y;
|
|
updateProblemFlags = TRUE;
|
|
//
|
|
// Correct the MaxY value;
|
|
//
|
|
hid->MaxY = (1 << (hid->BitSize.Y - 1)) - 1;
|
|
}
|
|
}
|
|
|
|
if (Data->ProblemFlags & PROBLEM_BAD_PHYSICAL_MIN_MAX_Y) {
|
|
|
|
axisMotion = 0;
|
|
|
|
HidP_GetUsageValue(HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_Y,
|
|
&axisMotion,
|
|
hid->Ppd,
|
|
hid->InputBuffer,
|
|
hid->Caps.InputReportByteLength);
|
|
|
|
// Sign extend the value manually.
|
|
Data->InputData.LastY
|
|
= axisMotion | ((axisMotion & (hid->MaxY + 1)) ? (~hid->MaxY)
|
|
: 0);
|
|
}
|
|
|
|
if (hid->IsAbsolute) {
|
|
//
|
|
// We need to scale this value from the physical max
|
|
//
|
|
scratch = ((LONGLONG)(Data->InputData.LastY) *
|
|
MOUHID_RIUT_ABSOLUTE_POINTER_MAX) /
|
|
hid->MaxY;
|
|
|
|
Data->InputData.LastY = (LONG) scratch;
|
|
}
|
|
|
|
//
|
|
// Determine the current Z position (wheel).
|
|
//
|
|
if (FALSE == hid->HasNoWheelUsage) {
|
|
|
|
axisMotion = 0;
|
|
|
|
if (!(Data->ProblemFlags & PROBLEM_BAD_PHYSICAL_MIN_MAX_Z)) {
|
|
status = HidP_GetScaledUsageValue(
|
|
HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_WHEEL,
|
|
&axisMotion,
|
|
hid->Ppd,
|
|
hid->InputBuffer,
|
|
hid->Caps.InputReportByteLength);
|
|
|
|
//
|
|
// If wheel usage not detected, set flag so that we do not
|
|
// process wheel usages in the future.
|
|
//
|
|
if (HIDP_STATUS_USAGE_NOT_FOUND == status) {
|
|
hid->HasNoWheelUsage = TRUE;
|
|
}
|
|
|
|
//
|
|
// If bad physical minimum/maximum detected, set flag so that
|
|
// we process usage value differently in the future.
|
|
//
|
|
if (status == HIDP_STATUS_BAD_LOG_PHY_VALUES) {
|
|
Data->ProblemFlags |= PROBLEM_BAD_PHYSICAL_MIN_MAX_Z;
|
|
updateProblemFlags = TRUE;
|
|
}
|
|
}
|
|
|
|
if (Data->ProblemFlags & PROBLEM_BAD_PHYSICAL_MIN_MAX_Z) {
|
|
HidP_GetUsageValue(HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_WHEEL,
|
|
&axisMotion,
|
|
hid->Ppd,
|
|
hid->InputBuffer,
|
|
hid->Caps.InputReportByteLength);
|
|
|
|
// Sign extend the value manually.
|
|
axisMotion
|
|
= axisMotion
|
|
| (axisMotion & (1 << (hid->BitSize.Z - 1))
|
|
? (0L - (1 << (hid->BitSize.Z - 1)))
|
|
: 0);
|
|
}
|
|
|
|
//
|
|
// Encode the Z position information into the MOUSE_INPUT_DATA
|
|
// structure same way that the Magellan wheel mouse does.
|
|
//
|
|
if (0 == axisMotion) {
|
|
Data->InputData.ButtonData = 0;
|
|
} else {
|
|
|
|
//
|
|
// Unlike PS/2 wheel mice, we don't need to sign flip the wheel
|
|
// data (unless it is an early prototype non spec compliant
|
|
// device)
|
|
//
|
|
axisMotion *= Data->WheelScalingFactor;
|
|
Data->InputData.ButtonData = Data->FlipFlop ?
|
|
(USHORT) -axisMotion : (USHORT) axisMotion;
|
|
Data->InputData.ButtonFlags |= MOUSE_WHEEL;
|
|
}
|
|
|
|
} else if (FALSE == hid->HasNoZUsage) {
|
|
//
|
|
// If there is no Wheel usage then there might be a "z" usage on
|
|
// this mouse. Check that.
|
|
//
|
|
|
|
axisMotion = 0;
|
|
|
|
if (!(Data->ProblemFlags & PROBLEM_BAD_PHYSICAL_MIN_MAX_Z)) {
|
|
status = HidP_GetScaledUsageValue(
|
|
HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_Z,
|
|
&axisMotion,
|
|
hid->Ppd,
|
|
hid->InputBuffer,
|
|
hid->Caps.InputReportByteLength);
|
|
|
|
//
|
|
// If wheel usage not detected, set flag so that we do not
|
|
// process wheel usages in the future.
|
|
//
|
|
if (HIDP_STATUS_USAGE_NOT_FOUND == status) {
|
|
hid->HasNoZUsage = TRUE;
|
|
}
|
|
|
|
//
|
|
// If bad physical minimum/maximum detected, set flag so that
|
|
// we process usage value differently in the future.
|
|
//
|
|
if (status == HIDP_STATUS_BAD_LOG_PHY_VALUES) {
|
|
Data->ProblemFlags |= PROBLEM_BAD_PHYSICAL_MIN_MAX_Z;
|
|
updateProblemFlags = TRUE;
|
|
}
|
|
}
|
|
|
|
if (Data->ProblemFlags & PROBLEM_BAD_PHYSICAL_MIN_MAX_Z) {
|
|
HidP_GetUsageValue(HidP_Input,
|
|
HID_USAGE_PAGE_GENERIC,
|
|
0,
|
|
HID_USAGE_GENERIC_Z,
|
|
&axisMotion,
|
|
hid->Ppd,
|
|
hid->InputBuffer,
|
|
hid->Caps.InputReportByteLength);
|
|
|
|
// Sign extend the value manually.
|
|
axisMotion
|
|
= axisMotion
|
|
| (axisMotion & (1 << (hid->BitSize.Z - 1))
|
|
? (0L - (1 << (hid->BitSize.Z - 1)))
|
|
: 0);
|
|
}
|
|
|
|
//
|
|
// Encode the Z position information into the MOUSE_INPUT_DATA
|
|
// structure the same way that the Magellan wheel mouse does.
|
|
//
|
|
if (0 == axisMotion) {
|
|
Data->InputData.ButtonData = 0;
|
|
} else {
|
|
|
|
//
|
|
// Unlike PS/2 wheel mice, we don't need to sign flip the wheel
|
|
// data (unless it is an early prototype non spec compliant
|
|
// device)
|
|
//
|
|
axisMotion *= Data->WheelScalingFactor;
|
|
Data->InputData.ButtonData = Data->FlipFlop ?
|
|
(USHORT) -axisMotion : (USHORT) axisMotion;
|
|
Data->InputData.ButtonFlags |= MOUSE_WHEEL;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Leave the remaining mouse input data fields as they were
|
|
// initialized (on the device's creation). This includes:
|
|
// o UnitID o RawButtons
|
|
// o Flags o ExtraInformation
|
|
//
|
|
// Now send the data up to the mouse class driver via our callback.
|
|
//
|
|
if (Data->EnableCount)
|
|
{
|
|
//
|
|
// Synchronization issue - it's not a big deal if .Enabled is set
|
|
// FALSE after the condition above, but before the callback below,
|
|
// so long as the .MouClassCallback field is not nulled. This is
|
|
// guaranteed since the disconnect IOCTL is not implemented yet.
|
|
//
|
|
// Mouse class callback assumes we are running at DISPATCH level,
|
|
// however this IoCompletion routine can be running <= DISPATCH.
|
|
// Raise the IRQL before calling the callback. [13.1]
|
|
//
|
|
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
|
|
|
|
//
|
|
// Call the callback.
|
|
//
|
|
(*(PSERVICE_CALLBACK_ROUTINE)
|
|
Data->ConnectData.ClassService) (
|
|
Data->ConnectData.ClassDeviceObject,
|
|
&Data->InputData,
|
|
&Data->InputData + 1, // (one data element)
|
|
&inputDataConsumed);
|
|
|
|
//
|
|
// Restore the previous IRQL right away.
|
|
//
|
|
KeLowerIrql(oldIrql);
|
|
|
|
ASSERT (1 == inputDataConsumed);
|
|
}
|
|
|
|
//
|
|
// Update ProblemFlags value in registry and log error on bad physical
|
|
// minimum/maximum.
|
|
//
|
|
if (updateProblemFlags) {
|
|
MouHid_UpdateRegistryProblemFlags (Data);
|
|
|
|
MouHid_LogError(Data->Self->DriverObject,
|
|
MOUHID_INVALID_PHYSICAL_MIN_MAX,
|
|
NULL);
|
|
}
|
|
|
|
//
|
|
// If MouHid_StartRead() fails, it will be handled appropriately
|
|
// in the completion routine. Exit this routine without touching
|
|
// HidDeviceContext.
|
|
//
|
|
|
|
break;
|
|
|
|
case STATUS_PRIVILEGE_NOT_HELD:
|
|
//
|
|
// The create didn't succeed
|
|
//
|
|
case STATUS_CANCELLED:
|
|
//
|
|
// The read IRP was cancelled. Do not send any more read IRPs.
|
|
//
|
|
|
|
case STATUS_DELETE_PENDING:
|
|
case STATUS_DEVICE_NOT_CONNECTED:
|
|
//
|
|
// The HID class device object is being deleted. We will soon
|
|
// receive Plug 'n Play notification of this device's removal,
|
|
// if we have not received it already.
|
|
//
|
|
SetEventAndBreak:
|
|
KeSetEvent (&Data->ReadCompleteEvent, 0, FALSE);
|
|
IoReleaseRemoveLock (&Data->RemoveLock, Data->ReadIrp);
|
|
startRead = FALSE;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// We don't expect any other error codes.
|
|
//
|
|
TRAP();
|
|
|
|
}
|
|
|
|
//
|
|
// Initiate the next read request to the HID class driver.
|
|
//
|
|
if (startRead) {
|
|
Print(DBG_READ_TRACE, ("calling StartRead directly\n"));
|
|
MouHid_StartRead (Data);
|
|
} else {
|
|
Print(DBG_READ_TRACE, ("StartRead will loop\n"));
|
|
}
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MouHid_StartRead (
|
|
IN PDEVICE_EXTENSION Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initiates a read to the HID class driver.
|
|
|
|
Note that the routine does not verify that the device context is in the
|
|
OperationPending state, but simply assumes it.
|
|
|
|
Note the IoCount must be incremented before entering into this read loop.
|
|
|
|
Arguments:
|
|
|
|
HidDeviceContext - Device context structure describing the HID device.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS result code from IoCallDriver().
|
|
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION stack;
|
|
PHID_EXTENSION hid;
|
|
LONG oldInterlock;
|
|
|
|
Print (DBG_READ_TRACE, ("Start Read: Ente\n"));
|
|
|
|
hid = Data->HidExtension;
|
|
|
|
//
|
|
// start this read.
|
|
//
|
|
|
|
irp = Data->ReadIrp;
|
|
|
|
while (1) {
|
|
oldInterlock = InterlockedExchange(&Data->ReadInterlock,
|
|
MOUHID_START_READ);
|
|
|
|
//
|
|
// END_READ should be the only value here!!! If not, the state machine
|
|
// of the interlock has been broken
|
|
//
|
|
ASSERT(oldInterlock == MOUHID_END_READ);
|
|
|
|
//
|
|
// Set the stack location for the Hid stack.
|
|
// Remember to get the file pointer correct.
|
|
// NOTE: we do not have any of the cool thread stuff set.
|
|
// therefore we need to make sure that we cut this IRP off
|
|
// at the knees when it returns. (STATUS_MORE_PROCESSING_REQUIRED)
|
|
//
|
|
// Note also that Hid class does direct IO.
|
|
//
|
|
|
|
IoReuseIrp (irp, STATUS_SUCCESS);
|
|
|
|
irp->MdlAddress = hid->InputMdl;
|
|
|
|
ASSERT (NULL != Data->ReadFile);
|
|
|
|
stack = IoGetNextIrpStackLocation (irp);
|
|
stack->Parameters.Read.Length = hid->Caps.InputReportByteLength;
|
|
stack->Parameters.Read.Key = 0;
|
|
stack->Parameters.Read.ByteOffset.QuadPart = 0;
|
|
stack->MajorFunction = IRP_MJ_READ;
|
|
stack->FileObject = Data->ReadFile;
|
|
|
|
//
|
|
// Hook a completion routine for when the device completes.
|
|
//
|
|
IoSetCompletionRoutine (irp,
|
|
MouHid_ReadComplete,
|
|
Data,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
//
|
|
// Unset the fact that the read has been sent. Synchoronizing
|
|
// with remove and close code. Remove portion (data->Shuttingdown)
|
|
// only really relevant on 9X.
|
|
//
|
|
KeResetEvent(&Data->ReadSentEvent);
|
|
|
|
if (!Data->EnableCount || Data->ShuttingDown) {
|
|
IoReleaseRemoveLock (&Data->RemoveLock, Data->ReadIrp);
|
|
status = Data->ShuttingDown ? STATUS_DELETE_PENDING : STATUS_UNSUCCESSFUL;
|
|
KeSetEvent (&Data->ReadSentEvent, 0, FALSE);
|
|
break;
|
|
} else {
|
|
status = IoCallDriver (Data->TopOfStack, irp);
|
|
}
|
|
KeSetEvent (&Data->ReadSentEvent, 0, FALSE);
|
|
|
|
if (MOUHID_IMMEDIATE_READ != InterlockedExchange(&Data->ReadInterlock,
|
|
MOUHID_END_READ)) {
|
|
//
|
|
// The read is asynch, will call SerialMouseStartRead from the
|
|
// completion routine
|
|
//
|
|
Print(DBG_READ_TRACE, ("read is pending\n"));
|
|
break;
|
|
} else {
|
|
//
|
|
// The read was synchronous (probably bytes in the buffer). The
|
|
// completion routine will not call SerialMouseStartRead, so we
|
|
// just loop here. This is to prevent us from running out of stack
|
|
// space if always call StartRead from the completion routine
|
|
//
|
|
Print(DBG_READ_TRACE, ("read is looping\n"));
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|