Module HidGame
Filename: C:/NTDDK/SRC/WDM/HID/HIDGAME/HIDGAME.H
Description
Analog WDM/HID Joystick driver.
HidGame is the HID minidriver for analog joysticks. This driver registers with the HID class driver and responds to IRPs put out by HIDclass. It informs HIDClass about the capabilities of the joystick and polls the joystick in response to a read IOCTL.
This driver is loaded in reponse to a "New hardware Found" PnP event, and consequently must have an entry in an inf file that binds a PnP hardware ID to this driver.
Gameport joysticks are not true PnP devices, so the user has to inform the system about the joystick that was added to the gameport by using the Game Controllers CPL "Add" a joystick. An example of how a new joystick type can be created is provided in the accompanying inf file.
Once a user selects a joystick and gameport, the GameCPL passes this information to DirectInput which sends an IOCTL to the gameport bus driver (GameEnum), specifying the number of axes, buttons and a PnPHardware ID for the joystick. The Gameport Bus informs PnP of a new device arrival. PnP searches the system for a match for the hardwareID and loads the appropriate driver.
 The following files are part of this driver.

HidGame.c 
DriverEntry, CreateClose, AddDevice and Unload Routines. This code performs functions required for any device driver and so can probably be used without changes for any game other game device.

PnP.c 
Support routines for PnP IOCTLs.

Ioctl.c 
Support routines for Non PnP IOCTLs These deal with all the HID IOCTLs required for an ordinary game device and so could be used without change as there is no analog specific funtionality in these routines. Drivers for some devices may need to add code to support more complex devices.

HidJoy.c 
Support routines to translate legacy joystick flags and data into HID descriptors.  The majority of this code is needed to support the wide variety of analog joysticks available so is not relevant to drivers written for specific devices.

Poll.c 
Support routines to read analog joystick data from a gameport.  These functions are likely to be of little use in a digital joystick driver.

i386\timing.c 
Support routines to use x86 Time Stamp Counter. Includes code to check for the presence of, calibrate and read the high speed CPU timer.

Hidgame.h 
Common include file. The general definitions are likely to be of use in most drivers for game devices but some customization will be needed.

Debug.h 
Definitions to aid debugging. This contains the tag for the driver name used in debug output which must be changed.

Analog.h 
Specific include file. Definitions specific to analog joystick devices.

OemSetup.inf 
Sample inf file. See comments in this file for how to install devices.

Source 
 Source file for the NT build utility

Makefile 
 Used as part of the build process

DriverEntry
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DeviceObject, IN PUNICODE_STRINT RegistryPath) 
Installable driver initialization entry point. 
This entry point is called directly by the I/O system.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidgame.c
Parameters
DeviceObject
Pointer to the driver object
RegistryPath
Pointer to a unicode string representing the path, to driver-specific key in the registry.
Return Codes
STATUS_SUCCESS	success	
???	returned HidRegisterMinidriver()	

HGM_AddDevice
NTSTATUS HGM_AddDevice(IN PDRIVER_OBJECT DeviceObject, IN PDEVICE_OBJECT FunctionalDeviceObject) 
Called by hidclass, allows us to initialize our device extensions.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidgame.c
Parameters
DeviceObject
Pointer to the driver object
FunctionalDeviceObject
Pointer to a functional device object created by hidclass.
Return Codes
STATUS_SUCCESS	success	

HGM_ChangeHandler
VOID HGM_ChangeHandler(IN  OUT PDEVICE_EXTENSION DeviceExtension) 
Use IOCTL_GAMEENUM_EXPOSE_SIBLING and IOCTL_GAMEENUM_REMOVE_SELF to change the attributes of the device.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidjoy.c
Parameters
DeviceExtension
Pointer to the mini-driver device extension.

HGM_CreateClose
NTSTATUS HGM_CreateClose(IN PDRIVER_OBJECT DeviceObject, IN PIRP Irp) 
Process the create and close IRPs sent to this device.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidgame.c
Parameters
DeviceObject
Pointer to the driver object
Irp
Pointer to an I/O Request Packet.
Return Codes
STATUS_SUCCESS	success	
STATUS_INVALID_PARAMETER	Irp not handled	

