📄 hidjoy.c
字号:
/*++
Copyright (c) 1998 - 1999 Microsoft Corporation
Module Name:
pnp.c
Abstract: This module contains routines Generate the HID report and
configure the joystick.
Environment:
Kernel mode
--*/
#include "hidgame.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, HGM_DriverInit)
#pragma alloc_text (PAGE, HGM_SetupButtons)
#pragma alloc_text (PAGE, HGM_MapAxesFromDevExt)
#pragma alloc_text (PAGE, HGM_GenerateReport)
#pragma alloc_text (PAGE, HGM_JoystickConfig)
#pragma alloc_text (PAGE, HGM_InitAnalog)
/* Sample only functions */
#ifdef CHANGE_DEVICE
#pragma alloc_text (PAGE, HGM_ChangeHandler)
#pragma alloc_text (PAGE, HGM_DeviceChanged)
#endif /* CHANGE_DEVICE */
#endif
/*
* A few look up tables to translate the JOY_HWS_* flags into axis masks.
* These flags allow any axis to be polled on any of the four axis bits in
* the gameport. For example, the X axis on a standard joystick is found on
* bit 0 (LSB) and the Y axis is on bit 1; however many steering wheel/pedal
* controllers have X on bit 0 but Y on bit 2. Although very few of these
* combinations are known to be used, supporting all the flags only causes a
* little extra work on setup. For each axis, there are three flags, one for
* each of the possible non-standard bit masks. Since it is possible that
* more than one of these may be set the invalid combinations are marked so
* that they can be refused.
*/
#define NA ( 0x80 )
/*
* Short versions of bit masks for axes
*/
#define X1 AXIS_X
#define Y1 AXIS_Y
#define X2 AXIS_R
#define Y2 AXIS_Z
/*
* Per axis flag masks and look up tables.
* In each case, combinations with more than one bit set are invalid
*/
#define XMAPBITS (JOY_HWS_XISJ2Y | JOY_HWS_XISJ2X | JOY_HWS_XISJ1Y)
/*
* 0 0 0 0001
* 0 0 1 0010
* 0 1 0 0100
* 1 0 0 1000
*/
static const unsigned char XLU[8] = { X1,Y1,X2,NA,Y2,NA,NA,NA };
#define XMAPSHFT 7
#define YMAPBITS (JOY_HWS_YISJ2Y | JOY_HWS_YISJ2X | JOY_HWS_YISJ1X)
/* 0 0 0 0010
* 0 0 1 0001
* 0 1 0 0100
* 1 0 0 1000
*/
static const unsigned char YLU[8] = { Y1,X1,X2,NA,Y2,NA,NA,NA };
#define YMAPSHFT 10
#define RMAPBITS (JOY_HWS_RISJ2Y | JOY_HWS_RISJ1X | JOY_HWS_RISJ1Y)
/* 0 0 0 0100
* 0 0 1 0010
* 0 1 0 0001
* 1 0 0 1000
*/
static const unsigned char RLU[8] = { X2,Y1,X1,NA,Y2,NA,NA,NA };
#define RMAPSHFT 20
#define ZMAPBITS (JOY_HWS_ZISJ2X | JOY_HWS_ZISJ1X | JOY_HWS_ZISJ1Y)
/* 0 0 0 1000
* 0 0 1 0010
* 0 1 0 0001
* 1 0 0 0100
*/
static const unsigned char ZLU[8] = { Y2,Y1,X1,NA,X2,NA,NA,NA };
#define ZMAPSHFT 13
#define POVMAPBITS (JOY_HWS_POVISJ2X | JOY_HWS_POVISJ1X | JOY_HWS_POVISJ1Y)
/*
* POV is the same as Z but with a larger shift
*/
#define POVMAPSHFT 16
#undef X1
#undef Y1
#undef X2
#undef Y2
/*
* This translates from an axis bitmask to an axis value index. The elements
* used should be as follows (X marks unsed) { X, 0, 1, X, 2, X, X, X, 3 }.
*/
static const unsigned char cAxisIndexTable[9] = { 0, 0, 1, 0, 2, 0, 0, 0, 3 };
typedef enum _POV1
{
P1_NULL = 0x80,
P1_0,
P1_90,
P1_180,
P1_270
} POV1;
typedef enum _POV2
{
P2_NULL = 0xc0,
P2_0,
P2_90,
P2_180,
P2_270
} POV2;
#define POV_MASK ((unsigned char)(~(P1_NULL | P2_NULL)))
/*
* Look up tables for button combos
* Buttons are zero based so use P1_NULL for a zero input so we don't have to
* special case it as a do nothing button.
* The 7th Button can be mapped either from it's unique combination or as
* foreward on a second POV being read as buttons 7 - 10.
*/
static const unsigned char c1PComboLU[] = { P1_NULL,0, 1, P1_270,
2, 4, 8, P1_180,
3, 5, 7, P1_90,
9, 6, 6, P1_0 };
static const unsigned char c2PComboLU[] = { P1_NULL,0, 1, P1_270,
2, 4, P2_180, P1_180,
3, 5, P2_90, P1_90,
P2_270, 6, P2_0, P1_0 };
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func NTSTATUS | HGM_DriverInit |
*
* Perform global initialization.
* <nl>This is called from DriverEntry. Try to initialize a CPU
* specific timer but if it fails set up default
*
* @rvalue STATUS_SUCCESS | success
* @rvalue STATUS_UNSUCCESSFUL | not success
*
*****************************************************************************/
NTSTATUS EXTERNAL
HGM_DriverInit()
{
NTSTATUS ntStatus = STATUS_SUCCESS;
if( !HGM_CPUCounterInit() )
{
LARGE_INTEGER QPCFrequency;
KeQueryPerformanceCounter( &QPCFrequency );
if( ( QPCFrequency.HighPart == 0 )
&& ( QPCFrequency.LowPart <= 10000 ) )
{
ntStatus = STATUS_UNSUCCESSFUL;
HGM_DBGPRINT(FILE_HIDJOY | HGM_ERROR,\
("QPC at %I64u Hz is unusable",
QPCFrequency.QuadPart ));
}
else
{
Global.CounterScale = CALCULATE_SCALE( QPCFrequency.QuadPart );
Global.ReadCounter = (COUNTER_FUNCTION)&KeQueryPerformanceCounter;
HGM_DBGPRINT(FILE_HIDJOY | HGM_BABBLE,\
("QPC at %I64u Hz used with scale %d",
QPCFrequency.QuadPart, Global.CounterScale ));
}
}
return ntStatus;
}
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func NTSTATUS | HGM_SetupButtons |
*
* Use the flags in the DeviceExtension to check and set up buttons.
* <nl>This is called both from HGM_JoystickConfig to validate the
* configuration and HGM_GenerateReport to prepare for polling.
*
* @parm IN OUT PDEVICE_EXTENSION | DeviceExtension |
*
* Pointer to the minidriver device extension
*
* @rvalue STATUS_SUCCESS | success
* @rvalue STATUS_DEVICE_CONFIGURATION_ERROR | The configuration is invalid
*
*****************************************************************************/
NTSTATUS INTERNAL
HGM_SetupButtons
(
IN OUT PDEVICE_EXTENSION DeviceExtension
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
if( DeviceExtension->fSiblingFound )
{
if( DeviceExtension->nButtons > 2 )
{
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_SetupButtons: failing config of sibling device with %u buttons",\
DeviceExtension->nButtons));
}
if( DeviceExtension->HidGameOemData.OemData[1].joy_hws_dwFlags & JOY_HWS_POVISBUTTONCOMBOS )
{
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_SetupButtons: failing config of sibling device with combo buttons" ));
}
}
else
{
if( DeviceExtension->HidGameOemData.OemData[0].joy_hws_dwFlags & JOY_HWS_POVISBUTTONCOMBOS )
{
if( DeviceExtension->nButtons > MAX_BUTTONS )
{
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_SetupButtons: failing config of button combo device with %u buttons",\
DeviceExtension->nButtons));
}
}
else
{
if( DeviceExtension->nButtons > 4 )
{
if( DeviceExtension->resistiveInputMask & AXIS_R )
{
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_SetupButtons: failing config of device with R axis and %u buttons",\
DeviceExtension->nButtons));
}
else
{
/*
* 5th button always read from R axis.
* Set the inital on/off boundary low
*/
DeviceExtension->resistiveInputMask |= AXIS_R;
DeviceExtension->button5limit = 2;
}
if( DeviceExtension->nButtons > 5 )
{
if( DeviceExtension->resistiveInputMask & AXIS_Z )
{
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_SetupButtons: failing config of device with Z axis and %u buttons",\
DeviceExtension->nButtons));
}
else
{
/*
* 6th button always read from Z axis.
* Set the inital on/off boundary low
*/
DeviceExtension->resistiveInputMask |= AXIS_Z;
DeviceExtension->button6limit = 2;
}
if( DeviceExtension->nButtons > 6 )
{
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_SetupButtons: failing config of device with %u buttons",\
DeviceExtension->nButtons));
}
}
}
}
}
return( ntStatus );
} /* HGM_SetupButtons */
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func NTSTATUS | HGM_MapAxesFromDevExt |
*
* Use the flags in the DeviceExtension to generate mappings for each
* axis.
* <nl>This is called both from HGM_JoystickConfig to validate the
* configuration and HGM_GenerateReport to use the axis maps.
*
*
* @parm IN OUT PDEVICE_EXTENSION | DeviceExtension |
*
* Pointer to the minidriver device extension
*
* @rvalue STATUS_SUCCESS | success
* @rvalue STATUS_DEVICE_CONFIGURATION_ERROR | The configuration is invalid
*
*****************************************************************************/
NTSTATUS EXTERNAL
HGM_MapAxesFromDevExt
(
IN OUT PDEVICE_EXTENSION DeviceExtension
)
{
NTSTATUS ntStatus;
ULONG dwFlags;
int nAxis;
UCHAR AxisMask;
ntStatus = STATUS_SUCCESS;
dwFlags = DeviceExtension->HidGameOemData.OemData[(DeviceExtension->fSiblingFound!=0)].joy_hws_dwFlags;
HGM_DBGPRINT( FILE_HIDJOY | HGM_BABBLE2,\
("HGM_MapAxesFromDevExt: - - - dwFlags=0x%x - - -", dwFlags));
#define XIS (0)
#define YIS (1)
#define ZIS (2)
#define RIS (3)
/*
* Check X and Y last as Z, R and POV must not overlap
* The are no flags to indicate the presence of X or Y so if they
* overlap, this indicates that they are not used,
*/
DeviceExtension->resistiveInputMask = 0;
for( nAxis=MAX_AXES; nAxis>=0; nAxis-- )
{
DeviceExtension->AxisMap[nAxis] = INVALID_INDEX;
}
nAxis = 0;
DeviceExtension->povMap = INVALID_INDEX;
if( dwFlags & JOY_HWS_HASZ )
{
AxisMask = ZLU[(dwFlags & ZMAPBITS) >> ZMAPSHFT];
if( AxisMask >= NA )
{
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: Z axis mapping error dwFlags=0x%x",\
dwFlags));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
}
else
{
nAxis = 1;
DeviceExtension->resistiveInputMask = AxisMask;
DeviceExtension->AxisMap[ZIS] = cAxisIndexTable[AxisMask];
}
}
if( dwFlags & JOY_HWS_HASR )
{
AxisMask = RLU[(dwFlags & RMAPBITS) >> RMAPSHFT];
if( AxisMask >= NA )
{
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: R axis mapping error dwFlags=0x%x",\
dwFlags));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
}
else
{
if( DeviceExtension->resistiveInputMask & AxisMask )
{
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR, \
("HGM_MapAxesFromDevExt: R axis mapped to same as Z axis"));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR ;
}
else
{
nAxis++;
DeviceExtension->resistiveInputMask |= AxisMask;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -