284 lines
7.0 KiB
C
284 lines
7.0 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
xpp.c
|
|
|
|
Abstract:
|
|
|
|
Xbox Peripheral Port support
|
|
|
|
The USB stack reports the insertion and removal of all devices here. This module converts the PNP_CLASS_ID
|
|
to the Xbox Device Type and vice versa.
|
|
|
|
The Xbox device type is a simple 0 based index into a table of devices allowing an efficient implementation
|
|
of XGetDevices, XGetDeviceChanges.
|
|
|
|
Environment:
|
|
|
|
XAPI
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
06-26-00 created by Mitchell Dernis (mitchd)
|
|
|
|
--*/
|
|
|
|
#include "basedll.h"
|
|
#pragma warning( push, 4 )
|
|
#pragma warning( disable: 4213)
|
|
#include <usbxapi.h>
|
|
|
|
typedef struct _XPP_DEVICE_TYPE_INTERNAL
|
|
{
|
|
ULONG CurrentConnected;
|
|
ULONG ChangeConnected;
|
|
ULONG PreviousConnected;
|
|
} XPP_DEVICE_TYPE_INTERNAL, *PXPP_DEVICE_TYPE_INTERNAL;
|
|
|
|
BOOL XPP_XInitDevicesHasBeenCalled = FALSE;
|
|
|
|
VOID
|
|
XdReportDeviceInsertionRemoval(
|
|
PXPP_DEVICE_TYPE XppDeviceType,
|
|
ULONG PortBit,
|
|
BOOLEAN fInserted
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
Called by the USB stack to report the insertion and removal of devices.
|
|
Keeps the XPP_GlobalDeviceTable up-to-date.
|
|
|
|
Comments:
|
|
This routine is called at DPC level
|
|
|
|
Parameters:
|
|
XppDeviceType - Pointer to XPP type.
|
|
PortBit - Port bit position in bitmap.
|
|
fInserted - TRUE on device insertion, FALSE on removal.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwPortMask = 1 << PortBit;
|
|
PXPP_DEVICE_TYPE_INTERNAL pXppTypeInternal =
|
|
(PXPP_DEVICE_TYPE_INTERNAL) XppDeviceType;
|
|
ASSERT(sizeof(PXPP_DEVICE_TYPE_INTERNAL)==sizeof(PXPP_DEVICE_TYPE));
|
|
|
|
//
|
|
// Set the change flag
|
|
//
|
|
pXppTypeInternal->ChangeConnected |=dwPortMask;
|
|
//
|
|
// Set or clear the CurrentConnected bit
|
|
//
|
|
if(fInserted)
|
|
{
|
|
pXppTypeInternal->CurrentConnected |= dwPortMask;
|
|
} else
|
|
{
|
|
pXppTypeInternal->CurrentConnected &= ~dwPortMask;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
// Internal API
|
|
//------------------------------------------------------------------
|
|
DWORD
|
|
WINAPI
|
|
XPeekDevices(
|
|
IN PXPP_DEVICE_TYPE DeviceType,
|
|
IN OUT PDWORD pLastGotten,
|
|
IN OUT PDWORD pStale
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This is an internal routine which can be used to determine which devices are connected.
|
|
It is designed not to interfere with the game which calles XGetDevices and XGetDeviceChanges.
|
|
It also allows the caller to track what the game knows about.
|
|
Arguments:
|
|
DeviceType - the device for which information is requested.
|
|
pLastGotten - If non-NULL, filled out on exit with a bitmap of connected devices
|
|
as seen by the game.
|
|
pState - If non-NULL, filled out on exit with a bitmap of devices which have
|
|
been removed and reinserted since the last time the game called
|
|
XGetDevices or XGetDeviceChanges.
|
|
--*/
|
|
{
|
|
KIRQL oldIrql;
|
|
DWORD dwRetVal;
|
|
PXPP_DEVICE_TYPE_INTERNAL pXppTypeInternal =
|
|
(PXPP_DEVICE_TYPE_INTERNAL) DeviceType;
|
|
|
|
RIP_ON_NOT_TRUE_WITH_MESSAGE(XPP_XInitDevicesHasBeenCalled, "XGetDevices: XInitDevices must be called first!");
|
|
|
|
//
|
|
// Raise to DPC for sync.
|
|
//
|
|
oldIrql = KeRaiseIrqlToDpcLevel();
|
|
|
|
//
|
|
// Return all devices
|
|
//
|
|
dwRetVal = pXppTypeInternal->CurrentConnected;
|
|
|
|
//
|
|
// Fill out *pLastGotten.
|
|
//
|
|
if(pLastGotten)
|
|
{
|
|
*pLastGotten = pXppTypeInternal->PreviousConnected;
|
|
}
|
|
|
|
//
|
|
// Fill out *pStale.
|
|
//
|
|
if(pStale)
|
|
{
|
|
*pStale = pXppTypeInternal->CurrentConnected &
|
|
pXppTypeInternal->PreviousConnected &
|
|
pXppTypeInternal->ChangeConnected;
|
|
}
|
|
|
|
//
|
|
// Done with syncronization.
|
|
//
|
|
KeLowerIrql(oldIrql);
|
|
return dwRetVal;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------
|
|
// Public API
|
|
//------------------------------------------------------------------
|
|
|
|
VOID
|
|
WINAPI
|
|
XInitDevices(DWORD NumDeviceTypes, PXDEVICE_PREALLOC_TYPE DeviceTypes)
|
|
{
|
|
#if DBG
|
|
if(XPP_XInitDevicesHasBeenCalled)
|
|
{
|
|
RIP("XInitDevices() is called more than once. Fatal Error.");
|
|
}
|
|
else
|
|
{
|
|
XPP_XInitDevicesHasBeenCalled = TRUE;
|
|
}
|
|
#endif
|
|
|
|
USBD_Init(NumDeviceTypes, DeviceTypes);
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
XGetDevices(
|
|
IN PXPP_DEVICE_TYPE DeviceType
|
|
)
|
|
{
|
|
KIRQL oldIrql;
|
|
DWORD dwRetVal;
|
|
PXPP_DEVICE_TYPE_INTERNAL pXppTypeInternal =
|
|
(PXPP_DEVICE_TYPE_INTERNAL) DeviceType;
|
|
|
|
RIP_ON_NOT_TRUE_WITH_MESSAGE(XPP_XInitDevicesHasBeenCalled, "XGetDevices: XInitDevices must be called first!");
|
|
|
|
//
|
|
// Raise to DPC for sync.
|
|
//
|
|
oldIrql = KeRaiseIrqlToDpcLevel();
|
|
//
|
|
// Fill in insertion bitmap with all devices
|
|
//
|
|
dwRetVal = pXppTypeInternal->CurrentConnected;
|
|
//
|
|
// Erase changed and reset previous
|
|
//
|
|
pXppTypeInternal->ChangeConnected = 0;
|
|
pXppTypeInternal->PreviousConnected = pXppTypeInternal->CurrentConnected;
|
|
|
|
//
|
|
// Done with syncronization.
|
|
//
|
|
KeLowerIrql(oldIrql);
|
|
return dwRetVal;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
XGetDeviceChanges(
|
|
IN IN PXPP_DEVICE_TYPE DeviceType,
|
|
OUT PDWORD pInsertions,
|
|
OUT PDWORD pRemovals
|
|
)
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
PXPP_DEVICE_TYPE_INTERNAL pXppTypeInternal =
|
|
(PXPP_DEVICE_TYPE_INTERNAL) DeviceType;
|
|
|
|
RIP_ON_NOT_TRUE_WITH_MESSAGE(XPP_XInitDevicesHasBeenCalled, "XGetDeviceChanges: XInitDevices must be called first!");
|
|
|
|
if(!pXppTypeInternal->ChangeConnected)
|
|
{
|
|
//
|
|
// Nothing has changed since the last call. Get out quickly.
|
|
//
|
|
*pInsertions = 0;
|
|
*pRemovals = 0;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Something has changed, so calculate the full info.
|
|
//
|
|
|
|
ULONG RemoveInsert;
|
|
|
|
//
|
|
// Raise to DPC for sync.
|
|
//
|
|
|
|
oldIrql = KeRaiseIrqlToDpcLevel();
|
|
|
|
//
|
|
// Construct the simple case of add or remove.
|
|
//
|
|
|
|
*pInsertions = (pXppTypeInternal->CurrentConnected & ~pXppTypeInternal->PreviousConnected);
|
|
*pRemovals = (pXppTypeInternal->PreviousConnected & ~pXppTypeInternal->CurrentConnected);
|
|
|
|
//
|
|
// Now add more insertions and removals for the case of remove and reinsert
|
|
//
|
|
|
|
RemoveInsert = pXppTypeInternal->ChangeConnected &
|
|
pXppTypeInternal->CurrentConnected &
|
|
pXppTypeInternal->PreviousConnected;
|
|
*pRemovals |= RemoveInsert;
|
|
*pInsertions |= RemoveInsert;
|
|
|
|
//
|
|
// Record that we retrieved info
|
|
//
|
|
|
|
pXppTypeInternal->ChangeConnected = 0;
|
|
pXppTypeInternal->PreviousConnected = pXppTypeInternal->CurrentConnected;
|
|
|
|
//
|
|
// Done with syncronization.
|
|
//
|
|
|
|
KeLowerIrql(oldIrql);
|
|
return (*pInsertions|*pRemovals) ? TRUE : FALSE;
|
|
}
|
|
}
|
|
|