HGM_DeviceChanged
VOID HGM_DeviceChanged(IN  OUT PDEVICE_EXTENSION DeviceExtension) 
Start the process of changing the device attributes by stashing away all the data needed and then initializing and queuing a work item to call the IOCTL at the required PASSIVE_LEVEL.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidjoy.c
Parameters
DeviceExtension
Pointer to the mini-driver device extension.

HGM_DriverInit
VOID HGM_DriverInit(void) 
Perform global initialization. 
This is called from DriverEntry.  Try to initialize a CPU specific timer but if it fails set up default
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidjoy.c

HGM_Game2HID
VOID HGM_Game2HID(IN      PDEVICE_EXTENSION DeviceExtension, IN  OUT PUHIDGAME_INPUT_DATA pHIDData) 
Process the data returned from polling the gameport into values and buttons for returning to HID. 
The meaning of the data is interpreted according to the characteristics of the device described in the hardware settings flags.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidjoy.c
Parameters
DeviceExtension
Pointer to the mini-driver device extension.
pHIDData
Pointer to the buffer into which the HID report should be written. This buffer must be assumed to be unaligned.

HGM_GenerateReport
NTSTATUS HGM_GenerateReport(IN PDEVICE_OBJECT DeviceObject, IN OUT UCHAR * rgGameReport[MAXBYTES_GAME_REPORT], OUT PUSHORT pCbReport) 
Generates a hid report descriptor for a n-axis, m-button joystick, depending on number of buttons and joy_hws_flags field.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidjoy.c
Parameters
DeviceObject
Pointer to the device object
rgGameReport[MAXBYTES_GAME_REPORT]
Array that receives the HID report descriptor
pCbReport
Address of a short integer that receives size of HID report descriptor.
Return Codes
STATUS_SUCCESS	success	
STATUS_BUFFER_TOO_SMALL	Need more memory for HID descriptor	

HGM_GetAttributes
NTSTATUS HGM_GetAttributes(IN PDRIVER_OBJECT DeviceObject, IN PIRP Irp) 
Respond to IOCTL_HID_GET_ATTRIBUTES, by filling the HID_DEVICE_ATTRIBUTES struct
Defined in: c:/ntddk/src/wdm/hid/hidgame/ioctl.c
Parameters
DeviceObject
Pointer to the driver object
Irp
Pointer to an I/O Request Packet.
Return Codes
STATUS_SUCCESS	success	
???	???	

HGM_GetDeviceDescriptor
NTSTATUS HGM_GetDeviceDescriptor(IN PDRIVER_OBJECT DeviceObject, IN PIRP Irp) 
Respond to HIDCLASS IOCTL_HID_GET_DEVICE_DESCRIPTOR by returning a device descriptor
Defined in: c:/ntddk/src/wdm/hid/hidgame/ioctl.c
Parameters
DeviceObject
Pointer to the driver object
Irp
Pointer to an I/O Request Packet.
Return Codes
STATUS_SUCCESS	success	
STATUS_BUFFER_TOO_SMALL	need more memory	

HGM_GetReportDescriptor
NTSTATUS HGM_GetReportDescriptor(IN PDRIVER_OBJECT DeviceObject, IN PIRP Irp) 
Respond to HIDCLASS IOCTL_HID_GET_REPORT_DESCRIPTOR by returning appropriate the report descriptor
Defined in: c:/ntddk/src/wdm/hid/hidgame/ioctl.c
Parameters
DeviceObject
Pointer to the driver object
Irp
Pointer to an I/O Request Packet.
Return Codes
STATUS_SUCCESS	success	
???	???	

