729 lines
22 KiB
C++
729 lines
22 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
input.c
|
|
|
|
Abstract:
|
|
|
|
Implementation of the Input API
|
|
|
|
|
|
Environment:
|
|
|
|
Designed for XBOX.
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
03-07-00 created by Mitchell Dernis (mitchd)
|
|
12-06-00 changed synchronization scheme
|
|
--*/
|
|
|
|
//
|
|
// Pull in OS headers
|
|
//
|
|
#define _XAPI_
|
|
#define _KERNEL32_ //since we are linked to XAPI for now.
|
|
extern "C" {
|
|
#include <ntos.h>
|
|
}
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <xtl.h>
|
|
#include <xboxp.h>
|
|
#include <xapidrv.h>
|
|
#include <xdbg.h>
|
|
#include <stdio.h>
|
|
|
|
//
|
|
// Setup the debug information for this file (see ..\inc\debug.h)
|
|
//
|
|
#define MODULE_POOL_TAG '_DIX'
|
|
#include <debug.h>
|
|
DEFINE_USB_DEBUG_FUNCTIONS("INPUT");
|
|
|
|
//
|
|
// Pull in public usb headers
|
|
//
|
|
#include <usb.h>
|
|
|
|
//
|
|
// Pull in xid headers
|
|
//
|
|
#include "xid.h"
|
|
|
|
//--------------------------------------------------------------
|
|
// Handle Verification
|
|
//--------------------------------------------------------------
|
|
#if DBG //Debug version verifies handles.
|
|
#define XID_VERIFY_HANDLES
|
|
#endif
|
|
#ifdef XID_VERIFY_HANDLES
|
|
|
|
PXID_OPEN_DEVICE XID_OpenDeviceList = NULL;
|
|
VOID XidInsertHandle(PXID_OPEN_DEVICE OpenDevice);
|
|
VOID XidRemoveHandle(PXID_OPEN_DEVICE OpenDevice);
|
|
VOID XidCheckHandle(PCHAR ApiName, PXID_OPEN_DEVICE OpenDevice);
|
|
|
|
#define XID_INSERT_HANDLE(OpenDevice) XidInsertHandle(OpenDevice)
|
|
#define XID_REMOVE_HANDLE(OpenDevice) XidRemoveHandle(OpenDevice)
|
|
#define XID_CHECK_HANDLE(ApiName, OpenDevice) XidCheckHandle(ApiName, OpenDevice)
|
|
|
|
#else
|
|
|
|
#define XID_INSERT_HANDLE(OpenDevice) do{}while(0)
|
|
#define XID_REMOVE_HANDLE(OpenDevice) do{}while(0)
|
|
#define XID_CHECK_HANDLE(ApiName,OpenDevice) do{}while(0)
|
|
|
|
#endif
|
|
|
|
//--------------------------------------------------------------
|
|
// Implementation
|
|
//--------------------------------------------------------------
|
|
XBOXAPI
|
|
HANDLE
|
|
WINAPI
|
|
XInputOpen(
|
|
IN PXPP_DEVICE_TYPE XppDeviceType,
|
|
IN DWORD dwPort,
|
|
IN DWORD dwSlot,
|
|
IN PXINPUT_POLLING_PARAMETERS pPollingParameters OPTIONAL
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Public API to open a handle to an input device.
|
|
|
|
Arguments:
|
|
XppDeviceType - device type to open.
|
|
dwPort - Port of device to open.
|
|
dwSlot - Slot of device to open.
|
|
pPollingParameters - [optional] polling parameters to use with device.
|
|
|
|
Return Value:
|
|
On success, handle to be used to access device.
|
|
On failure, NULL. Call GetLastError for specific error code.
|
|
|
|
ERROR_SHARING_VIOLATION - attempt to open more than one handle to a single device.
|
|
ERROR_OUTOFMEMORY - there was not enough memory to open the handle.
|
|
ERROR_INVALID_PARAMETER - the device type was not known.
|
|
ERROR_DEVICE_NOT_CONNECTED - a device was not found of the given type in the specified
|
|
port and slot.
|
|
ERROR_IO_DEVICE - an error occured talking to the device.
|
|
|
|
--*/
|
|
{
|
|
DWORD errorCode;
|
|
PXID_OPEN_DEVICE openDevice = NULL;
|
|
|
|
ASSERT_LESS_THAN_DISPATCH_LEVEL();
|
|
|
|
RIP_ON_NOT_TRUE_WITH_MESSAGE(XPP_XInitDevicesHasBeenCalled, "XInputOpen: XInitDevices must be called first!");
|
|
|
|
XID_TYPE_INFORMATION *typeInformation = GetTypeInformation(XppDeviceType);
|
|
|
|
if(!typeInformation)
|
|
{
|
|
RIP("XInputOpen: XppDeviceType is not a valid type for the XInputXXX API\n");
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// RIP port and slot parameters
|
|
//
|
|
RIP_ON_NOT_TRUE(XInputOpen, dwPort<XGetPortCount());
|
|
|
|
// At this time all XID devices are only direct connect, so this RIP applies.
|
|
// In the future, we may want to add a slot type parameter to the type table.
|
|
RIP_ON_NOT_TRUE(XInputOpen, (dwSlot == XDEVICE_NO_SLOT));
|
|
|
|
//
|
|
// If the polling parameters are NULL, look up the defaults based on type.
|
|
//
|
|
if(NULL == pPollingParameters)
|
|
{
|
|
pPollingParameters = typeInformation->DefaultPollingParameters;
|
|
}
|
|
|
|
//
|
|
// Open the device
|
|
//
|
|
errorCode = XID_fOpenDevice(
|
|
typeInformation,
|
|
(dwSlot != XDEVICE_BOTTOM_SLOT) ? dwPort : dwPort +16,
|
|
&openDevice,
|
|
pPollingParameters
|
|
);
|
|
|
|
//
|
|
// If the open failed, set the error code.
|
|
//
|
|
if(NULL==openDevice)
|
|
{
|
|
SetLastError(errorCode);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Insert the handle into the list of
|
|
// valid handles.
|
|
//
|
|
XID_INSERT_HANDLE(openDevice);
|
|
}
|
|
return (HANDLE)openDevice;
|
|
}
|
|
|
|
XBOXAPI
|
|
void
|
|
WINAPI
|
|
XInputClose(
|
|
IN HANDLE hDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Public API to close a handle to an input device.
|
|
|
|
Arguments:
|
|
XppDeviceType - device type to open.
|
|
dwPort - Port of device to open.
|
|
dwSlot - Slot of device to open.
|
|
pPollingParameters - [optional] polling parameters to use with device.
|
|
|
|
Return Value:
|
|
None
|
|
Remarks:
|
|
Close can block for several milliseconds while resources are being cleaned up.
|
|
|
|
It is the callers responsibility not to use a handle after XInputClose has been
|
|
called. It is particularly risky with multiple threads.
|
|
* No other call to an XInputXXX API using the handle should be started after
|
|
XInputClose has been called, even if XInputClose has not yet returned.
|
|
* XInputClose must not be called until all other XInputXXX API's using the handle
|
|
have returned.
|
|
In debug builds, an attempt is made to detect these conditions and RIP, however, the
|
|
RIP's are not full-proof, and under some circumstances, may miss such a condition.
|
|
If these rules are violated the result is undefined, in many cases this will lead to
|
|
memory corruption and system crash.
|
|
|
|
One should normally wait for asynchronous I/O (started with XInputSetState) to complete
|
|
before calling XInputClose, however, it is not an error to call XInputClose with
|
|
asynchronous I/O pending. The result is that pending I/O is guaranteed to complete,
|
|
usually with status set to ERROR_CANCELLED, before XInputClose returns.
|
|
|
|
--*/
|
|
{
|
|
PXID_OPEN_DEVICE openDevice = (PXID_OPEN_DEVICE)hDevice;
|
|
ASSERT_LESS_THAN_DISPATCH_LEVEL();
|
|
XID_REMOVE_HANDLE(openDevice);
|
|
XID_fCloseDevice(openDevice);
|
|
return;
|
|
}
|
|
|
|
XBOXAPI
|
|
DWORD
|
|
WINAPI
|
|
XInputGetCapabilities(
|
|
IN HANDLE hDevice,
|
|
OUT PXINPUT_CAPABILITIES pCapabilities
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Public API to retrieve capabilities from a device.
|
|
Arguments:
|
|
hDevice - handle to device for which to get capabilities.
|
|
pCapabilities - pointer to buffer to get capabilities.
|
|
Return Value:
|
|
ERROR_SUCCESS - on success.
|
|
ERROR_DEVICE_NOT_CONNECTED - if the device is no longer connected.
|
|
ERROR_IO_DEVICE - problem communicating with the device.
|
|
Remarks:
|
|
This routine blocks while the device is queried. This can take
|
|
a few milliseconds.
|
|
--*/
|
|
{
|
|
PCHAR pReportBuffer;
|
|
ULONG length;
|
|
URB_CONTROL_TRANSFER urb;
|
|
KEVENT event;
|
|
KIRQL oldIrql;
|
|
PXID_DEVICE_NODE xidNode;
|
|
DWORD errorCode = ERROR_SUCCESS;
|
|
PXID_OPEN_DEVICE openDevice = (PXID_OPEN_DEVICE)hDevice;
|
|
|
|
ASSERT_LESS_THAN_DISPATCH_LEVEL();
|
|
|
|
//
|
|
// Raise Irql for synchronization
|
|
//
|
|
oldIrql = KeRaiseIrqlToDpcLevel();
|
|
|
|
//
|
|
// Verify handle.
|
|
//
|
|
XID_CHECK_HANDLE("XInputGetCapabilities", openDevice);
|
|
|
|
//
|
|
// Make sure device is connected
|
|
//
|
|
xidNode = openDevice->XidNode;
|
|
if( NULL == xidNode || xidNode->PendingRemove)
|
|
{
|
|
errorCode = ERROR_DEVICE_NOT_CONNECTED;
|
|
goto exit_input_get_caps;
|
|
}
|
|
|
|
//
|
|
// Zero the whole output buffer
|
|
//
|
|
RtlZeroMemory(pCapabilities, sizeof(XINPUT_CAPABILITIES));
|
|
|
|
//
|
|
// Fill in the subtype, that doesn't depend on the report being queried
|
|
// so even if this fails with invalid parameter, we can check it.
|
|
//
|
|
pCapabilities->SubType = xidNode->SubType;
|
|
|
|
//
|
|
// Make sure that the device supports GET_CAPABILITIES.
|
|
// This check is primarily for legacy devices, in particular
|
|
// legacy keyboards.
|
|
//
|
|
if(xidNode->TypeInformation->ulFlags&XID_BSF_NO_CAPABILITIES)
|
|
{
|
|
errorCode = ERROR_ACCESS_DENIED;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Get the output portion
|
|
//
|
|
pReportBuffer = (PCHAR)&pCapabilities->Out;
|
|
length = xidNode->TypeInformation->pOutputReportInfoList[0].bCurrentSize;
|
|
|
|
//
|
|
// Build the URB
|
|
//
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
USB_BUILD_CONTROL_TRANSFER(
|
|
&urb,
|
|
NULL,
|
|
(PVOID)(pReportBuffer-2),
|
|
length+2,
|
|
USB_TRANSFER_DIRECTION_IN,
|
|
(PURB_COMPLETE_PROC)XID_SyncComplete,
|
|
&event,
|
|
TRUE,
|
|
USB_DEVICE_TO_HOST | USB_VENDOR_COMMAND | USB_COMMAND_TO_INTERFACE,
|
|
XID_COMMAND_GET_CAPABILITIES,
|
|
0x0200,
|
|
xidNode->InterfaceNumber,
|
|
length+2
|
|
);
|
|
|
|
//
|
|
// Submit the request.
|
|
//
|
|
xidNode->Device->SubmitRequest((PURB)&urb);
|
|
|
|
//
|
|
// Wait for transfer to complete
|
|
//
|
|
KeLowerIrql(oldIrql);
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
oldIrql = KeRaiseIrqlToDpcLevel();
|
|
|
|
//
|
|
// Recheck the handle (should not have been closed)
|
|
//
|
|
XID_CHECK_HANDLE("XInputGetCapabilities", openDevice);
|
|
|
|
//
|
|
// Make sure the device wasn't removed
|
|
// in the interm.
|
|
//
|
|
if( NULL == openDevice->XidNode || xidNode->PendingRemove)
|
|
{
|
|
errorCode = ERROR_DEVICE_NOT_CONNECTED;
|
|
goto exit_input_get_caps;
|
|
}
|
|
|
|
//
|
|
// Check for error
|
|
//
|
|
if(USBD_ERROR(urb.Hdr.Status))
|
|
{
|
|
errorCode = IUsbDevice::Win32FromUsbdStatus(urb.Hdr.Status);
|
|
goto exit_input_get_caps;
|
|
}
|
|
|
|
//
|
|
// Now get the input portion
|
|
//
|
|
pReportBuffer = (PCHAR)&pCapabilities->In;
|
|
length = xidNode->TypeInformation->pInputReportInfoList[0].bCurrentSize;
|
|
|
|
//
|
|
// Build the URB
|
|
//
|
|
USB_BUILD_CONTROL_TRANSFER(
|
|
&urb,
|
|
NULL,
|
|
(PVOID)(pReportBuffer-2),
|
|
length+2,
|
|
USB_TRANSFER_DIRECTION_IN,
|
|
(PURB_COMPLETE_PROC)XID_SyncComplete,
|
|
&event,
|
|
TRUE,
|
|
USB_DEVICE_TO_HOST | USB_VENDOR_COMMAND | USB_COMMAND_TO_INTERFACE,
|
|
XID_COMMAND_GET_CAPABILITIES,
|
|
0x0100,
|
|
xidNode->InterfaceNumber,
|
|
length+2
|
|
);
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
xidNode->Device->SubmitRequest((PURB)&urb);
|
|
|
|
//
|
|
// Wait for transfer to complete
|
|
//
|
|
KeLowerIrql(oldIrql);
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
oldIrql = KeRaiseIrqlToDpcLevel();
|
|
|
|
//
|
|
// Make sure the device wasn't removed
|
|
// in the interm.
|
|
//
|
|
if( NULL == openDevice->XidNode || xidNode->PendingRemove)
|
|
{
|
|
errorCode = ERROR_DEVICE_NOT_CONNECTED;
|
|
goto exit_input_get_caps;
|
|
}
|
|
|
|
//
|
|
// Check for error
|
|
//
|
|
if(USBD_ERROR(urb.Hdr.Status))
|
|
{
|
|
errorCode = IUsbDevice::Win32FromUsbdStatus(urb.Hdr.Status);
|
|
goto exit_input_get_caps;
|
|
}
|
|
}
|
|
|
|
exit_input_get_caps:
|
|
//Bug 2578, make sure nobody tries to falsely divine information
|
|
//from the reserved field.
|
|
pCapabilities->Reserved = 0;
|
|
KeLowerIrql(oldIrql);
|
|
return errorCode;
|
|
}
|
|
|
|
XBOXAPI
|
|
DWORD
|
|
WINAPI
|
|
XInputGetState(
|
|
IN HANDLE hDevice,
|
|
OUT PXINPUT_STATE pState
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Public API for retrieving the latest known state of the
|
|
device. This routine does not actually perform I/O it
|
|
just copies the latest known state into the caller's buffer.
|
|
|
|
|
|
Arguments:
|
|
hDevice - handle of device to get state for.
|
|
pState - buffer to receive state.
|
|
|
|
Return Value:
|
|
ERROR_SUCCESS - on success.
|
|
ERROR_DEVICE_NOT_CONNECTED - device no longer connected (buffer is still copied).
|
|
--*/
|
|
{
|
|
PXID_OPEN_DEVICE openDevice = (PXID_OPEN_DEVICE) hDevice;
|
|
DWORD errorCode = ERROR_SUCCESS;
|
|
KIRQL oldIrql;
|
|
ULONG length;
|
|
|
|
oldIrql = KeRaiseIrqlToDpcLevel();
|
|
|
|
//
|
|
// Verify handle.
|
|
//
|
|
XID_CHECK_HANDLE("XInputGetState", openDevice);
|
|
|
|
//
|
|
// Don't allow keyboards to work
|
|
//
|
|
#ifdef DEBUG_KEYBOARD
|
|
if(XDEVICE_TYPE_DEBUG_KEYBOARD == openDevice->TypeInformation->XppType)
|
|
{
|
|
KeLowerIrql(oldIrql);
|
|
RIP("XInputGetState does not work for keyboards.");
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
#endif //DEBUG_KEYBOARD
|
|
|
|
//
|
|
// If the device is not connected, mark it, but copy the
|
|
// data anyway.
|
|
//
|
|
if(NULL == openDevice->XidNode || openDevice->XidNode->PendingRemove)
|
|
{
|
|
errorCode = ERROR_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// Copy packet number
|
|
//
|
|
pState->dwPacketNumber = openDevice->PacketNumber;
|
|
|
|
//
|
|
// Copy the size indicated in the capatibility table.
|
|
//
|
|
length = openDevice->TypeInformation->pInputReportInfoList[0].bCurrentSize;
|
|
|
|
//
|
|
// Copy the latest report (We are using GameReport, but we could
|
|
// use any member of the union of report types)
|
|
RtlCopyMemory( (PVOID)&pState->Gamepad, (PVOID)openDevice->Report, length);
|
|
|
|
|
|
KeLowerIrql(oldIrql);
|
|
return errorCode;
|
|
}
|
|
|
|
XBOXAPI
|
|
DWORD
|
|
WINAPI
|
|
XInputSetState(
|
|
IN HANDLE hDevice,
|
|
OUT PXINPUT_FEEDBACK pFeedback
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Public API for sending data to the device.
|
|
THIS IS ASYNCHRONOUS!!!
|
|
|
|
Arguments:
|
|
hDevice - handle of device to send data to.
|
|
pFeedback - feedback data to send
|
|
|
|
Return Value:
|
|
ERROR_IO_PENDING - on sucess.
|
|
ERROR_DEVICE_NOT_CONNECTED - the device is no longer connected,
|
|
|
|
Remarks:
|
|
Calling XInputSetState programs output to the device. This output could a few to many
|
|
milliseconds to complete depending on the pPollingParameters passed to XInputOpen.
|
|
During this time XAPI owns pFeedback, the caller should consider it read only.
|
|
|
|
There are two options for synchronization:
|
|
|
|
1) If the caller sets pFeedback->Header.hEvent to a valid event handle, it will
|
|
be signaled when the I/O completes, otherwise hEvent should be NULL.
|
|
2) The caller may poll pFeedback->Header.dwStatus. This will be ERROR_IO_PENDING
|
|
when XInputSetState returns, it will change to ERROR_SUCCESS or another (non-pending)
|
|
error code when the transfer completes, successfully or otherwuse.
|
|
|
|
Calling XInputClose before the I/O complete cancels the I/O. pFeedback->Header.hEvent
|
|
(if a valid event) will be signaled before XInputClose returns,and pFeedback->Header.dwStatus
|
|
will change to ERROR_CANCELLED.
|
|
|
|
--*/
|
|
{
|
|
PXID_OPEN_DEVICE openDevice = (PXID_OPEN_DEVICE) hDevice;
|
|
PXINPUT_FEEDBACK_INTERNAL feedback = (PXINPUT_FEEDBACK_INTERNAL)pFeedback;
|
|
|
|
//
|
|
// Verify handle.
|
|
//
|
|
XID_CHECK_HANDLE("XInputSetState", openDevice);
|
|
|
|
//
|
|
// Don't allow keyboards to work
|
|
//
|
|
#ifdef DEBUG_KEYBOARD
|
|
if(XDEVICE_TYPE_DEBUG_KEYBOARD == openDevice->TypeInformation->XppType)
|
|
{
|
|
RIP("XInputSetState does not work for keyboards.");
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
#endif //DEBUG_KEYBOARD
|
|
|
|
//
|
|
// Check Handle the report ID, before
|
|
// passing down.
|
|
//
|
|
feedback->Internal.bReportId = 0;
|
|
feedback->Internal.bSize = openDevice->TypeInformation->pOutputReportInfoList[0].bCurrentSize + XID_REPORT_HEADER;
|
|
return XID_fSendDeviceReport(openDevice, feedback);
|
|
}
|
|
|
|
|
|
XBOXAPI
|
|
DWORD
|
|
WINAPI
|
|
XInputPoll(
|
|
IN HANDLE hDevice
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Public API for manually polling an input device.
|
|
|
|
Arguments:
|
|
hDevice - handle of device to poll.
|
|
|
|
Return Value:
|
|
ERROR_SUCCESS - on success.
|
|
ERROR_DEVICE_NOT_CONNECTED - if the device is no longer connected.
|
|
|
|
Remarks:
|
|
This API only needs to be called if XInputOpen was called with
|
|
pPollingParameter->fAutoPoll set to FALSE. Otherwise, it is
|
|
a no-op.
|
|
|
|
XInputGetState should be updated to return the latest state of the device
|
|
no later than (pPollingParameter->bInputInterval + 1) ms, after XInputPoll
|
|
is called.
|
|
|
|
--*/
|
|
{
|
|
DWORD errorCode = ERROR_SUCCESS;
|
|
PXID_OPEN_DEVICE openDevice = (PXID_OPEN_DEVICE)hDevice;
|
|
PXID_DEVICE_NODE xidNode;
|
|
KIRQL oldIrql = KeRaiseIrqlToDpcLevel();
|
|
|
|
//
|
|
// Verify handle.
|
|
//
|
|
XID_CHECK_HANDLE("XInputPoll", openDevice);
|
|
|
|
//
|
|
// Make sure device is connected
|
|
//
|
|
xidNode = openDevice->XidNode;
|
|
if(NULL == xidNode || xidNode->PendingRemove)
|
|
{
|
|
errorCode = ERROR_DEVICE_NOT_CONNECTED;
|
|
} else
|
|
{
|
|
if(!openDevice->AutoPoll)
|
|
{
|
|
if(!openDevice->OutstandingPoll)
|
|
{
|
|
openDevice->OutstandingPoll = 1;
|
|
#ifdef ALAMO_RAW_DATA_HACK
|
|
if(xidNode->AlamoHack) XID_AlamoStartPoll(openDevice);
|
|
else {
|
|
#endif
|
|
openDevice->Urb.BulkOrInterruptTransfer.TransferBufferLength =
|
|
openDevice->XidNode->bMaxInputReportSize;
|
|
openDevice->XidNode->Device->SubmitRequest(&openDevice->Urb);
|
|
#ifdef ALAMO_RAW_DATA_HACK
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
KeLowerIrql(oldIrql);
|
|
return errorCode;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// Debug routine that keep track of open handles, and generate
|
|
// RIP's when they are not valid.
|
|
//---------------------------------------------------------------------
|
|
#ifdef XID_VERIFY_HANDLES
|
|
|
|
VOID XidInsertHandle(PXID_OPEN_DEVICE OpenDevice)
|
|
{
|
|
KIRQL oldIrql = KeRaiseIrqlToDpcLevel();
|
|
OpenDevice->NextOpenDevice = XID_OpenDeviceList;
|
|
XID_OpenDeviceList = OpenDevice;
|
|
KeLowerIrql(oldIrql);
|
|
}
|
|
|
|
VOID XidRemoveHandle(PXID_OPEN_DEVICE OpenDevice)
|
|
{
|
|
KIRQL oldIrql = KeRaiseIrqlToDpcLevel();
|
|
PXID_OPEN_DEVICE previousDevice = NULL;
|
|
PXID_OPEN_DEVICE device = XID_OpenDeviceList;
|
|
BOOL found = FALSE;
|
|
while(device)
|
|
{
|
|
if(device == OpenDevice)
|
|
{
|
|
if(previousDevice)
|
|
{
|
|
previousDevice->NextOpenDevice = device->NextOpenDevice;
|
|
} else
|
|
{
|
|
XID_OpenDeviceList = device->NextOpenDevice;
|
|
}
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
previousDevice = device;
|
|
device = device->NextOpenDevice;
|
|
}
|
|
KeLowerIrql(oldIrql);
|
|
|
|
if(!found)
|
|
{
|
|
RIP("XInputClose: Invalid Handle\n");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID XidCheckHandle(CHAR *ApiName, PXID_OPEN_DEVICE OpenDevice)
|
|
{
|
|
KIRQL oldIrql = KeRaiseIrqlToDpcLevel();
|
|
PXID_OPEN_DEVICE device = XID_OpenDeviceList;
|
|
BOOL found = FALSE;
|
|
while(device)
|
|
{
|
|
if(device == OpenDevice)
|
|
{
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
device = device->NextOpenDevice;
|
|
}
|
|
|
|
//
|
|
// BUG 9292 - cannot RIP at DISPATCH_LEVEL. This hangs the machine when debugging
|
|
// with VC. We were lowering IRQL to oldIrql before the RIP, but since
|
|
// this routine is usually called at DISPATCH_LEVEL, this is not good enough.
|
|
// Note that since this routine is NEVER called from a true DPC, it is always
|
|
// possible to explictly lower IRQL to PASSIVE_LEVEL. We only want to do this
|
|
// though when we are going to RIP. In that case, the system is already hosed
|
|
// and we do not lose any sleep over completely hosing it.
|
|
//
|
|
if(!found)
|
|
{
|
|
KeLowerIrql(PASSIVE_LEVEL);
|
|
CHAR buffer[255];
|
|
sprintf(buffer, "%s: Invalid Handle(0x%0.8x)\n", ApiName, OpenDevice);
|
|
RIP(buffer);
|
|
KIRQL dummyIrql;
|
|
KeRaiseIrql(oldIrql, &dummyIrql); // A feeble attempt to keep the system running after the RIP.
|
|
} else
|
|
{
|
|
KeLowerIrql(oldIrql);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#endif //XID_VERIFY_HANDLES
|