Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1012 lines
31 KiB

//@doc
/******************************************************
**
** @module DTRANS.CPP | DataTransmitter implementation file
**
** Description:
**
** History:
** Created 11/13/97 Matthew L. Coill (mlc)
**
** 21-Mar-99 waltw Removed unused ReportTransmission (Win9x only)
** 22-Mar-99 waltw Added DWORD dwDeviceID param to Initialize
** members of DataTransmitter and derived classes
**
** (c) 1986-1999 Microsoft Corporation. All Rights Reserved.
******************************************************/
#include "FFDevice.h"
#include "DTrans.h"
#include "DPack.h"
#include "WinIOCTL.h" // For IOCTLs
#include "VxDIOCTL.hpp"
#include "SW_error.hpp"
#include "midi_obj.hpp"
#include "joyregst.hpp"
#include "CritSec.h"
DataTransmitter* g_pDataTransmitter = NULL;
extern CJoltMidi *g_pJoltMidi;
#ifdef _DEBUG
extern void DebugOut(LPCTSTR szDebug);
#else !_DEBUG
#define DebugOut(x)
#endif _DEBUG
const char cCommPortNames[4][5] = { "COM1", "COM2", "COM3", "COM4" };
const unsigned short c1_16_BytesPerShot = 3;
const DWORD c1_16_SerialSleepTime = 1;
/****************** DataTransmitter class ***************/
HRESULT DataTransmitter::Transmit(ACKNACK& ackNack)
{
ackNack.cBytes = 0; // Indicated not valid (ack/nack not done)
if (g_pDataPackager == NULL) {
ASSUME_NOT_REACHED();
return SFERR_DRIVER_ERROR;
}
if (NULL == g_pJoltMidi) return (SFERR_DRIVER_ERROR);
BOOL forcedToggle = FALSE;
if (m_NackToggle == 2) { // When Not yet sunk up == 2, probably initializing if 2 (synch up)
ULONG portByte = 0;
g_pDriverCommunicator->GetPortByte(portByte); // don't care about success, always fails on old driver
if (portByte & STATUS_GATE_200) {
SetNextNack(1);
} else {
SetNextNack(0);
}
forcedToggle = TRUE;
}
DataPacket* pNextPacket = NULL;
for (USHORT packetIndex = 0; packetIndex < g_pDataPackager->GetNumDataPackets(); packetIndex++) {
pNextPacket = g_pDataPackager->GetPacket(packetIndex);
ASSUME_NOT_NULL(pNextPacket);
if (pNextPacket == NULL) {
return SFERR_DRIVER_ERROR;
}
BOOL success = FALSE;
int retries = int(pNextPacket->m_NumberOfRetries);
do {
m_NackToggle = (m_NackToggle + 1) % 2; // Verions 2.0 switches button-line ack/nack methods each time
ULONG portByte = 0;
BOOL error = FALSE;
if (g_pDriverCommunicator->GetPortByte(portByte) == SUCCESS) { // Will fail on old driver
if (portByte & STATUS_GATE_200) { // Line is high
if (m_NackToggle != 0) { // We should be expecting low
m_NackToggle = 0; // Update it if wrong
error = TRUE;
DebugOut("SW_WHEEL.DLL: Status Gate is out of Synch (High - Expecting Low)!!!\r\n");
}
} else { // Line is low
if (m_NackToggle != 1) { // We should be expecting high
m_NackToggle = 1; // Update it if wrong
error = TRUE;
DebugOut("SW_WHEEL.DLL: Status Gate is out of Synch (Low - Expecting High)!!!\r\n");
}
}
}
Send(pNextPacket->m_pData, pNextPacket->m_BytesOfData);
if (pNextPacket->m_AckNackDelay != 0) {
Sleep(pNextPacket->m_AckNackDelay);
}
ackNack.cBytes = sizeof(ACKNACK);
HRESULT hr = g_pJoltMidi->GetAckNackData(pNextPacket->m_AckNackTimeout, &ackNack, (USHORT)pNextPacket->m_AckNackMethod);
if (forcedToggle == TRUE) {
m_NackToggle = 2;
}
if (hr != SUCCESS) {
return SFERR_DRIVER_ERROR;
}
success = (ackNack.dwAckNack == ACK);
if (success == FALSE) { // We don't want to bother retrying on certian error codes, retrying is worthless
success = ((ackNack.dwErrorCode == DEV_ERR_MEM_FULL_200) || (ackNack.dwErrorCode == DEV_ERR_PLAY_FULL_200) || (ackNack.dwErrorCode == DEV_ERR_INVALID_ID_200));
}
} while (!success && (--retries > 0));
if (ackNack.dwAckNack == NACK) {
return SFERR_DEVICE_NACK;
}
}
g_pDataPackager->ClearPackets();
return SUCCESS;
}
/****************** SerialDataTransmitter class ***************/
/******************************************************
**
** SerialDataTransmitter::SerialDataTransmitter()
**
** @mfunc Constructor.
**
******************************************************/
SerialDataTransmitter::SerialDataTransmitter() : DataTransmitter(),
m_SerialPort(INVALID_HANDLE_VALUE),
m_SerialPortIDHack(0)
{
}
/******************************************************
**
** SerialDataTransmitter::~SerialDataTransmitter()
**
** @mfunc Destructor.
**
******************************************************/
SerialDataTransmitter::~SerialDataTransmitter()
{
if (m_SerialPort != INVALID_HANDLE_VALUE) {
if (::CloseHandle(m_SerialPort) == FALSE) {
// ASSUME_NOT_REACHED();
}
m_SerialPort = INVALID_HANDLE_VALUE;
}
}
/******************************************************
**
** SerialDataTransmitter::Initialize()
**
** returns: TRUE if initialized FALSE if not able to initialize
** @mfunc Initialize.
**
******************************************************/
BOOL SerialDataTransmitter::Initialize(DWORD dwDeviceID)
{
// If already open, close for reinitialization
if (m_SerialPort != INVALID_HANDLE_VALUE) {
if (CloseHandle(m_SerialPort) == FALSE) {
// ASSUME_NOT_REACHED();
}
m_SerialPort = INVALID_HANDLE_VALUE;
}
for (unsigned int portNum = 0; portNum < 4; portNum++) {
DebugOut(cCommPortNames[portNum]);
DebugOut(":\r\n");
m_SerialPort = ::CreateFile(cCommPortNames[portNum], GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (m_SerialPort != INVALID_HANDLE_VALUE) {
DCB CommDCB;
if (::GetCommState(m_SerialPort, &CommDCB)) {
#ifdef _DEBUG
char dbgout[255];
wsprintf(dbgout, "Baud Rate = 0x%08X (38400 = 0x%08X)\r\n", CommDCB.BaudRate, CBR_38400);
_RPT0(_CRT_WARN, dbgout);
#endif _DEBUG
CommDCB.BaudRate = CBR_38400;
CommDCB.StopBits = ONESTOPBIT;
CommDCB.ByteSize = 8;
CommDCB.Parity = NOPARITY;
if (!::SetCommState(m_SerialPort, &CommDCB)) {
DebugOut("Unabled to set baud rate\r\n");
}
}
::GetCommState(m_SerialPort, &CommDCB);
if (g_ForceFeedbackDevice.DetectHardware()) {
m_SerialPortIDHack = portNum + 1;
// Write to shared file
DebugOut(" Opened and FFDev Detected\r\n");
break; // Exit from for loop
}
// Not found
::CloseHandle(m_SerialPort);
DebugOut(" Opened but FFDev NOT detected\r\n");
m_SerialPort = INVALID_HANDLE_VALUE;
} else {
DebugOut(" Not able to open\r\n");
}
}
if (m_SerialPort != INVALID_HANDLE_VALUE) { // Found it
DWORD oldPortID;
DWORD oldAccessMethod;
joyGetForceFeedbackCOMMInterface(dwDeviceID, &oldAccessMethod, &oldPortID);
DWORD accessMethod = (oldAccessMethod & (MASK_OVERRIDE_MIDI_PATH | MASK_SERIAL_BACKDOOR)) | COMM_SERIAL_FILE;
if ((accessMethod != oldAccessMethod) || (portNum != oldPortID)) {
joySetForceFeedbackCOMMInterface(dwDeviceID, accessMethod, portNum);
}
return TRUE;
}
return FALSE;
}
/******************************************************
**
** SerialDataTransmitter::Send()
**
** returns: TRUE if all data was successfully sent
** @mfunc Send.
**
******************************************************/
BOOL SerialDataTransmitter::Send(BYTE* data, UINT numBytes) const
{
// Do we have a valid serial port (hopefully with MS FF device connected)
if (m_SerialPort == NULL) {
return FALSE;
}
if ((g_ForceFeedbackDevice.GetFirmwareVersionMajor() == 1) && (g_ForceFeedbackDevice.GetFirmwareVersionMinor() == 16)) {
DWORD subTotalWritten;
DWORD totalWritten = 0;
DWORD numLeft = numBytes;
while (numLeft > c1_16_BytesPerShot) {
if (::WriteFile(m_SerialPort, (data + totalWritten), c1_16_BytesPerShot, &subTotalWritten, NULL) == FALSE) {
return FALSE;
}
totalWritten += subTotalWritten;
numLeft -= subTotalWritten;
Sleep(c1_16_SerialSleepTime);
}
if (numLeft > 0) {
if (::WriteFile(m_SerialPort, (data + totalWritten), numLeft, &subTotalWritten, NULL) == FALSE) {
return FALSE;
}
totalWritten += subTotalWritten;
}
return (totalWritten == numBytes);
}
// Firmware other than 1.16
DWORD numWritten;
if (::WriteFile(m_SerialPort, data, numBytes, &numWritten, NULL) == FALSE) {
return FALSE;
}
return (numWritten == numBytes);
}
/****************** WinMMDataTransmitter class ******************/
/******************************************************
**
** WinMMDataTransmitter::WinMMDataTransmitter()
**
** @mfunc Constructor.
**
******************************************************/
WinMMDataTransmitter::WinMMDataTransmitter() : DataTransmitter(),
m_MidiOutHandle(NULL)
{
// Check for callback event
m_EventMidiOutputFinished = OpenEvent(EVENT_ALL_ACCESS, FALSE, SWFF_MIDIEVENT);
if (m_EventMidiOutputFinished == NULL) { // Event not yet created
m_EventMidiOutputFinished = CreateEvent(NULL, TRUE, FALSE, SWFF_MIDIEVENT);
}
}
/******************************************************
**
** WinMMDataTransmitter::~WinMMDataTransmitter()
**
** @mfunc Destructor.
**
******************************************************/
WinMMDataTransmitter::~WinMMDataTransmitter()
{
// Kill MidiOutputEvent
if (m_EventMidiOutputFinished != NULL) {
CloseHandle(m_EventMidiOutputFinished);
m_EventMidiOutputFinished = NULL;
}
// Close MidiHandle -- Check shared memory
if (m_MidiOutHandle != NULL) {
if ((NULL != g_pJoltMidi) && (g_pJoltMidi->GetSharedMemoryReferenceCount() == 0)) { // Just me (reference count has already been lowered for me)
// Reset, close and release Midi Handles
::midiOutReset(m_MidiOutHandle);
::midiOutClose(m_MidiOutHandle);
m_MidiOutHandle = NULL;
} else {
DebugOut("SW_WHEEL.DLL: Cannot close midi in use by another process\r\n");
}
}
}
/******************************************************
**
** WinMMDataTransmitter::Initialize()
**
** returns: TRUE if initialized FALSE if not able to initialize
** @mfunc Initialize.
**
******************************************************/
BOOL WinMMDataTransmitter::Initialize(DWORD dwDeviceID)
{
// Wouldn't want to people initializing at the same time
g_CriticalSection.Enter();
if (NULL == g_pJoltMidi)
{
g_CriticalSection.Leave();
return (FALSE);
}
// Check to see if another task has already opened MidiPort
if (g_pJoltMidi->MidiOutHandleOf() != NULL) {
m_MidiOutHandle = g_pJoltMidi->MidiOutHandleOf();
DebugOut("SW_WHEEL.DLL: Using winmm handle from another process\r\n");
g_CriticalSection.Leave();
return TRUE;
}
try {
UINT numMidiDevices = ::midiOutGetNumDevs();
if (numMidiDevices == 0) {
throw 0; // No devices to check
}
MIDIOUTCAPS midiOutCaps;
for (UINT midiDeviceID = 0; midiDeviceID < numMidiDevices; midiDeviceID++) {
// Get dev-caps
MMRESULT midiRet = ::midiOutGetDevCaps(midiDeviceID, &midiOutCaps, sizeof(midiOutCaps));
if (midiRet != MMSYSERR_NOERROR) {
throw 0; // Something went ugly - All ids should be valid upto numMidiDevs
}
// Midi hardware-port device (thats what we are looking for)
if (midiOutCaps.wTechnology == MOD_MIDIPORT) {
DebugOut("DetectMidiDevice: Opening WinMM Midi Output\n");
// Try to open the thing
UINT openRet = ::midiOutOpen(&m_MidiOutHandle, midiDeviceID, (DWORD) m_EventMidiOutputFinished, (DWORD) this, CALLBACK_EVENT);
// UINT openRet = ::midiOutOpen(&m_MidiOutHandle, midiDeviceID, (DWORD) NULL, (DWORD) this, CALLBACK_EVENT);
if ((openRet != MMSYSERR_NOERROR) || (m_MidiOutHandle == NULL)) {
throw 0; // Unable to open midi handle for midi-device
}
DebugOut("Open Midi Output - Success.\r\n");
if (g_ForceFeedbackDevice.DetectHardware()) {
// Found Microsoft FF hardware - Set all the stuff and return happy
g_pJoltMidi->SetMidiOutHandle(m_MidiOutHandle);
// Tell the Registry WinMM was okay
DWORD oldPortID;
DWORD oldAccessMethod;
joyGetForceFeedbackCOMMInterface(dwDeviceID, &oldAccessMethod, &oldPortID);
DWORD accessMethod = (oldAccessMethod & (MASK_OVERRIDE_MIDI_PATH | MASK_SERIAL_BACKDOOR)) | COMM_WINMM;
if ((accessMethod != oldAccessMethod) || (oldPortID != 0)) {
joySetForceFeedbackCOMMInterface(dwDeviceID, accessMethod, 0);
}
g_CriticalSection.Leave();
return TRUE;
}
// Not what we were looking for - close and continue
::midiOutClose(m_MidiOutHandle);
m_MidiOutHandle = NULL;
} // End of ModMidiPort found
} // End of for loop
throw 0; // Did not find MS FFDevice
} catch (...) {
m_MidiOutHandle = NULL;
DebugOut("Failure to initlaize WinMMDataTransmitter\r\n");
g_CriticalSection.Leave();
return FALSE;
}
}
/******************************************************
**
** WinMMDataTransmitter::MakeShortMessage()
**
** returns: DWORD WinMM MidiShort message
** @mfunc MakeShortMessage.
**
******************************************************/
DWORD WinMMDataTransmitter::MakeShortMessage(BYTE* data, UINT numBytes) const
{
DWORD shortMessage = data[0];
if (numBytes > 1) {
shortMessage |= (data[1] << 8);
if (numBytes < 2) {
shortMessage |= (data[2] << 16);
}
}
return shortMessage;
}
/******************************************************
**
** WinMMDataTransmitter::MakeLongMessageHeader()
**
** returns: SUCCESS indication and WinMM MidiLong message header
** @mfunc MakeLongMessageHeader.
**
******************************************************/
BOOL WinMMDataTransmitter::MakeLongMessageHeader(MIDIHDR& longHeader, BYTE* data, UINT numBytes) const
{
longHeader.lpData = LPSTR(data);
longHeader.dwBufferLength = numBytes;
longHeader.dwBytesRecorded = numBytes;
longHeader.dwFlags = 0;
longHeader.dwUser = 0;
longHeader.dwOffset = 0;
return (::midiOutPrepareHeader(m_MidiOutHandle, &longHeader, sizeof(MIDIHDR)) == MMSYSERR_NOERROR);
}
/******************************************************
**
** WinMMDataTransmitter::DestroyLongMessageHeader()
**
** returns: TRUE if header was unprepared
** @mfunc DestroyLongMessageHeader.
**
******************************************************/
BOOL WinMMDataTransmitter::DestroyLongMessageHeader(MIDIHDR& longHeader) const
{
return (::midiOutUnprepareHeader(m_MidiOutHandle, &longHeader, sizeof(MIDIHDR)) == MMSYSERR_NOERROR);
}
/******************************************************
**
** WinMMDataTransmitter::Send()
**
** returns: TRUE if all data was successfully sent
** @mfunc Send.
**
******************************************************/
BOOL WinMMDataTransmitter::Send(BYTE* data, UINT numBytes) const
{
// Do we have a valid midi port (hopefully with MS FF device connected)
if (m_MidiOutHandle == NULL) {
return FALSE;
}
// Sanity check
if ((data == NULL) || (numBytes == 0)) {
return FALSE;
}
// Clear the Event Callback
::ResetEvent(m_EventMidiOutputFinished);
// Short message
if (data[0] < 0xF0) {
DWORD shortMessage = MakeShortMessage(data, numBytes);
return (::midiOutShortMsg(m_MidiOutHandle, shortMessage) == MMSYSERR_NOERROR);
}
// Long message
BOOL retVal = FALSE;
MIDIHDR midiHeader;
if (MakeLongMessageHeader(midiHeader, data, numBytes)) {
retVal = (::midiOutLongMsg(m_MidiOutHandle, &midiHeader, sizeof(MIDIHDR)) == MMSYSERR_NOERROR);
DestroyLongMessageHeader(midiHeader);
if (retVal == FALSE) { // Didn't work, kick it
::midiOutReset(m_MidiOutHandle);
}
}
return retVal;
}
/******************************************************
**
** WinMMDataTransmitter::WaitTillSendFinished()
**
** returns: TRUE when all data is successfully sent or
** FALSE for timeOut
** @mfunc Send.
**
******************************************************/
BOOL WinMMDataTransmitter::WaitTillSendFinished(DWORD timeOut)
{
BOOL retVal = FALSE;
if (m_EventMidiOutputFinished != NULL) {
retVal = (::WaitForSingleObject(m_EventMidiOutputFinished, timeOut) == WAIT_OBJECT_0);
::ResetEvent(m_EventMidiOutputFinished);
}
return retVal;
}
/****************** BackdoorDataTransmitter class ***************/
/******************************************************
**
** BackdoorDataTransmitter::BackdoorDataTransmitter()
**
** @mfunc Constructor.
**
******************************************************/
BackdoorDataTransmitter::BackdoorDataTransmitter() : DataTransmitter(),
m_DataPort(INVALID_HANDLE_VALUE)
{
m_OldBackdoor = (g_ForceFeedbackDevice.GetDriverVersionMajor() == 1) && (g_ForceFeedbackDevice.GetDriverVersionMinor() == 0);
}
/******************************************************
**
** BackdoorDataTransmitter::~BackdoorDataTransmitter()
**
** @mfunc Destructor.
**
******************************************************/
BackdoorDataTransmitter::~BackdoorDataTransmitter()
{
if (m_DataPort != INVALID_HANDLE_VALUE) {
if (::CloseHandle(m_DataPort) == FALSE) {
// ASSUME_NOT_REACHED();
}
m_DataPort = INVALID_HANDLE_VALUE;
}
}
/******************************************************
**
** BackdoorDataTransmitter::Initialize()
**
** returns: This base class only does error checking on preset values
** @mfunc Initialize.
**
******************************************************/
BOOL BackdoorDataTransmitter::Initialize(DWORD dwDeviceID)
{
if (g_ForceFeedbackDevice.IsOSNT5()) {
return FALSE; // NT5 cannot use backdoor!
}
return TRUE;
}
/******************************************************
**
** BackdoorDataTransmitter::Send()
**
** returns: TRUE if all data was successfully sent
** @mfunc Send.
**
******************************************************/
BOOL BackdoorDataTransmitter::Send(BYTE* pData, UINT numBytes) const
{
// Do we have a valid serial port (hopefully with MS FF device connected)
if (m_DataPort == NULL) {
return FALSE;
}
return SUCCEEDED(g_pDriverCommunicator->SendBackdoor(pData, numBytes));
}
/****************** SerialBackdoorDataTransmitter class ***************/
/******************************************************
**
** SerialBackdoorDataTransmitter::SerialBackdoorDataTransmitter()
**
** @mfunc Constructor.
**
******************************************************/
SerialBackdoorDataTransmitter::SerialBackdoorDataTransmitter() : BackdoorDataTransmitter()
{
}
/******************************************************
**
** SerialBackdoorDataTransmitter::Initialize()
**
** returns: TRUE if initialized FALSE if not able to initialize
** @mfunc Initialize.
**
******************************************************/
BOOL SerialBackdoorDataTransmitter::Initialize(DWORD dwDeviceID)
{
if (!BackdoorDataTransmitter::Initialize(dwDeviceID)) {
return FALSE;
}
SerialDataTransmitter serialFrontDoor;
// This is funky
if (g_pDataTransmitter == NULL) {
ASSUME_NOT_REACHED();
return FALSE;
}
g_pDataTransmitter = &serialFrontDoor;
if (serialFrontDoor.Initialize(dwDeviceID)) {
m_DataPort = HANDLE(serialFrontDoor.GetSerialPortHack());
if (g_pDriverCommunicator->SetBackdoorPort(ULONG(m_DataPort)) == SUCCESS) {
serialFrontDoor.StopAutoClose();
DWORD oldPortID, oldAccessMethod;
joyGetForceFeedbackCOMMInterface(dwDeviceID, &oldAccessMethod, &oldPortID);
DWORD accessMethod = (oldAccessMethod & (MASK_OVERRIDE_MIDI_PATH | MASK_SERIAL_BACKDOOR)) | COMM_SERIAL_BACKDOOR;
joySetForceFeedbackCOMMInterface(dwDeviceID, accessMethod, oldPortID);
g_pDataTransmitter = this;
return TRUE;
}
}
g_pDataTransmitter = this;
return FALSE;
}
/****************** MidiBackdoorDataTransmitter class ***************/
/******************************************************
**
** MidiBackdoorDataTransmitter::MidiBackdoorDataTransmitter()
**
** @mfunc Constructor.
**
******************************************************/
MidiBackdoorDataTransmitter::MidiBackdoorDataTransmitter() : BackdoorDataTransmitter()
{
}
/******************************************************
**
** MidiBackdoorDataTransmitter::~MidiBackdoorDataTransmitter()
**
** @mfunc Destructor.
**
******************************************************/
MidiBackdoorDataTransmitter::~MidiBackdoorDataTransmitter()
{
m_DataPort = NULL; // Prevent attempt to ::CloseHandle(m_DataPort)
}
/******************************************************
**
** MidiBackdoorDataTransmitter::Initialize()
**
** returns: TRUE if initialized FALSE if not able to initialize
** @mfunc Initialize.
**
******************************************************/
BOOL MidiBackdoorDataTransmitter::Initialize(DWORD dwDeviceID)
{
if (!BackdoorDataTransmitter::Initialize(dwDeviceID)) {
return FALSE;
}
if (midiOutGetNumDevs() == 0) {
return FALSE; // No midi-devices backdoor check is worthless
}
// Valid MIDI ports table for backdoor - ordered by probability of working
DWORD midiPorts[] = {0x330, 0x300, 0x320, 0x340, 0x310, 0x350, 0x360, 0x370, 0x380, 0x390, 0x3a0, 0x3b0, 0x3c0, 0x3d0, 0x3e0, 0x3f0};
int numMidiPorts = sizeof(midiPorts)/sizeof(DWORD);
m_DataPort = NULL;
for (int i=0; i < numMidiPorts; i++) {
#ifdef _DEBUG
char buff[256];
wsprintf(buff, "MidiBackdoorDataTransmitter::Initialize(): Midi Port:%lx - ", midiPorts[i]);
DebugOut(buff);
#endif
// We have the Port #, Let's see if Jolt is out there
m_DataPort = HANDLE(midiPorts[i]);
if (g_pDriverCommunicator->SetBackdoorPort(ULONG(m_DataPort)) == SUCCESS) {
if (g_ForceFeedbackDevice.DetectHardware()) {
DebugOut(" Success!\n");
DWORD oldPortID;
DWORD oldAccessMethod;
joyGetForceFeedbackCOMMInterface(dwDeviceID, &oldAccessMethod, &oldPortID);
DWORD accessMethod = (oldAccessMethod & (MASK_OVERRIDE_MIDI_PATH | MASK_SERIAL_BACKDOOR)) | COMM_MIDI_BACKDOOR;
if ((accessMethod != oldAccessMethod) || (ULONG(m_DataPort) != oldPortID)) {
joySetForceFeedbackCOMMInterface(dwDeviceID, accessMethod, ULONG(m_DataPort));
}
// joySetForceFeedbackCOMMInterface(0, COMM_MIDI_BACKDOOR, ULONG(m_DataPort));
return TRUE;
} else {
m_DataPort = NULL;
DebugOut(" No Answer\n");
}
}
}
// If we have fallen through we have failed
return FALSE;
}
/******************************************************
**
** MidiBackdoorDataTransmitter::InitializeSpecific(HANDLE specificHandle)
**
** returns: TRUE if initialized FALSE if not able to initialize
** @mfunc Initialize.
**
******************************************************/
BOOL MidiBackdoorDataTransmitter::InitializeSpecific(DWORD dwDeviceID, HANDLE specificHandle)
{
if (!BackdoorDataTransmitter::Initialize(dwDeviceID)) {
return FALSE;
}
if (midiOutGetNumDevs() == 0) {
return FALSE; // No midi-devices backdoor check is worthless
}
m_DataPort = NULL;
// We have the Port #, Let's see if Jolt is out there
if (g_pDriverCommunicator->SetBackdoorPort(ULONG(specificHandle) == SUCCESS)) {
if (g_ForceFeedbackDevice.DetectHardware()) {
m_DataPort = specificHandle;
// No need to set registry the registry is what brought us here
return TRUE;
}
}
// If we have fallen through we have failed
return FALSE;
}
#if 0
/************************** PinTransmitter Class ******************************/
/******************************************************
**
** PinTransmitter::PinTransmitter()
**
** @mfunc Constructor.
**
******************************************************/
PinTransmitter::PinTransmitter() : DataTransmitter(),
m_UartFilter(INVALID_HANDLE_VALUE),
m_MidiPin(INVALID_HANDLE_VALUE),
m_MidiOutEvent(INVALID_HANDLE_VALUE)
{
}
/******************************************************
**
** PinTransmitter::~PinTransmitter()
**
** @mfunc Destructor.
**
******************************************************/
PinTransmitter::~PinTransmitter()
{
// Close the send event
if (IsHandleValid(m_MidiOutEvent)) {
::CloseHandle(m_MidiOutEvent);
m_MidiOutEvent = NULL;
}
// Close the pin
if (IsHandleValid(m_MidiPin)) {
::CloseHandle(m_MidiPin);
m_MidiPin = INVALID_HANDLE_VALUE;
}
// Close the Uart
if (IsHandleValid(m_UartFilter)) {
::CloseHandle(m_UartFilter);
m_UartFilter = INVALID_HANDLE_VALUE;
}
}
/******************************************************
**
** PinTransmitter::Initialize()
**
** returns: TRUE if initialized FALSE if not able to initialize
** @mfunc Initialize.
**
******************************************************/
BOOL PinTransmitter::Initialize()
{
// Load the ksUserLibrary and grab the create pin function
HINSTANCE ksUserLib = ::LoadLibrary(TEXT("KsUser.dll"));
if (ksUserLib == NULL) {
return FALSE;
}
KSCREATEPIN pfCreatePin = (KSCREATEPIN)::GetProcAddress(ksUserLib, TEXT("KsCreatePin"));
if (pfCreatePin == NULL) {
::FreeLibrary(ksUserLib);
return FALSE;
}
// Open the Uart
m_UartFilter = ::CreateFile(UART_FILTER_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (m_UartFilter == INVALID_HANDLE_VALUE) {
::FreeLibrary(ksUserLib);
return FALSE;
}
// Create Overlapped event
OVERLAPPED overlapped;
::memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
// Get the number of pins
KSP_PIN ksPinProp;
::memset(&ksPinProp, 0, sizeof(ksPinProp));
ksPinProp.Property.Set = KSPROPSETID_Pin;
ksPinProp.Property.Id = KSPROPERTY_PIN_CTYPES;
ksPinProp.Property.Flags = KSPROPERTY_TYPE_GET;
DWORD numPins = 0;
OverLappedPinIOCTL(overlapped, ksPinProp, &numPins, sizeof(numPins));
// Check each pin for proper type, then try to create
BOOL wasCreated = FALSE;
for (UINT pinNum = 0; (pinNum < numPins) && (wasCreated == FALSE); pinNum++) {
ksPinProp.PinId = pinNum;
ksPinProp.Property.Id = KSPROPERTY_PIN_DATAFLOW;
KSPIN_DATAFLOW dataFlow = (KSPIN_DATAFLOW)0;
if (OverLappedPinIOCTL(overlapped, ksPinProp, &dataFlow, sizeof(dataFlow)) == TRUE) {
if (dataFlow == KSPIN_DATAFLOW_IN) {
ksPinProp.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
KSPIN_COMMUNICATION communication = KSPIN_COMMUNICATION_NONE;
if (OverLappedPinIOCTL(overlapped, ksPinProp, &communication, sizeof(communication)) == TRUE) {
if ((communication == KSPIN_COMMUNICATION_SINK) || (communication == KSPIN_COMMUNICATION_BOTH)) {
wasCreated = CreatePinInstance(pinNum, pfCreatePin);
}
}
}
}
}
::FreeLibrary(ksUserLib);
::CloseHandle(overlapped.hEvent);
if (wasCreated == FALSE) {
::CloseHandle(m_UartFilter);
m_UartFilter = INVALID_HANDLE_VALUE;
return FALSE;
}
return TRUE;
}
/******************************************************
**
** PinTransmitter::OverLappedPinIOCTL()
**
** returns: TRUE if able to proform Pin Property IOCTL
** @mfunc OverLappedPinIOCTL.
******************************************************/
BOOL PinTransmitter::OverLappedPinIOCTL(OVERLAPPED overlapped, KSP_PIN ksPinProp, void* pData, DWORD dataSize)
{
// IOCTL the Property
if (::DeviceIoControl(m_UartFilter, IOCTL_KS_PROPERTY, &ksPinProp, sizeof(ksPinProp), pData, dataSize, NULL, &overlapped) == TRUE) {
return TRUE;
}
// Failed IOCTL check if more time is needed
if (::GetLastError() != ERROR_IO_PENDING) {
return FALSE;
}
// Do wait
if (::WaitForSingleObject(overlapped.hEvent, 3000) == WAIT_OBJECT_0) {
return TRUE; // Waiting paid off
}
return FALSE; // Grew tired of waiting
}
/******************************************************
**
** PinTransmitter::CreatePinInstance()
**
** returns: TRUE if able to create the requested pin instance
** @mfunc CreatePinInstance.
******************************************************/
BOOL PinTransmitter::CreatePinInstance(UINT pinNumber, KSCREATEPIN pfCreatePin)
{
// Set the pin format
KSDATAFORMAT ksDataFormat;
::memset(&ksDataFormat, 0, sizeof(ksDataFormat));
ksDataFormat.FormatSize = sizeof(ksDataFormat);
ksDataFormat.MajorFormat = KSDATAFORMAT_TYPE_MUSIC;
ksDataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_MIDI;
ksDataFormat.Specifier = KSDATAFORMAT_SPECIFIER_NONE;
// Set the pin connection information
KSPIN_CONNECT* pConnectionInfo = (KSPIN_CONNECT*) new BYTE[sizeof(KSPIN_CONNECT) + sizeof(ksDataFormat)];
::memset(pConnectionInfo, 0, sizeof(KSPIN_CONNECT));
pConnectionInfo->Interface.Set = KSINTERFACESETID_Standard;
pConnectionInfo->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
pConnectionInfo->Medium.Set = KSMEDIUMSETID_Standard;
pConnectionInfo->Medium.Id = KSMEDIUM_STANDARD_DEVIO;
pConnectionInfo->PinId = pinNumber;
pConnectionInfo->Priority.PriorityClass = KSPRIORITY_NORMAL;
pConnectionInfo->Priority.PrioritySubClass = 1;
::memcpy(pConnectionInfo + 1, &ksDataFormat, sizeof(ksDataFormat));
DWORD status = pfCreatePin(m_UartFilter, pConnectionInfo, FILE_WRITE_ACCESS, &m_MidiPin);
delete[] pConnectionInfo;
if (status != NO_ERROR) {
#ifdef _DEBUG
TCHAR buff[256];
wsprintf(buff, TEXT("Error Creating Pin: 0x%08X\r\n"), status);
_RPT0(_CRT_WARN, buff);
#endif
return FALSE;
}
SetPinState(KSSTATE_PAUSE);
return TRUE;
}
/******************************************************
**
** PinTransmitter::Send()
**
** returns: TRUE if all data was successfully sent
** @mfunc Send.
**
******************************************************/
BOOL PinTransmitter::Send(BYTE* pData, UINT numBytes)
{
if (!IsHandleValid(m_MidiPin)) {
return FALSE;
}
BYTE musicData[c_LongMsgMax + sizeof(KSMUSICFORMAT)];
::memset(musicData, 0, sizeof(musicData));
((KSMUSICFORMAT*)musicData)->ByteCount = numBytes;
::memcpy(((KSMUSICFORMAT*)musicData) + 1, pData, numBytes);
KSSTREAM_HEADER ksStreamHeader;
::memset(&ksStreamHeader, 0, sizeof(ksStreamHeader));
ksStreamHeader.Size = sizeof(ksStreamHeader);
ksStreamHeader.PresentationTime.Numerator = 1;
ksStreamHeader.PresentationTime.Denominator = 1;
ksStreamHeader.FrameExtent = sizeof(musicData);
ksStreamHeader.DataUsed = sizeof KSMUSICFORMAT + numBytes;
ksStreamHeader.Data = (void*)musicData;
if (!IsHandleValid(m_MidiOutEvent)) {
m_MidiOutEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
}
OVERLAPPED overlapped;
::memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = m_MidiOutEvent;
SetPinState(KSSTATE_RUN);
if (!DeviceIoControl(m_MidiPin, IOCTL_KS_WRITE_STREAM, NULL, 0,
&ksStreamHeader, sizeof(ksStreamHeader), NULL, &overlapped)) {
if (GetLastError() == ERROR_IO_PENDING) {
::WaitForSingleObject(overlapped.hEvent, 3000);
}
}
SetPinState(KSSTATE_PAUSE);
return TRUE;
}
/******************************************************
**
** PinTransmitter::SetPinState()
**
** returns: Nothing
** @mfunc SetPinState.
**
******************************************************/
void PinTransmitter::SetPinState(KSSTATE state)
{
if (!IsHandleValid(m_MidiPin)) {
return;
}
KSPROPERTY ksProperty;
::memset(&ksProperty, 0, sizeof(ksProperty));
ksProperty.Set = KSPROPSETID_Connection;
ksProperty.Id = KSPROPERTY_CONNECTION_STATE;
ksProperty.Flags = KSPROPERTY_TYPE_SET;
OVERLAPPED overlapped;
::memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if (IsHandleValid(overlapped.hEvent)) {
if( !DeviceIoControl(m_MidiPin, IOCTL_KS_PROPERTY, &ksProperty, sizeof ksProperty, &state, sizeof state, NULL, &overlapped )) {
if (GetLastError() == ERROR_IO_PENDING) {
WaitForSingleObject(overlapped.hEvent, 30000);
}
}
::CloseHandle(overlapped.hEvent);
}
}
#endif