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.
 
 
 
 
 
 

608 lines
18 KiB

//@doc
/******************************************************
**
** @module DTRANS.CPP | DataTransmitter implementation file
**
** Description:
**
** History:
** Created 11/13/97 Matthew L. Coill (mlc)
**
** (c) 1986-1997 Microsoft Corporation. All Rights Reserved.
******************************************************/
#include "FFDevice.h"
#include "DTrans.h"
//#include <devioctl.h>
#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;
#define UART_FILTER_NAME TEXT("\\\\.\\.\\PortClass0\\Uart")
const WORD c_LongMsgMax = 256;
inline BOOL IsHandleValid(HANDLE handleToCheck)
{
return ((handleToCheck != NULL) && (handleToCheck != INVALID_HANDLE_VALUE));
}
#define CHECK_RELEASE_AND_NULL(pIUnknown) \
if (pIUnknown != NULL) \
{ \
pIUnknown->Release(); \
pIUnknown = NULL; \
}
/************************** 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()
{
// 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 (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);
::OutputDebugString(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");
}
}
return (m_SerialPort != INVALID_HANDLE_VALUE);
}
/******************************************************
**
** SerialDataTransmitter::Send()
**
** returns: TRUE if all data was successfully sent
** @mfunc Send.
**
******************************************************/
BOOL SerialDataTransmitter::Send(BYTE* data, UINT numBytes)
{
// Do we have a valid serial port (hopefully with MS FF device connected)
if (m_SerialPort == NULL) {
return FALSE;
}
/* char dbgOut[255];
::OutputDebugString("(SerialDataTransmitter::Send) : ");
for (UINT i = 0; i < numBytes; i++) {
wsprintf(dbgOut, " 0x%02X", data[i]);
::OutputDebugString(dbgOut);
}
::OutputDebugString("\r\n");
*/
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);
}
/************************** DMusicTransmitter Class ******************************/
/****************************************
**
** DMusicTransmitter::DMusicTransmitter()
**
** @mfunc Constructor for DirectMusic Transmitter
**
*****************************************/
DMusicTransmitter::DMusicTransmitter() : DataTransmitter(),
m_pIDirectMusic(NULL),
m_pIDirectMusicPort(NULL),
m_pIDirectMusicBuffer(NULL)
{
}
/****************************************
**
** DMusicTransmitter::~DMusicTransmitter()
**
** @mfunc Destructor for DirectMusic Transmitter
**
*****************************************/
DMusicTransmitter::~DMusicTransmitter()
{
CHECK_RELEASE_AND_NULL(m_pIDirectMusicBuffer);
CHECK_RELEASE_AND_NULL(m_pIDirectMusicPort);
CHECK_RELEASE_AND_NULL(m_pIDirectMusic);
}
/****************************************
**
** BOOL DMusicTransmitter::Initialize()
**
** @mfunc Intialize the Direct Music Transmission path
**
** @rdesc TRUE if initialization was successful, FALSE otherwise
**
*****************************************/
BOOL DMusicTransmitter::Initialize()
{
// Case they are reinitializing
CHECK_RELEASE_AND_NULL(m_pIDirectMusicBuffer);
CHECK_RELEASE_AND_NULL(m_pIDirectMusicPort);
CHECK_RELEASE_AND_NULL(m_pIDirectMusic);
// Create the global IDirectMusic Interface
HRESULT hr = ::CoCreateInstance(CLSID_DirectMusic, NULL, CLSCTX_INPROC, IID_IDirectMusic, (void**)&m_pIDirectMusic);
if (FAILED(hr) || m_pIDirectMusic == NULL)
{
return FALSE;
}
// Enumerate and create the port when valid one is found
DMUS_PORTCAPS portCaps;
portCaps.dwSize = sizeof portCaps;
DWORD dwPortIndex = 0;
for (;;)
{
HRESULT hr = m_pIDirectMusic->EnumPort(dwPortIndex, &portCaps);
if (FAILED(hr) || hr == S_FALSE)
{ // Either we have failed or run out of ports
return FALSE;
}
if (portCaps.dwClass == DMUS_PC_OUTPUTCLASS)
{
DMUS_PORTPARAMS portParams;
portParams.dwSize = sizeof DMUS_PORTPARAMS;
portParams.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
portParams.dwChannelGroups = 1;
// hr = m_pIDirectMusic->CreatePort(portCaps.guidPort, GUID_NULL, &portParams, &m_pIDirectMusicPort, NULL);
hr = m_pIDirectMusic->CreatePort(portCaps.guidPort, &portParams, &m_pIDirectMusicPort, NULL);
break;
}
dwPortIndex++;
}
// Create the buffer
DMUS_BUFFERDESC dmbd;
dmbd.dwSize = sizeof DMUS_BUFFERDESC;
dmbd.dwFlags = 0;
// dmbd.guidBufferFormat = GUID_KSMusicFormat;
dmbd.guidBufferFormat = GUID_NULL;
dmbd.cbBuffer = 256;
hr = m_pIDirectMusic->CreateMusicBuffer(&dmbd, &m_pIDirectMusicBuffer, NULL);
if (FAILED(hr) || m_pIDirectMusicBuffer == NULL)
{
return FALSE;
}
return TRUE;
}
/****************************************
**
** BOOL DMusicTransmitter::Send(BYTE* pData, UINT ulByteCount)
**
** @mfunc Sends bytes via DirectMusic to the stick
**
** @rdesc TRUE if send was successful, FALSE otherwise
**
*****************************************/
BOOL DMusicTransmitter::Send
(
BYTE* pData, //@parm Data buffer to send
UINT ulByteCount //@parm Number of bytes in buffer to send
)
{
// Do sanity checks
if ((pData == NULL) || (m_pIDirectMusicPort == NULL) || (m_pIDirectMusicBuffer == NULL) || (ulByteCount == 0))
{
return FALSE;
}
// Check if we need to pack sysex or channel message
if (pData[0] == 0xF0)
{ // Create system exclusive
/*
// Pack the sysex-message into the buffer
HRESULT hr = m_pIDirectMusicBuffer->PackSysEx(0, 1, ulByteCount, pData);
if (FAILED(hr))
{ // Unable to pack the buffer
return FALSE;
}
*/ }
else
{ // Channel Message (fix intel backwards byte order)
DWORD channelMessage = pData[0];
if (ulByteCount > 1)
{
channelMessage |= pData[1] << 8;
if (ulByteCount > 2)
{
channelMessage |= pData[2] << 16;
}
}
// Pack the channel-message into the buffer
/* HRESULT hr = m_pIDirectMusicBuffer->PackChannelMsg(0, 1, channelMessage);
if (FAILED(hr))
{ // Unable to pack the buffer
return FALSE;
}
*/ }
// Send the buffer to the port
HRESULT hr = m_pIDirectMusicPort->PlayBuffer(m_pIDirectMusicBuffer);
if (FAILED(hr))
{ // Unable to send the data across the port
return FALSE;
}
return TRUE;
}
#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);
::OutputDebugString(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