Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

713 lines
18 KiB

/*****************************************************************************
*
* Pidi.h
*
* Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
*
* Abstract:
*
* Internal header for PID driver.
*
*****************************************************************************/
#define hresLe(le) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, (USHORT)(le))
#define HidP_Max (HidP_Feature+1)
#define REGSTR_PATH_VID_PID_TEMPLATE REGSTR_PATH_JOYOEM TEXT("\\VID_%04X&PID_%04X")
#define REGSTR_OEM_FF_TEMPLATE REGSTR_PATH_VID_PID_TEMPLATE TEXT("\\OEMForceFeedback")
#define REGSTR_EFFECTS TEXT("Effects")
#define REGSTR_ATTRIBUTES TEXT("Attributes")
#define REGSTR_CLSID TEXT("CLSID")
#define REGSTR_CREATEDBY TEXT("CreatedBy")
#define MAX_DEVICEINTERFACE (1024)
#define PIDMAKEUSAGEDWORD(Usage) \
DIMAKEUSAGEDWORD(HID_USAGE_PAGE_PID, HID_USAGE_PID_##Usage )
#define DIGETUSAGEPAGE(UsageAndUsagePage) ((USAGE)(HIWORD(UsageAndUsagePage)))
#define DIGETUSAGE( UsageAndUsagePage) ((USAGE)(LOWORD(UsageAndUsagePage)))
#define MAKE_PIDUSAGE( Usage, Offset ) { PIDMAKEUSAGEDWORD(Usage), Offset }
#define MAKE_HIDUSAGE( UsagePage, Usage, Offset ) { DIMAKEUSAGEDWORD(HID_USAGE_PAGE_##UsagePage, Usage), Offset }
#define PID_DIES_START (0x80000000)
#define PID_DIES_STOP (0x40000000)
#define PIDALLOC_INIT (0xF)
#define HID_VALUE (0x01)
#define HID_BUTTON (0x02)
#define HID_COLLECTION (0x04)
#define MAX_ORDINALS (8)
#define MAX_BUTTONS (0xff)
#define MAX_AXES (8)
/*
* Device-specific errors for USB/PID force feedback devices.
*/
/*
* The requested usage was not found.
*/
#define DIERR_PID_USAGENOTFOUND DIERR_DRIVERFIRST + 1
/*
* The parameter block couldn't be downloaded to the device.
*/
#define DIERR_PID_BLOCKLOADERROR DIERR_DRIVERFIRST + 2
/*
* PID initialization failed.
*/
#define DIERR_PID_NOTINITIALIZED DIERR_DRIVERFIRST + 3
/*
* The provided values couldn't be scaled.
*/
#define DIERR_PID_INVALIDSCALING DIERR_DRIVERFIRST + 4
typedef CONST GUID *LPCGUID;
#ifndef MAXULONG_PTR
typedef DWORD ULONG_PTR;
typedef DWORD *PULONG_PTR;
typedef DWORD UINT_PTR;
typedef DWORD *PULONG_PTR;
#endif //MAXULONG_PTR
/*****************************************************************************
*
* For each active unit, one of these structures exists to keep
* track of which effects are "in use".
*
* Our imaginary hardware does not do dynamic memory allocation;
* there are merely 16 "slots", and each "slot" can be "in use"
* or "free".
*
*****************************************************************************/
#define MAX_UNITS 4
#define GLOBAL_EFFECT_MEMSZ ( 1024 )
typedef struct _PIDMEM{
ULONG uOfSz;
INT_PTR iNext;
} PIDMEM, *PPIDMEM;
#define PIDMEM_OFFSET(pMem) ( HIWORD(pMem->uOfSz) )
#define PIDMEM_SIZE(pMem) ( LOWORD(pMem->uOfSz) )
#define PIDMEM_OFSZ(Offset, Size) ( MAKELONG((Size), (Offset)) )
#define GET_NEXTOFFSET(pMem) ( PIDMEM_OFFSET(pMem) + PIDMEM_SIZE(pMem) )
typedef struct _EFFECTSTATE{
ULONG lEfState;
PIDMEM PidMem[];
} EFFECTSTATE, *PEFFECTSTATE;
typedef struct _UNITSTATE {
GUID GuidInstance;
USHORT cEfDownloaded;
USHORT nAlloc;
USHORT cbAlloc;
PIDMEM Guard[2];
UCHAR State[GLOBAL_EFFECT_MEMSZ];
} UNITSTATE, *PUNITSTATE;
/*****************************************************************************
*
* Since the information to track each unit is so small, we pack them
* together into a single shared memory block to save memory.
*
* We use our own GUID as the name of the memory block to avoid
* collisions with other named memory blocks.
*
*****************************************************************************/
typedef struct SHAREDMEMORY {
UNITSTATE rgus[MAX_UNITS];
} SHAREDMEMORY, *PSHAREDMEMORY;
typedef struct _REPORTPOOL
{
ULONG uRamPoolSz;
ULONG uRomPoolSz;
ULONG uRomETCount;
ULONG uSimulEfMax;
ULONG uPoolAlign;
} REPORTPOOL, *PREPORTPOOL;
typedef struct _SZPOOL
{
ULONG uSzEffect;
ULONG uSzEnvelope;
ULONG uSzCondition;
ULONG uSzCustom;
ULONG uSzPeriodic;
ULONG uSzConstant;
ULONG uSzRamp;
ULONG uSzCustomData;
} SZPOOL, *PSZPOOL;
typedef struct _DIUSAGEANDINST
{
DWORD dwUsage;
DWORD dwType;
} DIUSAGEANDINST, *PDIUSAGEANDINST;
#define MAX_BLOCKS 4 //we can send up to 4 blocks at a time -- 1 effect block, 2 param blocks & 1 effect operation block
typedef struct CPidDrv
{
/* Supported interfaces */
IDirectInputEffectDriver ed;
ULONG cRef; /* Object reference count */
/*
* !!IHV!! Add additional instance data here.
* (e.g., handle to driver you want to IOCTL to)
*/
DWORD dwDirectInputVersion;
DWORD dwID;
TCHAR tszDeviceInterface[MAX_DEVICEINTERFACE];
GUID GuidInstance;
HANDLE hdev;
PHIDP_PREPARSED_DATA \
ppd;
HIDD_ATTRIBUTES attr;
HIDP_CAPS caps;
PUCHAR pReport[HidP_Max];
USHORT cbReport[HidP_Max];
//here we store reports that need to be written in a non-blocking way
PUCHAR pWriteReport[MAX_BLOCKS];
USHORT cbWriteReport[MAX_BLOCKS];
PHIDP_LINK_COLLECTION_NODE pLinkCollection;
USHORT cMaxEffects;
USHORT cMaxParameters;
/*
* We remember the unit number because that tells us
* which I/O port we need to send the commands to.
*/
DWORD dwUnit; /* Device unit number */
UINT uDeviceManaged;
UINT cFFObjMax;
UINT cFFObj;
PDIUSAGEANDINST rgFFUsageInst;
REPORTPOOL ReportPool;
SZPOOL SzPool;
INT_PTR iUnitStateOffset;
DIEFFECT DiSEffectScale;
DIEFFECT DiSEffectOffset;
DIENVELOPE DiSEnvScale;
DIENVELOPE DiSEnvOffset;
DICONDITION DiSCondScale;
DICONDITION DiSCondOffset;
DIRAMPFORCE DiSRampScale;
DIRAMPFORCE DiSRampOffset;
DIPERIODIC DiSPeriodicScale;
DIPERIODIC DiSPeriodicOffset;
DICONSTANTFORCE DiSConstScale;
DICONSTANTFORCE DiSConstOffset;
DICUSTOMFORCE DiSCustomScale;
DICUSTOMFORCE DiSCustomOffset;
DWORD DiSEffectAngleScale[MAX_ORDINALS];
DWORD DiSEffectAngleOffset[MAX_ORDINALS];
DWORD DiSCustomSample[MAX_ORDINALS];
HIDP_VALUE_CAPS customCaps[3];
HIDP_VALUE_CAPS customDataCaps;
HANDLE hThread;
DWORD idThread;
ULONG cThreadRef;
HANDLE hdevOvrlp;
OVERLAPPED o;
HANDLE hWrite;
HANDLE hWriteComplete;
DWORD dwWriteAttempt;
UINT totalBlocks; //how many total blocks we need to write
UINT blockNr; //the block we're currently writing
DWORD dwState;
DWORD dwUsedMem;
} CPidDrv, *PCPidDrv;
/*****************************************************************************
*
* @doc INTERNAL
*
* @struct EFFECTMAPINFO |
*
* Information about an effect, much like a
* <t DIEFFECTINFO>, but containing the
* effect ID, too.
*
* @field DWORD | dwId |
*
* The effect ID. This comes first so we can copy
* an <t EFFECTMAPINFO> into a <t DIEFFECTINFO>
* all at one go.
*
* @field GUID | guid |
*
* The effect GUID.
*
* @field DWORD | dwEffType |
*
* The effect type and flags.
*
* @field WCHAR | wszName[MAX_PATH] |
*
* The name for the effect.
*
*****************************************************************************/
typedef struct _EFFECTMAPINFO
{
DIEFFECTATTRIBUTES attr;
PCGUID pcguid;
TCHAR tszName[MAX_PATH];
} EFFECTMAPINFO, *PEFFECTMAPINFO;
typedef const EFFECTMAPINFO *PCEFFECTMAPINFO;
typedef struct _PIDSUPPORT
{
DWORD dwDIFlags;
DWORD dwPidUsage;
USAGE Type;
HIDP_REPORT_TYPE HidP_Type;
} PIDSUPPORT, *PPIDSUPPORT;
typedef struct _PIDUSAGE
{
DWORD dwUsage;
UINT DataOffset;
} PIDUSAGE, *PPIDUSAGE;
typedef struct _PIDREPORT
{
HIDP_REPORT_TYPE HidP_Type;
USAGE UsagePage;
USAGE Collection;
UINT cbXData;
UINT cAPidUsage;
PPIDUSAGE rgPidUsage;
} PIDREPORT, *PPIDREPORT;
extern PIDREPORT g_BlockIndex;
extern PIDREPORT g_Effect;
extern PIDREPORT g_Condition;
extern PIDREPORT g_Periodic;
extern PIDREPORT g_Ramp;
extern PIDREPORT g_Envelope;
extern PIDREPORT g_Constant;
extern PIDREPORT g_Direction;
extern PIDREPORT g_TypeSpBlockOffset;
extern PIDREPORT g_PoolReport;
extern PIDREPORT g_BlockIndexIN;
extern PIDREPORT g_Custom;
extern PIDREPORT g_CustomSample;
extern PIDREPORT g_CustomData;
#pragma BEGIN_CONST_DATA
static PIDUSAGE c_rgUsgDirection[]=
{
MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_RX, 0*cbX(ULONG)),
MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_RY, 1*cbX(ULONG)),
MAKE_HIDUSAGE(GENERIC, HID_USAGE_GENERIC_RZ, 2*cbX(ULONG)),
};
/*
* Define translation table for ordinals to HID usages
*/
static PIDUSAGE c_rgUsgOrdinals[] =
{
MAKE_HIDUSAGE(ORDINAL, 0x1, 0*cbX(ULONG)),
MAKE_HIDUSAGE(ORDINAL, 0x2, 1*cbX(ULONG)),
MAKE_HIDUSAGE(ORDINAL, 0x3, 2*cbX(ULONG)),
MAKE_HIDUSAGE(ORDINAL, 0x4, 3*cbX(ULONG)),
MAKE_HIDUSAGE(ORDINAL, 0x5, 4*cbX(ULONG)),
MAKE_HIDUSAGE(ORDINAL, 0x6, 5*cbX(ULONG)),
MAKE_HIDUSAGE(ORDINAL, 0x7, 6*cbX(ULONG)),
MAKE_HIDUSAGE(ORDINAL, 0x8, 7*cbX(ULONG)),
};
#pragma END_CONST_DATA
typedef BOOL (WINAPI *CANCELIO)(HANDLE);
typedef BOOL (WINAPI *TRYENTERCRITICALSECTION)(LPCRITICAL_SECTION);
BOOL WINAPI FakeCancelIO(HANDLE h);
BOOL WINAPI FakeTryEnterCriticalSection(LPCRITICAL_SECTION lpCrit_sec);
extern CANCELIO CancelIo_;
extern TRYENTERCRITICALSECTION TryEnterCriticalSection_;
/*****************************************************************************
*
* Constant globals: Never change. Ever.
*
*****************************************************************************/
DEFINE_GUID(GUID_MySharedMemory, 0x1dc900bf,0xbcac,0x11d2,0xa9,0x19,0x00,0xc0,0x4f,0xb9,0x86,0x38);
DEFINE_GUID(GUID_MyMutex, 0x4368208f,0xbcac,0x11d2,0xa9,0x19,0x00,0xc0,0x4f,0xb9,0x86,0x38);
/*****************************************************************************
*
* Static globals: Initialized at PROCESS_ATTACH and never modified.
*
*****************************************************************************/
extern HINSTANCE g_hinst; /* This DLL's instance handle */
extern PSHAREDMEMORY g_pshmem; /* Our shared memory block */
extern HANDLE g_hfm; /* Handle to file mapping object */
extern HANDLE g_hmtxShared; /* Handle to mutex that protects g_pshmem */
/*****************************************************************************
*
* Prototypes
*
*****************************************************************************/
STDMETHODIMP
PID_DownloadEffect
(
IDirectInputEffectDriver *ped,
DWORD dwId,
DWORD dwEffectId,
LPDWORD pdwEffect,
LPCDIEFFECT peff,
DWORD dwFlags
);
STDMETHODIMP
PID_DoParameterBlocks
(
IDirectInputEffectDriver *ped,
DWORD dwId,
DWORD dwEffectId,
DWORD dwEffectIndex,
LPCDIEFFECT peff,
DWORD dwFlags,
PUINT puParameter,
BOOL bBlocking,
UINT totalBlocks
);
STDMETHODIMP
PID_EffectOperation
(
IDirectInputEffectDriver *ped,
DWORD dwId,
DWORD dwEffect,
DWORD dwMode,
DWORD dwCount,
BOOL bBlocking,
UINT blockNr,
UINT totalBlocks
);
STDMETHODIMP
PID_SetGain
(
IDirectInputEffectDriver *ped,
DWORD dwId,
DWORD dwGain
);
STDMETHODIMP
PID_SendForceFeedbackCommand
(
IDirectInputEffectDriver *ped,
DWORD dwId,
DWORD dwCommand
);
STDMETHODIMP
PID_GetLinkCollectionIndex
(
IDirectInputEffectDriver *ped,
USAGE UsagePage,
USAGE Collection,
USHORT Parent,
PUSHORT puLinkCollection
);
STDMETHODIMP
PID_Init
(
IDirectInputEffectDriver *ped
);
STDMETHODIMP
PID_InitFFAttributes
(
IDirectInputEffectDriver *ped
);
STDMETHODIMP
PID_Finalize
(
IDirectInputEffectDriver *ped
);
STDMETHODIMP
PID_InitRegistry
(
IDirectInputEffectDriver *ped
);
STDMETHODIMP
PID_Support
(
IDirectInputEffectDriver *ped,
UINT cAPidSupport,
PPIDSUPPORT rgPidSupport,
PDWORD pdwFlags
);
STDMETHODIMP
PID_PackValue
(
IDirectInputEffectDriver *ped,
PPIDREPORT pPidReport,
USHORT LinkCollection,
PVOID pvData,
UINT cbData,
PCHAR pReport,
ULONG cbReport
);
STDMETHODIMP
PID_ParseReport
(
IDirectInputEffectDriver *ped,
PPIDREPORT pPidReport,
USHORT LinkCollection,
PVOID pvData,
UINT cbData,
PCHAR pReport,
ULONG cbReport
);
STDMETHODIMP
PID_SendReport
(
IDirectInputEffectDriver *ped,
PUCHAR pReport,
UINT cbReport,
HIDP_REPORT_TYPE HidP_Type,
BOOL bBlocking,
UINT blockNr,
UINT totalBlocks
);
STDMETHODIMP
PID_GetReport
(
IDirectInputEffectDriver *ped,
PPIDREPORT pPidReport,
USHORT LinkCollection,
PVOID pReport,
UINT cbReport
);
STDMETHODIMP
PID_NewEffectIndex
(
IDirectInputEffectDriver *ped,
LPDIEFFECT lpdieff,
DWORD dwEffectId,
PDWORD pdwEffect
);
STDMETHODIMP
PID_ValidateEffectIndex
(
IDirectInputEffectDriver *ped,
DWORD pdwEffect
);
STDMETHODIMP
PID_DestroyEffect
(
IDirectInputEffectDriver *ped,
DWORD dwId,
DWORD dwEffect
);
STDMETHODIMP
PID_GetParameterOffset
(
IDirectInputEffectDriver *ped,
DWORD dwEffectIndex,
UINT uParameterBlock,
DWORD dwSz,
PLONG plValue
);
STDMETHODIMP
PID_ComputeScalingFactors
(
IDirectInputEffectDriver *ped,
PPIDREPORT pPidReport,
USHORT LinkCollection,
PVOID pvData,
UINT cbData,
PVOID pvOffset,
UINT cbOffset
);
STDMETHODIMP
PID_ApplyScalingFactors
(
IDirectInputEffectDriver *ped,
PPIDREPORT pPidReport,
PVOID pvScale,
UINT cbScale,
PVOID pvOffset,
UINT cbOffset,
PVOID pvData,
UINT cbData
);
STDMETHODIMP
PID_GetReportId
(
IDirectInputEffectDriver *ped,
PPIDREPORT pPidReport,
USHORT uLinkCollection,
UCHAR* pReportId
);
VOID INTERNAL
PID_ThreadProc(CPidDrv* this);
STDMETHODIMP_(ULONG)
PID_AddRef(IDirectInputEffectDriver *ped);
STDMETHODIMP_(ULONG)
PID_Release(IDirectInputEffectDriver *ped);
void EXTERNAL
NameFromGUID(LPTSTR ptszBuf, PCGUID pguid);
#ifdef DEBUG
#define PIDUSAGETXT_MAX ( 0xAC )
extern PTCHAR g_rgUsageTxt[PIDUSAGETXT_MAX]; // Cheat sheet for EffectNames
#define PIDUSAGETXT(UsagePage, Usage ) \
( ( UsagePage == HID_USAGE_PAGE_PID && Usage < PIDUSAGETXT_MAX) ? g_rgUsageTxt[Usage] : NULL )
void PID_CreateUsgTxt();
#else
#define PID_CreateUsgTxt()
#define PIDUSAGETXT(UsagePage, Usage) ( NULL )
#endif
PEFFECTSTATE INLINE PeffectStateFromBlockIndex(PCPidDrv this, UINT Index )
{
return (PEFFECTSTATE)(&((PUNITSTATE)(g_pshmem + this->iUnitStateOffset))->State[0] + (Index-1) * ((FIELD_OFFSET(EFFECTSTATE,PidMem)) + this->cMaxParameters*cbX(PIDMEM)));
}
#define PID_EFFECT_RESET (0x0000000)
#define PID_EFFECT_BUSY (0x8000000)
#define PID_EFFECT_STARTED (0x4000000)
#define PID_EFFECT_STARTED_SOLO (0x2000000)
#define PID_DRIVER_VERSION (0x0000001)
#define PID_DEVICEMANAGED (0x1)
#define PID_SHAREDPARAM (0x2)
/*****************************************************************************
*
* Dll global functions
*
*****************************************************************************/
void EXTERNAL DllEnterCrit_(LPCTSTR lptszFile, UINT line);
void EXTERNAL DllLeaveCrit_(LPCTSTR lptszFile, UINT line);
#ifdef DEBUG
BOOL EXTERNAL DllInCrit(void);
#define DllEnterCrit() DllEnterCrit_(TEXT(__FILE__), __LINE__)
#define DllLeaveCrit() DllLeaveCrit_(TEXT(__FILE__), __LINE__)
#else
#define DllEnterCrit() DllEnterCrit_(NULL, 0x0)
#define DllLeaveCrit() DllLeaveCrit_(NULL, 0x0)
#endif
STDAPI_(ULONG) DllAddRef(void);
STDAPI_(ULONG) DllRelease(void);
/*****************************************************************************
*
* Class factory
*
*****************************************************************************/
STDAPI CClassFactory_New(REFIID riid, LPVOID *ppvObj);
/*****************************************************************************
*
* Effect driver
*
*****************************************************************************/
STDAPI PID_New(REFIID riid, LPVOID *ppvObj);
#ifndef WINNT
/***************************************************************************
*
* KERNEL32 prototypes missing from Win98 headers.
*
***************************************************************************/
WINBASEAPI BOOL WINAPI CancelIo( HANDLE hFile );
#endif