HGM_GetResources
NTSTATUS HGM_GetResources(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
Gets gameport resource information from the GameEnum driver
Defined in: c:/ntddk/src/wdm/hid/hidgame/pnp.c
Parameters
DeviceObject
Pointer to the device object.
Irp
Pointer to an I/O request packet.
Return Codes
STATUS_SUCCESS	success	
???	Return from IoCallDriver()	

HGM_InitAnalog
NTSTATUS HGM_InitAnalog(IN PDEVICE_OBJECT DeviceObject) 
Check that the configuration is valid whilst there is still time to refuse it. 
Detect and validate sibling relationships and call HGM_JoystickConfig for the rest of the work.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidjoy.c
Parameters
DeviceObject
Pointer to the device object
Return Codes
STATUS_SUCCESS	success	
STATUS_DEVICE_CONFIGURATION_ERROR	Invalid configuration specified	

HGM_InitDevice
NTSTATUS HGM_InitDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
Get the device information and attempt to initialize a configuration for a device.  If we cannot identify this as a valid HID device or configure the device, our start device function is failed.
Defined in: c:/ntddk/src/wdm/hid/hidgame/pnp.c
Parameters
DeviceObject
Pointer to the device object.
Irp
Pointer to an I/O request packet.
Return Codes
STATUS_SUCCESS	success	
STATUS_DEVICE_CONFIGURATION_ERROR	Resources overlap	
???	Return from HGM_GetResources() or HGM_JoystickConfig()	

HGM_InternalIoctl
NTSTATUS HGM_InternalIoctl(IN PDRIVER_OBJECT DeviceObject, IN PIRP Irp) 
Process the Control IRPs sent to this device. 
This function cannot be pageable because reads/writes can be made at dispatch-level
Defined in: c:/ntddk/src/wdm/hid/hidgame/ioctl.c
Parameters
DeviceObject
Pointer to the driver object
Irp
Pointer to an I/O Request Packet.
Return Codes
STATUS_SUCCESS	success	
STATUS_NOT_SUPPORT	Irp function not supported	
???	???	

HGM_JoystickConfig
NTSTATUS HGM_JoystickConfig(IN PDEVICE_OBJECT DeviceObject) 
Check that the configuration is valid whilst there is still time to refuse it. 
HGM_GenerateReport uses the results generated here if the settings are OK.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidjoy.c
Parameters
DeviceObject
Pointer to the device object
Return Codes
STATUS_SUCCESS	success	
STATUS_DEVICE_CONFIGURATION_ERROR	Invalid configuration specified	

HGM_MapAxesFromDevExt
NTSTATUS HGM_MapAxesFromDevExt(IN OUT PDEVICE_EXTENSION DeviceExtension) 
Use the flags in the DeviceExtension to generate mappings for each axis. 
This is called both from HGM_JoystickConfig to validate the configuration and HGM_GenerateReport to use the axis maps.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidjoy.c
Parameters
DeviceExtension
Pointer to the minidriver device extension
Return Codes
STATUS_SUCCESS	success	
STATUS_DEVICE_CONFIGURATION_ERROR	The configuration is invalid	

HGM_PnP
NTSTATUS HGM_PnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
Plug and Play dispatch routine for this driver.
Defined in: c:/ntddk/src/wdm/hid/hidgame/pnp.c
Parameters
DeviceObject
Pointer to the device object.
Irp
Pointer to an I/O request packet.
Return Codes
STATUS_SUCCESS	success	
STATUS_DELETE_PENDING	PnP IRP received after device was removed	
???	Return from IoCallDriver() or HGM_InitDevice()	

HGM_PnPComplete
NTSTATUS HGM_PnPComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
Completion routine for PnP IRPs.
Defined in: c:/ntddk/src/wdm/hid/hidgame/pnp.c
Parameters
DeviceObject
Pointer to the device object.
Irp
Pointer to an I/O request packet.
Return Codes
STATUS_MORE_PROCESSING_REQUIRED	We want the IRP back	

HGM_Power
NTSTATUS HGM_Power(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
The power dispatch routine. 
This driver does not recognize power IRPS.  It merely sends them down, unmodified to the next device on the attachment stack. As this is a POWER irp, and therefore a special irp, special power irp handling is required. No completion routine is required.
Defined in: c:/ntddk/src/wdm/hid/hidgame/pnp.c
Parameters
DeviceObject
Pointer to the device object.
Irp
Pointer to an I/O request packet.
Return Codes
STATUS_SUCCESS	success	
???	Return from PoCallDriver()	

HGM_ReadReport
NTSTATUS HGM_ReadReport(IN PDRIVER_OBJECT DeviceObject, IN PIRP Irp) 
Poll the gameport, remap the axis and button data and package into the defined HID report field. 
This routine cannot be pageable as HID can make reads at dispatch-level.
Defined in: c:/ntddk/src/wdm/hid/hidgame/ioctl.c
Parameters
DeviceObject
Pointer to the driver object
Irp
Pointer to an I/O Request Packet.
Return Codes
STATUS_SUCCESS	success	
STATUS_DEVICE_NOT_CONNECTED	Device Failed to Quiesce ( not connected )	
STATUS_TIMEOUT	Could not determine exact transition time for one or more axis but not a failure.	

HGM_RemoveDevice
VOID HGM_RemoveDevice(IN PDEVICE_EXTENSION DeviceExtension) 
FDO Remove routine
Defined in: c:/ntddk/src/wdm/hid/hidgame/pnp.c
Parameters
DeviceExtension
Pointer to the device extension.

HGM_SetupButtons
NTSTATUS HGM_SetupButtons(IN OUT PDEVICE_EXTENSION DeviceExtension) 
Use the flags in the DeviceExtension to check and set up buttons. 
This is called both from HGM_JoystickConfig to validate the configuration and HGM_GenerateReport to prepare for polling.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidjoy.c
Parameters
DeviceExtension
Pointer to the minidriver device extension
Return Codes
STATUS_SUCCESS	success	
STATUS_DEVICE_CONFIGURATION_ERROR	The configuration is invalid	

HGM_Unload
void HGM_Unload(IN PDRIVER_OBJECT DeviceObject) 
Free all the allocated resources, etc.
Defined in: c:/ntddk/src/wdm/hid/hidgame/hidgame.c
Parameters
DeviceObject
Pointer to the driver object

HGM_UpdateLatestPollData
NTSTATUS HGM_UpdateLatestPollData(IN  OUT PDEVICE_EXTENSION DeviceExtension) 
Do whatever polling is required and possible to update the LastGoodAxis and LastGoodButton arrays in the DeviceExtension. Handles synchronization and non-fatal errors. 
This routine cannot be pageable as HID can make reads at dispatch-level.
Defined in: c:/ntddk/src/wdm/hid/hidgame/poll.c
Parameters
DeviceExtension
Pointer to the device extension containing the data to be updated and the functions and to use.
Return Codes
STATUS_SUCCESS	success	
STATUS_DEVICE_CONFIGURATION_ERROR	Invalid configuration specified	

HidAnalogPoll
NTSTATUS HidAnalogPoll(IN PDEVICE_EXTENSION DeviceExtension, IN UCHAR resisitiveInputMask, IN BOOLEAN fApproximate, IN OUT ULONG Axis[MAX_AXES], OUT UCHAR Button[PORT_BUTTONS]) 
Polling routine for analog joysticks. 
Polls the analog device for position and button information. The position  information in analog devices is conveyed by the duration of a pulse width. Each axis occupies one bit position. The read operation is started by writing a value to the joystick io address. Immediately thereafter we begin examing the values returned and the elapsed time.
This sort of device has a few limitations:
First, button information is not latched by the device, so if a button press which occurrs in between polls it will be lost. There is really no way to prevent this short of devoting the entire cpu to polling.  In reality this does not cause a problem.
Second, since it is necessary to measure the duration of the axis pulse, the most accurate results would be obtained using the smallest possible sense loop and no interruptions of this loop. The typical range of pulse lengths is from around 10 uSecs to 1500 uSecs but depending on the joystick and gameport, this could extend to at least 8000 uSecs.  Keeping interrupts disabled for this length of time causes many problems, like modems losing connections to sound break ups.
Third, because each iteration of the poll loop requires an port read, the speed of the loop is largely constrained by the speed of the IO bus. This also means that when there is contention for the IO bus, the loop will be slowed down.  IO contention is usually caused by DMAs (or FDMAs) which result in a significant slow down.
Forth, because of the previous two problems, the poll loop may be slowed down or interrupted at any time so an external time source is needed to measure the pulse width for each axis.  The only cross-platform high resolution timer is the read with KeQueryPerformanceCounter. Unfortunately the implementation of this often uses a 1.18MHz 8253 timer which requires 3 IO accesses to read, compounding the third problem and even then, the result may need to be reread if the counters were in the wrong state.  Current CPUs have on board counters that can be used to provide very accurate timing and more recent HAL implementations tend to use these to implement KeQueryPerformanceCounter so this will be a problem on less systems as time goes on.  In the majority of cases, a poor KeQueryPerformanceCounter implementation is made irrelevant by testing for the availability of a CPU time stamp counter on Intel architechtures and using it directly if it is available.
The algorithm implemented here is not the most obvious but works as follows:
Once started, the axes read a value of one until the completion of their pulse.  The axes are the four lower bits in the byte read from the port. The state of the axes in each iteration of the poll loop is therefore represented as a value between 0 and 15.  The important time for each axis is the time at which it changes from 1 to 0.  This is done by using the value representing the state of the axes to index an array into which time values are stored.  For each axis, the duration of its pulse width is the latest time stored in the array at an index with the bit for that axis set.  However since interrupts can occur at any time, it is not possible to simultaneously read the port value and record that time in an atomic operation the in each iteration, the current time is stored in two arrays, one using the index before the time was recorded and the other using the index after the time was recorded. Once all the axes being monitored have become 0, or a timeout value is reached, the data left in the arrays is analysed to find the best estimate for the transition time for each axis.  If the times before and after the transition differ by too much, it is judged that an interrupt must have occured so the last known good axis value is returned unless that falls outside the range in which it is known that the transition occured.
This routine cannot be pageable as HID can make reads at dispatch-level.
Defined in: c:/ntddk/src/wdm/hid/hidgame/poll.c
Parameters
DeviceExtension
Pointer to the device extension.
resisitiveInputMask
Mask that describes the axes lines that are to be polled
fApproximate
Boolean value indicating if it is OK to approximate some value of the current axis state with the last axis state if polling was not successful (we took an interrput during polling)
Axis[MAX_AXES]
The state of the axes. On entry the last axis state is passed into this routine. If the fApproximate flag is turned on, we can make use of the last axis state to "guess" the current axis state.
Button[PORT_BUTTONS]
Receives the state of the buttons. 0x0 specifies the button is not pressed and 0x1 indicates an armed button state.
Return Codes
STATUS_SUCCESS	success	
STATUS_DEVICE_NOT_CONNECTED	Device Failed to Quiesce ( not connected ) This is a failure code.	
STATUS_TIMEOUT	Could not determine exact transition time for one or more axis.  This is a success code.	

ANALOG_DEVICE Structure
typedef struct {
	USHORT nAxes;
	USHORT nButtons;
	HIDGAME_OEM_DATA HidGameOemData;
	ULONG ScaledTimeout;
	ULONG ScaledThreshold;
	ULONG LastGoodAxis[MAX_AXES];
	UCHAR LastGoodButton[PORT_BUTTONS];
	int AxisMap[MAX_AXES];
	int povMap;
	UCHAR resistiveInputMask;
	UCHAR bSiblingState;
	BOOLEAN fSiblingFound;
} ANALOG_DEVICE;

Analog Device specific data.
Defined in: C:/NTDDK/SRC/WDM/HID/HIDGAME/ANALOG.H
Members
nAxes
Number of axis this device has.
nButtons
Number of buttons this device has.
HidGameOemData
The OEM Data field ( Contains joy_hws_dwFlags, vid & pid )
ScaledTimeout
The number value at which an axis is considered to be not present.
ScaledThreshold
The minimum resolution of a polling cycle. This is used to detect if we've been pre-empted or interrupted during a polling loop.
LastGoodAxis[MAX_AXES]
Value of the axes on last good poll.
LastGoodButton[PORT_BUTTONS]
Value of the buttons on last good poll.
AxisMap[MAX_AXES]
Index of axes remapping.
povMap
Index of axis where POV is mapped.
resistiveInputMask
Resisitive Input mask.
bSiblingState
Indicates the state of an expose sibling\remove self transition
fSiblingFound
Set to true if this device has a sibling.

DEVICE_EXTENSION Structure
typedef struct {
	PGAMEENUM_READPORT ReadAccessor;
	PGAMEENUM_WRITEPORT WriteAccessor;
	PGAMEENUM_READPORT_DIGITAL ReadAccessorDigital;
	PGAMEENUM_ACQUIRE_PORT AcquirePort;
	PGAMEENUM_RELEASE_PORT ReleasePort;
	PVOID GameContext;
	PVOID PortContext;
	LIST_ENTRY Link;
	KEVENT RemoveEvent;
	LONG RequestCount;
	PDEVICE_OBJECT NextDeviceObject;
	WORK_QUEUE_ITEM WorkItem;
	ANALOG_DEVICE unnamed structure see ANALOG_DEVICE;
	BOOLEAN fRemoved;
	BOOLEAN fStarted;
	BOOLEAN fSurpriseRemoved;
} DEVICE_EXTENSION;

Device specific data.
Defined in: C:/NTDDK/SRC/WDM/HID/HIDGAME/HIDGAME.H
Members
ReadAccessor
Read Accessor function for the gameport. Obtained in the return from IOCTL to the gameport.
WriteAccessor
Write Accessor function for the gameport. Obtained in the return from IOCTL to the gameport.
ReadAccessorDigital
Digital read accessor for the gameport. Obtained as part of return from IOCTL to the gameport
AcquirePort
Function to call before reading/writing to the port. Obtained as part of return from IOCTL to the gameport
ReleasePort
Function to call when done reading/writing to the port. Obtained as part of return from IOCTL to the gameport
GameContext
Token to read this game port. Obtained as part of the return from IOCTL to the gameport.
PortContext
Context to pass to AcquirePort and ReleasePort. Obtained as part of the return from IOCTL to the gameport.
Link
Link to other hidgame devices on the system.
RemoveEvent
The remove plugplay request must use this event to make sure all other requests have completed before it deletes the device object.
RequestCount
Number of IRPs underway.
NextDeviceObject
NOTE: Only present if CHANGE_DEVICE is defined
DeviceObject to send self created IRPs down to
WorkItem
NOTE: Only present if CHANGE_DEVICE is defined
Work item used for expose sibling/remove self
unnamed structure see ANALOG_DEVICE
Structure containing analog device specific information.
NOTE: this structure is placed after the DWORD aligned elements.
fRemoved
Set to true if the device has been removed => all requests should be failed
fStarted
Set to true is device has started.
fSurpriseRemoved
Set to true if the device has been surprise removed by PnPs device has started.
See Also
ANALOG_DEVICE.

HIDGAME_GLOBAL Structure
typedef struct {
	FAST_MUTEX Mutex;
	LIST_ENTRY DeviceListHead;
	KSPIN_LOCK SpinLock;
	COUNTER_FUNCTION ReadCounter;
	ULONG CounterScale;
} HIDGAME_GLOBAL;

Global struct to store driver wide data. Stuff we need to share across multiple instances of this driver.
Defined in: C:/NTDDK/SRC/WDM/HID/HIDGAME/HIDGAME.H
Members
Mutex
Mutex to synchronize access to the following list entry
DeviceListHead
Keeps a list of all devices.
SpinLock
Spinlock used to stop multiple processors polling gameports at once.  It would be better to keep a list of spinlocks, one for each gameport but then processors could contend for IO access and we'd have to maintain another list.
ReadCounter
Function to retrieve clock time
CounterScale
The scale to be used.

HIDGAME_INPUT_DATA Structure
typedef struct {
	ULONG Axis[MAX_AXES];
	UCHAR hatswitch[2];
	UCHAR Button[MAX_BUTTONS];
} HIDGAME_INPUT_DATA;

Our HID reports always have 4 axis values (one of which may be a polled POV), 2 digital POVs and 10 buttons. Depending on the HWS flags and number of buttons some of the fields will report constant data.
Note, this structure should be byte aligned so that the sizeof(it) is the same as HID will calculate given the report descriptor.  (In this case it happens to be aligned anyway.)
Defined in: C:/NTDDK/SRC/WDM/HID/HIDGAME/ANALOG.H
Members
Axis[MAX_AXES]
Axes data values.
hatswitch[2]
digital POVs (derived from button combos)
Button[MAX_BUTTONS]
Button data values.

OEMDATA Structure
typedef struct {
	USHORT VID;
	USHORT PID;
	ULONG joy_hws_dwFlags;
	ULONG Timeout;
	ULONG Reserved;
} OEMDATA;

OEMData is send to gameEnum as a parameter to IOCTL_EXPOSE_HARDWARE. Defined as 8 DWORDS. We interpert them here
Defined in: C:/NTDDK/SRC/WDM/HID/HIDGAME/ANALOG.H
Members
VID
Vendor ID
PID
Product ID
joy_hws_dwFlags
The dwFlags fields for the device ( Usually read from the registry )
Timeout
Global timeout for device polling in micro seconds
Reserved
Reserved for future use.