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.
1148 lines
32 KiB
1148 lines
32 KiB
/****************************************************************************
|
|
|
|
MODULE: VXDIOCTL.CPP
|
|
Tab stops 5 9
|
|
Copyright 1995-1997, Microsoft Corporation, All Rights Reserved.
|
|
|
|
PURPOSE: Methods for communicating with VJoyD min-driver specific
|
|
to Jolt Midi device
|
|
|
|
FUNCTIONS:
|
|
|
|
Author(s): Name:
|
|
---------- ----------------
|
|
MEA Manolito E. Adan
|
|
|
|
Revision History:
|
|
-----------------
|
|
Version Date Author Comments
|
|
------- ------ ----- -------------------------------------------
|
|
1.0 03-Jan-97 MEA Original
|
|
1.1 14-Apr-97 MEA Added SetMidiPort IOCTL
|
|
11-Jun-97 MEA Added JoltHWReset IOCTL
|
|
17-Jun-97 MEA Added MAX_RETRY_COUNT on IOCTLs
|
|
20-Mar-99 waltw Nuked VxDCommunicator, this is NT5 only!
|
|
20-Mar-99 waltw Nuked unused IsHandleValid
|
|
|
|
****************************************************************************/
|
|
|
|
#include "vxdioctl.hpp"
|
|
//#include <crtdbg.h> // For RPT macros
|
|
#include <WINIOCTL.H> // For IOCTL definitions (CTL_CODE)
|
|
#include "FFDevice.h" // For g_ForceFeedbackDevice
|
|
#include "sw_error.hpp" // For Sidewinder HRESULT Error codes
|
|
#include "hau_midi.hpp" // For MAX_RETRY_COUNT and others
|
|
#include "midi_obj.hpp" // Global Jolt midi object and definition
|
|
#include "JoyRegst.hpp" // The differnt types of ACK_NACK
|
|
#include "DTrans.h" // For global Data Transmitter
|
|
|
|
DriverCommunicator* g_pDriverCommunicator = NULL;
|
|
extern DataTransmitter* g_pDataTransmitter;
|
|
extern HINSTANCE g_MyInstance;
|
|
|
|
|
|
// Bitmasks for FW Version
|
|
#define FW_MAJOR_VERSION 0x40 // Bit 6
|
|
#define FW_MINOR_VERSION 0x3F // Bit 5-0
|
|
#define FW_PRODUCT_ID 0xff
|
|
|
|
// Bitmasks for Get Status packet dwDeviceStatus member
|
|
#define ERROR_STATUS_MASK 0x07 // only bits 0-2 valid
|
|
|
|
|
|
/********************************** HIDFeatureCommunicator class ***********************************/
|
|
|
|
/****************************************
|
|
**
|
|
** HIDFeatureCommunicator::HIDFeatureCommunicator()
|
|
**
|
|
** @mfunc Constructor for VxD Communications path
|
|
**
|
|
*****************************************/
|
|
HIDFeatureCommunicator::HIDFeatureCommunicator() :
|
|
DriverCommunicator(),
|
|
m_ForceFeature()
|
|
{
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** HIDFeatureCommunicator::~HIDFeatureCommunicator()
|
|
**
|
|
** @mfunc Destructor for VxD communications path
|
|
**
|
|
*****************************************/
|
|
HIDFeatureCommunicator::~HIDFeatureCommunicator()
|
|
{
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** BOOL HIDFeatureCommunicator::Initialize(UINT uJoystickId)
|
|
**
|
|
** @mfunc Opens the driver for communications via IOCTLs
|
|
**
|
|
** @rdesc TRUE if driver opened, FALSE otherwise
|
|
**
|
|
*****************************************/
|
|
BOOL HIDFeatureCommunicator::Initialize
|
|
(
|
|
UINT uJoystickId //@parm Joystick ID to use
|
|
)
|
|
{
|
|
if (g_ForceFeedbackDevice.IsOSNT5() == FALSE)
|
|
{ // Only allowable on NT5
|
|
return FALSE;
|
|
}
|
|
|
|
return (SUCCEEDED(m_ForceFeature.Initialize(uJoystickId, g_MyInstance)));
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** BOOL HIDFeatureCommunicator::ResetDevice()
|
|
**
|
|
** @mfunc Sends the driver a device reset IOCTL
|
|
**
|
|
** @rdesc S_OK if IOCTL suceeds,
|
|
**
|
|
*****************************************/
|
|
HRESULT HIDFeatureCommunicator::ResetDevice()
|
|
{
|
|
return m_ForceFeature.DoReset();
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** HRESULT HIDFeatureCommunicator::GetDriverVersion(DWORD& rdwMajor, DWORD& rdwMinor)
|
|
**
|
|
** @mfunc IOCTLs a version request
|
|
**
|
|
** @rdesc S_OK on success E_FAIL if driver not initialized
|
|
**
|
|
*****************************************/
|
|
HRESULT HIDFeatureCommunicator::GetDriverVersion
|
|
(
|
|
DWORD& rdwMajor, //@parm reference to returned major part of version
|
|
DWORD& rdwMinor //@parm reference to returned minor part of version
|
|
)
|
|
{
|
|
ULONG ulVersion = m_ForceFeature.GetVersion();
|
|
rdwMajor = (ulVersion >> 16) & 0x0000FFFF;
|
|
rdwMinor = ulVersion & 0x0000FFFF;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** HRESULT HIDFeatureCommunicator::GetID(LOCAL_PRODUCT_ID& rProductID)
|
|
**
|
|
** @mfunc IOCTLs a product id request
|
|
**
|
|
** @rdesc S_OK on success E_FAIL if driver not initialized
|
|
**
|
|
*****************************************/
|
|
HRESULT HIDFeatureCommunicator::GetID
|
|
(
|
|
LOCAL_PRODUCT_ID& rProductID //@parm reference to local product id structure for return value
|
|
)
|
|
{
|
|
if (rProductID.cBytes != sizeof LOCAL_PRODUCT_ID)
|
|
{ // structure size is invalid
|
|
return SFERR_INVALID_STRUCT_SIZE;
|
|
}
|
|
|
|
// Create report packet and request
|
|
PRODUCT_ID_REPORT productIDReport;
|
|
productIDReport.ProductId.cBytes = sizeof PRODUCT_ID;
|
|
HRESULT hr = m_ForceFeature.GetId(productIDReport);
|
|
if (FAILED(hr))
|
|
{ // There was a problem
|
|
return hr;
|
|
}
|
|
|
|
// Decode to local packet
|
|
rProductID.dwProductID = productIDReport.ProductId.dwProductID & FW_PRODUCT_ID;
|
|
rProductID.dwFWMajVersion = 1;
|
|
if (productIDReport.ProductId.dwFWVersion & FW_MAJOR_VERSION)
|
|
{
|
|
rProductID.dwFWMajVersion++;
|
|
}
|
|
rProductID.dwFWMinVersion = productIDReport.ProductId.dwFWVersion & FW_MINOR_VERSION;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** HRESULT HIDFeatureCommunicator::GetStatus(JOYCHANNELSTATUS& rChannelStatus)
|
|
**
|
|
** @mfunc IOCTLs a status request
|
|
**
|
|
** @rdesc S_OK on success E_FAIL if driver not initialized
|
|
**
|
|
*****************************************/
|
|
HRESULT HIDFeatureCommunicator::GetStatus
|
|
(
|
|
JOYCHANNELSTATUS& rChannelStatus //@parm reference to status packet for result
|
|
)
|
|
{
|
|
if (rChannelStatus.cBytes != sizeof JOYCHANNELSTATUS)
|
|
{ // structure size is invalid
|
|
return SFERR_INVALID_STRUCT_SIZE;
|
|
}
|
|
|
|
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
|
|
|
|
// Create report packet and perform request
|
|
JOYCHANNELSTATUS_REPORT statusReport;
|
|
statusReport.JoyChannelStatus.cBytes = sizeof JOYCHANNELSTATUS;
|
|
|
|
HRESULT hr = S_OK;
|
|
for (int i=0; i < MAX_GET_STATUS_PACKET_RETRY_COUNT; i++) {
|
|
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwGetStatusPacketDelay);
|
|
|
|
hr = m_ForceFeature.GetStatus(statusReport);
|
|
|
|
if (FAILED(hr))
|
|
{ // There was a problem
|
|
if (i > 5)
|
|
{
|
|
Sleep(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{ // Get the data from report packet
|
|
::memcpy(&rChannelStatus, &(statusReport.JoyChannelStatus), sizeof JOYCHANNELSTATUS);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** HRESULT HIDFeatureCommunicator::GetAckNack(ACKNACK& rAckNack, USHORT usRegIndex)
|
|
**
|
|
** @mfunc IOCTLs a status request
|
|
**
|
|
** @rdesc S_OK on success E_FAIL if driver not initialized
|
|
**
|
|
*****************************************/
|
|
HRESULT HIDFeatureCommunicator::GetAckNack
|
|
(
|
|
ACKNACK& rAckNack, //@parm Structure for return of acking
|
|
USHORT usRegIndex //@parm Index to what type of ack/nack to do
|
|
)
|
|
{
|
|
if (rAckNack.cBytes != sizeof ACKNACK)
|
|
{ // Invalid structure size
|
|
return SFERR_INVALID_STRUCT_SIZE;
|
|
}
|
|
|
|
// Determine how to get the result
|
|
switch (g_ForceFeedbackDevice.GetAckNackMethod(usRegIndex))
|
|
{
|
|
case ACKNACK_NOTHING:
|
|
{ // This one is real easy - do nothing
|
|
rAckNack.dwAckNack = ACK;
|
|
rAckNack.dwErrorCode = 0;
|
|
return S_OK;
|
|
}
|
|
case ACKNACK_BUTTONSTATUS:
|
|
{ // Look at the button status (status gate)
|
|
ULONG_REPORT report;
|
|
HRESULT hr = m_ForceFeature.GetAckNak(report);
|
|
if (FAILED(hr))
|
|
{ // There was a problem
|
|
return hr;
|
|
}
|
|
|
|
if (report.uLong & ACKNACK_MASK_200)
|
|
{ // NACK error, so get Error code
|
|
rAckNack.dwAckNack = NACK;
|
|
JOYCHANNELSTATUS statusPacket = { sizeof JOYCHANNELSTATUS };
|
|
if (FAILED(hr = GetStatus(statusPacket)))
|
|
{ // Failed to get status error
|
|
return hr;
|
|
}
|
|
rAckNack.dwErrorCode = (statusPacket.dwDeviceStatus & ERROR_STATUS_MASK);
|
|
return S_OK;
|
|
}
|
|
// ACK success
|
|
rAckNack.dwAckNack = ACK;
|
|
rAckNack.dwErrorCode = 0;
|
|
|
|
if (report.uLong & RUNNING_MASK_200)
|
|
{ // Current driver and effect running
|
|
rAckNack.dwEffectStatus = SWDEV_STS_EFFECT_RUNNING;
|
|
}
|
|
else
|
|
{ // Effect not running
|
|
rAckNack.dwEffectStatus = SWDEV_STS_EFFECT_STOPPED;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
case ACKNACK_STATUSPACKET:
|
|
{ // Use the Status Packet Error code field to determine ACK or NACK and Get Error code
|
|
JOYCHANNELSTATUS statusPacket = { sizeof JOYCHANNELSTATUS };
|
|
|
|
HRESULT hr = GetStatus(statusPacket);
|
|
if (FAILED(hr))
|
|
{ // Failed (retried inside GetStatus)
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
rAckNack.dwErrorCode = statusPacket.dwDeviceStatus & ERROR_STATUS_MASK;
|
|
rAckNack.dwAckNack = (rAckNack.dwErrorCode) ? NACK : ACK;
|
|
return S_OK;
|
|
}
|
|
default:
|
|
{ // Someone put garbage in the registry (do nothing)
|
|
rAckNack.dwAckNack = ACK;
|
|
rAckNack.dwErrorCode = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** HRESULT HIDFeatureCommunicator::GetStatusGateData(DWORD& rdwGateData)
|
|
**
|
|
** @mfunc IOCTLs a status gate request
|
|
**
|
|
** @rdesc S_OK on success E_FAIL if driver not initialized
|
|
**
|
|
*****************************************/
|
|
HRESULT HIDFeatureCommunicator::GetStatusGateData
|
|
(
|
|
DWORD& rdwGateData //@parm reference to return gate data
|
|
)
|
|
{
|
|
ULONG_REPORT report;
|
|
HRESULT hr = m_ForceFeature.GetAckNak(report);
|
|
rdwGateData = report.uLong;
|
|
return hr;
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** HRESULT HIDFeatureCommunicator::SendBackdoorShortMidi(DWORD dwMidiMessage)
|
|
**
|
|
** @mfunc IOCTLs a request sending a message through midi backdoor
|
|
**
|
|
** @rdesc S_OK on success E_FAIL if driver not initialized
|
|
**
|
|
*****************************************/
|
|
HRESULT HIDFeatureCommunicator::SendBackdoorShortMidi
|
|
(
|
|
DWORD dwMidiMessage //@parm Midi Channel Message to send via IOCTL
|
|
)
|
|
{
|
|
// Byte count
|
|
short int sByteCount = 3;
|
|
BYTE bCmd = BYTE(dwMidiMessage & 0xF0);
|
|
if ((bCmd == 0xC0 ) || (bCmd == 0xD0)) {
|
|
sByteCount = 2;
|
|
}
|
|
|
|
// Send via data transmitter
|
|
if (g_pDataTransmitter != NULL) {
|
|
if (g_pDataTransmitter->Send((BYTE*)(&dwMidiMessage), sByteCount)) {
|
|
return S_OK;
|
|
}
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
// Must use the data transmitter there is no backdoor in NT5
|
|
return E_FAIL;
|
|
}
|
|
|
|
/****************************************
|
|
**
|
|
** HRESULT HIDFeatureCommunicator::SendBackdoorLongMidi(BYTE* pMidiData)
|
|
**
|
|
** @mfunc IOCTLs a request sending a message through midi backdoor
|
|
**
|
|
** @rdesc S_OK on success E_FAIL if driver not initialized
|
|
**
|
|
*****************************************/
|
|
HRESULT HIDFeatureCommunicator::SendBackdoorLongMidi
|
|
(
|
|
BYTE* pMidiData //@parm Array of bytes to send out
|
|
)
|
|
{
|
|
// Count the bytes
|
|
short int sByteCount = 1;
|
|
while (!(pMidiData[sByteCount++] & 0x80));
|
|
|
|
// Send via data transmitter?
|
|
if (g_pDataTransmitter != NULL) {
|
|
if (g_pDataTransmitter->Send(pMidiData, sByteCount)) {
|
|
return (SUCCESS);
|
|
}
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
|
|
// There is no real backdoor in NT
|
|
return E_FAIL;
|
|
}
|
|
|
|
/********************************** Old dead code ***********************************/
|
|
#if 0
|
|
#include <windows.h>
|
|
|
|
#include <WINIOCTL.H>
|
|
|
|
#include "vxdioctl.hpp"
|
|
#include "SW_error.hpp"
|
|
#include "version.h"
|
|
#include "hau_midi.hpp"
|
|
#include "midi_obj.hpp"
|
|
|
|
#include "DTrans.h"
|
|
#include "FFDevice.h"
|
|
#include "joyregst.hpp"
|
|
|
|
#ifdef _DEBUG
|
|
extern char g_cMsg[160];
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
extern void DebugOut(LPCTSTR szDebug);
|
|
#else !_DEBUG
|
|
#define DebugOut(x)
|
|
#endif _DEBUG
|
|
|
|
|
|
extern DataTransmitter* g_pDataTransmitter;
|
|
DWORD g_PreviousShortMidi = 0;
|
|
|
|
class CJoltMidi;
|
|
extern CJoltMidi *g_pJoltMidi;
|
|
|
|
//
|
|
// --- IOCTL Functions
|
|
//
|
|
/****************************************************************************
|
|
|
|
FUNCTION: GetDevice
|
|
|
|
PARAMETERS: IN const char* vxdName - Name of VxD
|
|
|
|
RETURNS: valid HANDLE if successful or NULL
|
|
|
|
COMMENTS:
|
|
|
|
****************************************************************************/
|
|
HANDLE WINAPI GetDevice(
|
|
IN const char* vxdName)
|
|
{
|
|
char fileName[64];
|
|
HANDLE retVal;
|
|
|
|
if (g_ForceFeedbackDevice.IsOSNT5()) { // Need to start MSGameIO
|
|
try {
|
|
// Open the Service Control Managere
|
|
SC_HANDLE serviceControlManager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
|
if (serviceControlManager == NULL) {
|
|
throw 0;
|
|
}
|
|
// Open the Service
|
|
SC_HANDLE ring0DriverService = ::OpenService(serviceControlManager, vxdName, SERVICE_QUERY_STATUS | SERVICE_START);
|
|
if (ring0DriverService == NULL) {
|
|
throw 0;
|
|
}
|
|
// Start for service
|
|
if (!::StartService(ring0DriverService, 0, NULL)) {
|
|
throw 0;
|
|
}
|
|
// Did it start yet - Do some fancy waiting
|
|
SERVICE_STATUS serviceStatus;
|
|
DWORD lastCheckPoint = 0;
|
|
do {
|
|
if (!::QueryServiceStatus(ring0DriverService, &serviceStatus)) {
|
|
throw 0;
|
|
}
|
|
if (serviceStatus.dwCurrentState == SERVICE_START_PENDING) {
|
|
if (serviceStatus.dwCheckPoint <= lastCheckPoint) {
|
|
DebugOut("Failed to start service\r\n");
|
|
break;
|
|
}
|
|
lastCheckPoint = serviceStatus.dwCheckPoint;
|
|
::Sleep(serviceStatus.dwWaitHint);
|
|
} else {
|
|
DebugOut("Service Started (maybe), Yeah!\r\n");
|
|
break;
|
|
}
|
|
} while (1);
|
|
::CloseServiceHandle(ring0DriverService); // Close the Ring0 Handle
|
|
::CloseServiceHandle(serviceControlManager); // Close the service control manager handle
|
|
} catch(...) {
|
|
DWORD errorCode = ::GetLastError();
|
|
if (errorCode == ERROR_ACCESS_DENIED) { // We are screwed
|
|
DebugOut("Access is denied\r\n");
|
|
} else {
|
|
DebugOut("Unable to start service\r\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
wsprintf(fileName, "\\\\.\\%s", vxdName);
|
|
retVal = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE,
|
|
0, 0, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0);
|
|
#ifdef _DEBUG
|
|
wsprintf(g_cMsg, "GetDevice: %s -- Vxd Handle: 0x%X\r\n", vxdName, retVal);
|
|
OutputDebugString(g_cMsg);
|
|
#endif
|
|
return retVal;
|
|
}
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: CloseDevice
|
|
|
|
PARAMETERS: IN HANDLE hVxD - valid VxD Handle
|
|
|
|
RETURNS: BOOL TRUE if successful else FALSE
|
|
|
|
COMMENTS:
|
|
|
|
****************************************************************************/
|
|
BOOL WINAPI CloseDevice(
|
|
IN HANDLE hVxD)
|
|
{
|
|
if (hVxD != INVALID_HANDLE_VALUE)
|
|
return (CloseHandle(hVxD));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: QueryDriverVersion
|
|
|
|
PARAMETERS: DWORD& major, DWORD& minor - Major and Minor parts of driver version
|
|
|
|
RETURNS: BOOL TRUE if successful else FALSE
|
|
|
|
COMMENTS:
|
|
|
|
****************************************************************************/
|
|
HRESULT QueryDriverVersion(DWORD& major, DWORD& minor)
|
|
{
|
|
if ((g_pJoltMidi == NULL) || (g_pJoltMidi->VxDHandleOf() == INVALID_HANDLE_VALUE)) {
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
DWORD version = 0x00000000;
|
|
DWORD bytesReturned = 0;
|
|
// HRESULT hr = DeviceIoControl(g_pJoltMidi->VxDHandleOf(), DIOC_GETVERSION, NULL, 0, &version, 4, &bytesReturned, NULL);
|
|
if (::DeviceIoControl(g_pJoltMidi->VxDHandleOf(), IOCTL_GET_VERSION, NULL, 0, &version, 4, &bytesReturned, NULL)) {
|
|
major = (version >> 16) & 0x0000FFFF;
|
|
minor = version & 0x0000FFFF;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: GetDataPacket
|
|
|
|
PARAMETERS: IN HANDLE hVxD - valid VxD Handle
|
|
IN OUT PJOYCHANNELDATA pDataPacket - Pointer to JOYCHANNELDATA
|
|
structure
|
|
|
|
RETURNS: SUCCESS or error code
|
|
|
|
COMMENTS: No longer a valid IOCTL (mlc)
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI GetDataPacket(
|
|
IN HANDLE hDevice,
|
|
IN OUT PJOYCHANNELDATA pDataPacket)
|
|
{
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: GetStatusPacket
|
|
|
|
PARAMETERS: IN HANDLE hVxD - valid VxD Handle
|
|
IN OUT PJOYCHANNELSTATUS pStatusPacket - Pointer to
|
|
JOYCHANNELSTATUS structure
|
|
|
|
RETURNS: SUCCESS or error code
|
|
|
|
COMMENTS:
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI GetStatusPacket(
|
|
IN HANDLE hDevice,
|
|
IN OUT PJOYCHANNELSTATUS pStatusPacket)
|
|
{
|
|
DWORD dwBytesReturned;
|
|
|
|
if (INVALID_HANDLE_VALUE == hDevice) {
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
if (pStatusPacket->cBytes != sizeof(JOYCHANNELSTATUS)) {
|
|
return (SFERR_INVALID_STRUCT_SIZE);
|
|
}
|
|
|
|
DWORD ioctlID = (g_ForceFeedbackDevice.GetDriverVersionMajor() > 1) ? IOCTL_SWFORCE_GETSTATUS : IOCTL_GET_STATUSPACKET;
|
|
for (int i=0; i < MAX_GET_STATUS_PACKET_RETRY_COUNT; i++) {
|
|
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwGetStatusPacketDelay);
|
|
|
|
// Send the IOCTL
|
|
BOOL bRetFlag = DeviceIoControl(hDevice,
|
|
ioctlID,
|
|
(LPVOID) pStatusPacket,
|
|
(DWORD) sizeof(JOYCHANNELSTATUS),
|
|
(LPVOID) pStatusPacket,
|
|
(DWORD) sizeof(JOYCHANNELSTATUS),
|
|
(LPDWORD) &dwBytesReturned,
|
|
(LPOVERLAPPED) NULL);
|
|
|
|
|
|
if (bRetFlag) {
|
|
// Convert values to a signed LONG
|
|
pStatusPacket->dwXVel = (LONG)((char)(pStatusPacket->dwXVel));
|
|
pStatusPacket->dwYVel = (LONG)((char)(pStatusPacket->dwYVel));
|
|
pStatusPacket->dwXAccel = (LONG)((char)(pStatusPacket->dwXAccel));
|
|
pStatusPacket->dwXAccel = (LONG)((char)(pStatusPacket->dwYAccel));
|
|
return SUCCESS;
|
|
}
|
|
if(i>5) {
|
|
Sleep(1);
|
|
}
|
|
|
|
}
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: GetIDPacket
|
|
|
|
PARAMETERS: IN HANDLE hVxD - valid VxD Handle
|
|
IN OUT PPRODUCT_ID pID - Pointer to PRODUCT_ID structure
|
|
|
|
RETURNS: SUCCESS or error code
|
|
|
|
COMMENTS:
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI GetIDPacket(
|
|
IN HANDLE hDevice,
|
|
IN OUT PPRODUCT_ID pID)
|
|
{
|
|
DWORD dwBytesReturned;
|
|
|
|
if (INVALID_HANDLE_VALUE == hDevice)
|
|
return SFERR_DRIVER_ERROR;
|
|
|
|
if (pID->cBytes != sizeof(PRODUCT_ID))
|
|
return (SFERR_INVALID_STRUCT_SIZE);
|
|
|
|
JOYCHANNELID IDPacket = {sizeof(JOYCHANNELID)};
|
|
|
|
DWORD ioctlID = (g_ForceFeedbackDevice.GetDriverVersionMajor() > 1) ? IOCTL_SWFORCE_GETID : IOCTL_GET_IDPACKET;
|
|
for (int i=0; i<MAX_RETRY_COUNT; i++)
|
|
{
|
|
// Send the IOCTL
|
|
BOOL bRetFlag = DeviceIoControl(hDevice,
|
|
ioctlID,
|
|
(LPVOID) &IDPacket,
|
|
(DWORD) sizeof(JOYCHANNELID),
|
|
(LPVOID) &IDPacket,
|
|
(DWORD) sizeof(JOYCHANNELID),
|
|
(LPDWORD) &dwBytesReturned,
|
|
(LPOVERLAPPED) NULL);
|
|
|
|
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwGetIDPacketDelay);
|
|
|
|
// Any error codes are returned in the first DWORD of the structure
|
|
if (bRetFlag) {
|
|
pID->dwProductID = IDPacket.dwProductID & FW_PRODUCT_ID;
|
|
pID->dwFWMajVersion = 1;
|
|
if (IDPacket.dwFWVersion & FW_MAJOR_VERSION)
|
|
pID->dwFWMajVersion++;
|
|
pID->dwFWMinVersion = IDPacket.dwFWVersion & FW_MINOR_VERSION;
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: GetDiagnostics
|
|
|
|
PARAMETERS: IN HANDLE hVxD - valid VxD Handle
|
|
IN OUT PDIAGNOSTIC_COUNTER pDiagnostics - Pointer to
|
|
DIAGNOSTIC_COUNTER structure
|
|
|
|
RETURNS: SUCCESS or error code
|
|
|
|
COMMENTS:
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI GetDiagnostics(
|
|
IN HANDLE hDevice,
|
|
IN OUT PDIAGNOSTIC_COUNTER pDiagnostics)
|
|
{
|
|
DWORD dwBytesReturned;
|
|
BOOL bRetFlag;
|
|
|
|
if (INVALID_HANDLE_VALUE == hDevice)
|
|
return (SFERR_DRIVER_ERROR);
|
|
|
|
if (pDiagnostics->cBytes != sizeof(DIAGNOSTIC_COUNTER))
|
|
return (SFERR_INVALID_STRUCT_SIZE);
|
|
|
|
// Send the IOCTL
|
|
bRetFlag = DeviceIoControl(hDevice,
|
|
(DWORD) IOCTL_GET_DIAGNOSTICS,
|
|
(LPVOID) pDiagnostics,
|
|
(DWORD) sizeof(DIAGNOSTIC_COUNTER),
|
|
(LPVOID) pDiagnostics,
|
|
(DWORD) sizeof(DIAGNOSTIC_COUNTER),
|
|
(LPDWORD) &dwBytesReturned,
|
|
(LPOVERLAPPED) NULL);
|
|
// Any error codes are returned in the first DWORD of the structure
|
|
if (!bRetFlag || (dwBytesReturned != sizeof(DIAGNOSTIC_COUNTER)) )
|
|
{
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
return (SUCCESS);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: GetAckNack
|
|
|
|
PARAMETERS: IN HANDLE hVxD - valid VxD Handle
|
|
IN OUT PACKNACK pAckNack - Pointer to ACKNACK structure
|
|
|
|
RETURNS: SUCCESS or error code
|
|
|
|
COMMENTS:
|
|
typedef struct _ACKNACK {
|
|
DWORD cBytes;
|
|
DWORD dwAckNack; //ACK, NACK
|
|
DWORD dwErrorCode;
|
|
DWORD dwEffectStatus; //SWDEV_STS_EFFECT_RUNNING||SWDEV_STS_EFFECT_STOPPED
|
|
} ACKNACK, *PACKNACK;
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI GetAckNack(
|
|
IN HANDLE hDevice,
|
|
IN OUT PACKNACK pAckNack,
|
|
IN USHORT regindex)
|
|
{
|
|
if (INVALID_HANDLE_VALUE == hDevice) {
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
if (pAckNack->cBytes != sizeof(ACKNACK)) {
|
|
return SFERR_INVALID_STRUCT_SIZE;
|
|
}
|
|
|
|
switch (g_ForceFeedbackDevice.GetAckNackMethod(regindex)) {
|
|
case ACKNACK_NOTHING: {
|
|
pAckNack->dwAckNack = ACK;
|
|
pAckNack->dwErrorCode = 0;
|
|
return SUCCESS;
|
|
}
|
|
case ACKNACK_BUTTONSTATUS: {
|
|
DWORD dwBytesReturned;
|
|
BOOL bRetFlag;
|
|
DWORD dwIn;
|
|
|
|
DWORD ioctlID = (g_ForceFeedbackDevice.GetDriverVersionMajor() > 1) ? IOCTL_SWFORCE_GETACKNACK : IOCTL_GET_ACKNACK;
|
|
|
|
// Send the IOCTL
|
|
bRetFlag = DeviceIoControl(hDevice,
|
|
ioctlID,
|
|
(LPVOID) &dwIn,
|
|
(DWORD) sizeof(DWORD),
|
|
(LPVOID) &dwIn,
|
|
(DWORD) sizeof(DWORD),
|
|
(LPDWORD) &dwBytesReturned,
|
|
(LPOVERLAPPED) NULL);
|
|
|
|
if (!bRetFlag || (dwBytesReturned != sizeof(DWORD)) ) {
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
|
|
if (((g_ForceFeedbackDevice.GetDriverVersionMajor() == 1) && (dwIn & ACKNACK_MASK_1XX))
|
|
|| ((g_ForceFeedbackDevice.GetDriverVersionMajor() != 1) && (dwIn & ACKNACK_MASK_200))) { // NACK error, so get Error code
|
|
pAckNack->dwAckNack = NACK;
|
|
JOYCHANNELSTATUS StatusPacket = {sizeof(JOYCHANNELSTATUS)};
|
|
if (FAILED(GetStatusPacket(hDevice, &StatusPacket))) {
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
pAckNack->dwErrorCode = (StatusPacket.dwDeviceStatus & ERROR_STATUS_MASK);
|
|
return SUCCESS;
|
|
}
|
|
// ACK success
|
|
pAckNack->dwAckNack = ACK;
|
|
pAckNack->dwErrorCode = 0;
|
|
|
|
if (((g_ForceFeedbackDevice.GetDriverVersionMajor() == 1) && (dwIn & RUNNING_MASK_1XX))
|
|
|| ((g_ForceFeedbackDevice.GetDriverVersionMajor() != 1) && (dwIn & RUNNING_MASK_200))) {
|
|
pAckNack->dwEffectStatus = SWDEV_STS_EFFECT_RUNNING;
|
|
} else {
|
|
pAckNack->dwEffectStatus = SWDEV_STS_EFFECT_STOPPED;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
case ACKNACK_STATUSPACKET: {
|
|
// Use the Status Packet Error code field to determine ACK or NACK
|
|
// Get Error code
|
|
JOYCHANNELSTATUS StatusPacket = {sizeof(JOYCHANNELSTATUS)};
|
|
|
|
HRESULT hRet = GetStatusPacket(hDevice, &StatusPacket); // Retry count in GetStatusPacket function
|
|
if (FAILED(hRet)) {
|
|
DebugOut("GetStatusPacket Error\n");
|
|
hRet = SFERR_DRIVER_ERROR;
|
|
} else {
|
|
pAckNack->dwErrorCode = StatusPacket.dwDeviceStatus & ERROR_STATUS_MASK;
|
|
pAckNack->dwAckNack = (pAckNack->dwErrorCode) ? NACK : ACK;
|
|
}
|
|
return hRet;
|
|
}
|
|
default: { // Someone put garbage in the registry (do nothing)
|
|
pAckNack->dwAckNack = ACK;
|
|
pAckNack->dwErrorCode = 0;
|
|
return SUCCESS;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: GetStatusGateData
|
|
|
|
PARAMETERS: IN HANDLE hVxD - valid VxD Handle
|
|
IN OUT DWORD *pdwStatusGateData - Pointer to Status Gate
|
|
|
|
RETURNS: SUCCESS or error code
|
|
|
|
COMMENTS:
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI GetStatusGateData(
|
|
IN HANDLE hDevice,
|
|
IN OUT DWORD *pdwStatusGateData)
|
|
{
|
|
DWORD dwBytesReturned;
|
|
BOOL bRetFlag;
|
|
DWORD dwIn;
|
|
|
|
HRESULT hRet = SFERR_DRIVER_ERROR;
|
|
if (INVALID_HANDLE_VALUE == hDevice)
|
|
return (hRet);
|
|
|
|
if (NULL == pdwStatusGateData)
|
|
return (SFERR_INVALID_PARAM);
|
|
|
|
DWORD ioctlID = (g_ForceFeedbackDevice.GetDriverVersionMajor() > 1) ? IOCTL_SWFORCE_GETACKNACK : IOCTL_GET_ACKNACK;
|
|
for (int i=0; i<MAX_RETRY_COUNT; i++)
|
|
{
|
|
// Obtain Status Gate data
|
|
// Send the IOCTL
|
|
bRetFlag = DeviceIoControl(hDevice,
|
|
ioctlID,
|
|
(LPVOID) &dwIn,
|
|
(DWORD) sizeof(DWORD),
|
|
(LPVOID) &dwIn,
|
|
(DWORD) sizeof(DWORD),
|
|
(LPDWORD) &dwBytesReturned,
|
|
(LPOVERLAPPED) NULL);
|
|
|
|
Sleep(g_pJoltMidi->DelayParamsPtrOf()->dwGetStatusGateDataDelay);
|
|
|
|
|
|
if (bRetFlag && (dwBytesReturned == sizeof(DWORD)))
|
|
{
|
|
hRet = SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
*pdwStatusGateData = dwIn;
|
|
return (hRet);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: SendBackDoorShortMidi
|
|
|
|
PARAMETERS: IN HANDLE hDevice - Handle to Vxd
|
|
IN ULONG ulData - DWORD to send
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI SendBackDoorShortMidi(
|
|
IN HANDLE hDevice,
|
|
IN ULONG ulData)
|
|
{
|
|
#ifdef _DEBUG
|
|
// wsprintf(g_cMsg, "SendBackDoorShortMidi Data=%.8lx\r\n", ulData);
|
|
// OutputDebugString(g_cMsg);
|
|
#endif
|
|
DWORD dwIn;
|
|
DWORD bytesReturned;
|
|
|
|
// Byte count
|
|
int numBytes = 3;
|
|
DWORD cmd = ulData & 0xF0;
|
|
if ((cmd == 0xC0 ) || (cmd == 0xD0)) {
|
|
numBytes = 2;
|
|
}
|
|
|
|
// Send via data transmitter
|
|
if (g_pDataTransmitter != NULL) {
|
|
g_PreviousShortMidi = ulData;
|
|
if (g_pDataTransmitter->Send((BYTE*)(&ulData), numBytes)) {
|
|
return (SUCCESS);
|
|
}
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
|
|
// Is there a proper ring0 driver?
|
|
if (INVALID_HANDLE_VALUE == hDevice) {
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
|
|
// Send via new single send IOCTL
|
|
if (g_ForceFeedbackDevice.GetDriverVersionMajor() > 1) {
|
|
if (DeviceIoControl(hDevice, IOCTL_SWFORCE_SENDDATA, (void*)&ulData, DWORD(numBytes),
|
|
(void*)&dwIn, sizeof(DWORD), (DWORD*)&bytesReturned,
|
|
(LPOVERLAPPED) NULL)) {
|
|
if (bytesReturned == DWORD(numBytes)) {
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
// Send the IOCTL the old way
|
|
if (DeviceIoControl(hDevice, IOCTL_MIDISENDSHORTMSG, (void*)&ulData, sizeof(DWORD),
|
|
(void*)&dwIn, sizeof(DWORD), &bytesReturned,
|
|
(LPOVERLAPPED) NULL)) {
|
|
if (bytesReturned == sizeof(DWORD)) {
|
|
return (SUCCESS);
|
|
|
|
}
|
|
}
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: SendBackDoorLongMidi
|
|
|
|
PARAMETERS: IN HANDLE hDevice - Handle to Vxd
|
|
IN ULONG ulData - DWORD to send
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI SendBackDoorLongMidi(
|
|
IN HANDLE hDevice,
|
|
IN PBYTE pData)
|
|
{
|
|
#ifdef _VERBOSE
|
|
#pragma message("Compiling with VERBOSE mode")
|
|
#ifdef _DEBUG
|
|
wsprintf(g_cMsg, "SendBackDoorLongMidi pData\n%.2x ", pData[0]);
|
|
OutputDebugString(g_cMsg);
|
|
int i=1;
|
|
while(TRUE)
|
|
{
|
|
wsprintf(g_cMsg,"%.2x ", pData[i]);
|
|
OutputDebugString(g_cMsg);
|
|
if (pData[i] & 0x80)
|
|
break;
|
|
else
|
|
i++;
|
|
}
|
|
OutputDebugString("\n");
|
|
#endif
|
|
|
|
#endif
|
|
DWORD dwIn;
|
|
DWORD bytesReturned;
|
|
|
|
// Count the bytes
|
|
int numBytes = 1;
|
|
while (!(pData[numBytes++] & 0x80));
|
|
|
|
// Send via data transmitter?
|
|
if (g_pDataTransmitter != NULL) {
|
|
if (g_pDataTransmitter->Send(pData, numBytes)) {
|
|
return (SUCCESS);
|
|
}
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
|
|
// Is there a proper ring0 driver?
|
|
if (INVALID_HANDLE_VALUE == hDevice) {
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
|
|
// Send via new single send IOCTL
|
|
if (g_ForceFeedbackDevice.GetDriverVersionMajor() > 1) {
|
|
if (DeviceIoControl(hDevice, IOCTL_SWFORCE_SENDDATA, (void*)pData, DWORD(numBytes),
|
|
(void*)&dwIn, sizeof(DWORD), (DWORD*)&bytesReturned,
|
|
(LPOVERLAPPED) NULL)) {
|
|
if (bytesReturned == DWORD(numBytes)) {
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
// Send the IOCTL the old way
|
|
if (DeviceIoControl(hDevice, IOCTL_MIDISENDLONGMSG, (void*)pData, sizeof(DWORD),
|
|
(void*)&dwIn, sizeof(DWORD), (DWORD*)&bytesReturned,
|
|
(LPOVERLAPPED) NULL)) {
|
|
if (bytesReturned == sizeof(DWORD)) {
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
return SFERR_DRIVER_ERROR;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: SetMidiPort
|
|
|
|
PARAMETERS: IN HANDLE hDevice - Handle to Vxd
|
|
IN ULONG ulPort - Port #
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
0 = DEFAULT MIDI UART 330
|
|
1 = COM1
|
|
2 = COM2
|
|
3 = COM3
|
|
4 = COM4
|
|
or other MIDI port 340, etc...
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI SetMidiPort(
|
|
IN HANDLE hDevice,
|
|
IN ULONG ulPort)
|
|
{
|
|
if (g_ForceFeedbackDevice.IsOSNT5()) {
|
|
return SUCCESS;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
wsprintf(g_cMsg, "SetMidiPort Port %lx\r\n", ulPort);
|
|
OutputDebugString(g_cMsg);
|
|
#endif
|
|
DWORD dwBytesReturned;
|
|
BOOL bRetFlag;
|
|
DWORD dwIn;
|
|
|
|
if (INVALID_HANDLE_VALUE == hDevice)
|
|
return (SFERR_DRIVER_ERROR);
|
|
|
|
DWORD ioctlID = (g_ForceFeedbackDevice.GetDriverVersionMajor() > 1) ? IOCTL_SWFORCE_SETPORT : IOCTL_SET_MIDIPORT;
|
|
|
|
// Send the IOCTL
|
|
bRetFlag = DeviceIoControl(hDevice,
|
|
ioctlID,
|
|
(LPVOID) &ulPort,
|
|
(DWORD) sizeof(DWORD),
|
|
(LPVOID) &dwIn,
|
|
(DWORD) sizeof(DWORD),
|
|
(LPDWORD) &dwBytesReturned,
|
|
(LPOVERLAPPED) NULL);
|
|
|
|
if (!bRetFlag || (dwBytesReturned != sizeof(DWORD)) )
|
|
{
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
return (SUCCESS);
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: JoltHWReset
|
|
|
|
PARAMETERS: IN HANDLE hDevice - Handle to Vxd
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
Jolt is Reset (4 knocks)
|
|
|
|
****************************************************************************/
|
|
HRESULT WINAPI JoltHWReset(
|
|
IN HANDLE hDevice)
|
|
{
|
|
#ifdef _DEBUG
|
|
wsprintf(g_cMsg, "JoltHWReset\r\n");
|
|
OutputDebugString(g_cMsg);
|
|
#endif
|
|
|
|
DWORD dwBytesReturned;
|
|
BOOL bRetFlag;
|
|
DWORD dwIn;
|
|
|
|
if (INVALID_HANDLE_VALUE == hDevice)
|
|
return (SFERR_DRIVER_ERROR);
|
|
|
|
DWORD ioctlID = (g_ForceFeedbackDevice.GetDriverVersionMajor() > 1) ? IOCTL_SWFORCE_RESET : IOCTL_HW_RESET;
|
|
|
|
// Send the IOCTL
|
|
bRetFlag = DeviceIoControl(hDevice,
|
|
ioctlID,
|
|
(LPVOID) NULL,
|
|
(DWORD) sizeof(DWORD),
|
|
(LPVOID) &dwIn,
|
|
(DWORD) sizeof(DWORD),
|
|
(LPDWORD) &dwBytesReturned,
|
|
(LPOVERLAPPED) NULL);
|
|
|
|
if (!bRetFlag || (dwBytesReturned != sizeof(DWORD)) )
|
|
{
|
|
return (SFERR_DRIVER_ERROR);
|
|
}
|
|
return (SUCCESS);
|
|
}
|
|
|
|
#endif
|