mididd.c
来自「Windows NT声卡驱动VXD」· C语言 代码 · 共 1,581 行 · 第 1/4 页
C
1,581 行
/****************************************************************************
*
* mididd.c
*
* Multimedia kernel driver support component (esddrv)
*
* Copyright (c) 1991 - 1995 Microsoft Corporation. All Rights Reserved.
*
* Driver for midi input and output devices
*
* -- Midi driver entry points (modMessage, midMessage)
* -- Auxiliary task (necessary for receiving Apcs and generating
* callbacks ASYNCRHONOUSLY)
* -- Interface to kernel driver (NtDeviceIoControlFile)
* -- Midi parsing code (ported from Windows 3.1).
*
* History
* 01-Feb-1992 - Robin Speed (RobinSp) wrote it
*
***************************************************************************/
#include "esddrv.h"
#include <ntddmidi.h>
/*****************************************************************************
internal declarations
****************************************************************************/
#define D1 dprintf1
#define D2 dprintf2
#define D3 dprintf3
// Stack size for our auxiliary task
#define MIDI_STACK_SIZE 300
#define SYSEX_ERROR 0xFF // internal error for sysex's on input
// Functions for auxiliary thread to perform
typedef enum {
MidiThreadInvalid,
MidiThreadAddBuffer,
MidiThreadSetState,
MidiThreadSetData,
MidiThreadClose,
MidiThreadTerminate
} MIDITHREADFUNCTION;
//
// Our local buffers for interfacing to midi input
#define LOCAL_MIDI_DATA_SIZE 20
typedef struct _LOCALMIDIHDR {
OVERLAPPED Ovl;
DWORD BytesReturned;
struct _LOCALMIDIHDR *lpNext; // Queueing (really debug only)
BOOL Done; // Driver completed buffer
PVOID pClient; // Our instance data for Apcs
MIDI_DD_INPUT_DATA MidiData; // What the driver wants to process
BYTE ExtraData[LOCAL_MIDI_DATA_SIZE - sizeof(ULONG)];
// The rest of our input buffer
} LOCALMIDIHDR, *PLOCALMIDIHDR;
// Midi input data
#define NUMBER_OF_LOCAL_MIDI_BUFFERS 8
typedef struct {
//
// Static data for managing midi input
//
BOOL fMidiInStarted; // Do we think midi in is running ?
DWORD dwMsg; // Current short msg
DWORD dwCurData; // Position in long message
BYTE status; // Running status byte
BOOLEAN fSysex; // Processing extended message
BOOLEAN Bad; // Input not working properly
BYTE bBytesLeft; // Bytes left in short message
BYTE bBytePos; // Position in short message
DWORD dwCurTime; // Latest time from driver
DWORD dwMsgTime; // Time to insert into message
// in milliseconds since device
// was opened
PLOCALMIDIHDR DeviceQueue; // Keep track of what the device
// has (debugging only)
LOCALMIDIHDR // Driver interface buffers
Bufs[NUMBER_OF_LOCAL_MIDI_BUFFERS];// When input is active these
// are queued on the device
// except while data is being
// processed from them
} LOCALMIDIDATA, *PLOCALMIDIDATA;
//
// per allocation structure for Midi
//
typedef struct tag_MIDIALLOC {
struct tag_MIDIALLOC *Next; // Chain of devices
UINT DeviceNumber; // Number of device
UINT DeviceType; // MidiInput or MidiOutput
DWORD dwCallback; // client's callback
DWORD dwInstance; // client's instance data
HMIDI hMidi; // handle for stream
HANDLE hDev; // Midi device handle
LPMIDIHDR lpMIQueue; // Buffers sent to device
// This is only required so that
// CLOSE knows when things have
// really finished.
// notify. This is only accessed
// on the device thread and its
// apcs so does not need any
// synchronized access.
HANDLE Event; // Event for driver syncrhonization
// and notification of auxiliary
// task operation completion.
MIDITHREADFUNCTION AuxFunction; // Function for thread to perform
union {
LPMIDIHDR pHdr; // Buffer to pass in aux task
ULONG State; // State to set
struct {
ULONG Function; // IOCTL to use
PBYTE pData; // Data to set or get
ULONG DataLen; // Length of data
} GetSetData;
} AuxParam;
// 0 means terminate task.
HANDLE ThreadHandle; // Handle for termination ONLY
HANDLE AuxEvent1; // Aux thread waits on this
HANDLE AuxEvent2; // Aux thread caller waits on this
DWORD AuxReturnCode; // Return code from Aux task
DWORD dwFlags; // Open flags
PLOCALMIDIDATA Mid; // Extra midi input structures
int l; // Helper global for modMidiLength
} MIDIALLOC, *PMIDIALLOC;
PMIDIALLOC MidiHandleList; // Our chain of wave handles
/*****************************************************************************
internal function prototypes
****************************************************************************/
STATIC DWORD midiGetDevCaps(DWORD id, UINT DeviceType, LPBYTE lpCaps,
DWORD dwSize);
STATIC DWORD midiThread(LPVOID lpParameter);
STATIC void midiCleanUp(PMIDIALLOC pClient);
STATIC DWORD midiThreadCall(MIDITHREADFUNCTION Function, PMIDIALLOC pClient);
STATIC DWORD midiSetState(PMIDIALLOC pClient, ULONG State);
STATIC void midiInOvl(DWORD dwRet, DWORD dwBytes, LPOVERLAPPED pOverlap);
STATIC DWORD midiInWrite(LPMIDIHDR pHdr, PMIDIALLOC pClient);
STATIC DWORD midiOutWrite(PBYTE pData, ULONG Len, PMIDIALLOC pClient);
STATIC void midiBlockFinished(LPMIDIHDR lpHdr, DWORD MsgId);
STATIC void midiCallback(PMIDIALLOC pMidi, DWORD msg, DWORD dw1, DWORD dw2);
STATIC int modMIDIlength(PMIDIALLOC pClient, BYTE b);
STATIC void midByteRec(PMIDIALLOC pClient, BYTE byte);
STATIC void midSendPartBuffer(PMIDIALLOC pClient);
STATIC void midFreeQ(PMIDIALLOC pClient);
STATIC void midiFlush(PMIDIALLOC pClient);
/****************************************************************************
* @doc INTERNAL
*
* @api VOID | TerminateMidi | Free all midi resources for esddrv.dll
*
* @rdesc None
***************************************************************************/
VOID TerminateMidi(VOID)
{
//
// Don't do any cleanup - Midi input resources cleaned up on Close.
//
}
/****************************************************************************
* @doc INTERNAL
*
* @api void | midiGetDevCaps | Get the device capabilities.
*
* @parm DWORD | id | Device id
*
* @parm UINT | DeviceType | type of device
*
* @parm LPBYTE | lpCaps | Far pointer to a MIDIOUTCAPS structure to
* receive the information.
*
* @parm DWORD | dwSize | Size of the MIDIOUTCAPS structure.
*
* @rdesc There is no return value.
***************************************************************************/
STATIC DWORD midiGetDevCaps(DWORD id, UINT DeviceType,
LPBYTE lpCaps, DWORD dwSize)
{
return sndGetData(DeviceType, id, dwSize, lpCaps,
IOCTL_MIDI_GET_CAPABILITIES);
}
/****************************************************************************
* @doc INTERNAL
*
* @api DWORD | midiOpen | Open midi device and set up logical device data
* and auxilary task for issuing requests and servicing Apc's
*
* @parm MIDIDEVTYPE | DeviceType | Whether it's a midi input or output device
*
* @parm DWORD | id | The device logical id
*
* @parm DWORD | msg | Input parameter to modMessage
*
* @parm DWORD | dwUser | Input parameter to modMessage - pointer to
* application's handle (generated by this routine)
*
* @parm DWORD | dwParam1 | Input parameter to modMessage
*
* @parm DWORD | dwParam2 | Input parameter to modMessage
*
* @rdesc modMessage return code.
***************************************************************************/
STATIC DWORD midiOpen(UINT DeviceType,
DWORD id,
DWORD dwUser,
DWORD dwParam1,
DWORD dwParam2)
{
PMIDIALLOC pClient; // pointer to client information structure
MMRESULT mRet;
// dwParam1 contains a pointer to a MIDIOPENDESC
// dwParam2 contains midi driver specific flags in the LOWORD
// and generic driver flags in the HIWORD
//
// allocate my per-client structure
//
if (DeviceType == MidiOutDevice) {
pClient = (PMIDIALLOC)HeapAlloc(hHeap, 0, sizeof(MIDIALLOC));
if (pClient != NULL) {
memset(pClient, 0, sizeof(MIDIALLOC));
}
} else {
WinAssert(DeviceType == MidiInDevice);
pClient = (PMIDIALLOC)HeapAlloc(hHeap, 0,
sizeof(struct _x{MIDIALLOC S1; LOCALMIDIDATA S2;}));
if (pClient != NULL) {
memset(pClient, 0, sizeof(struct _x{MIDIALLOC S1; LOCALMIDIDATA S2;}));
}
}
if (pClient == NULL) {
return MMSYSERR_NOMEM;
}
if (DeviceType == MidiInDevice) {
int i;
pClient->Mid = (PLOCALMIDIDATA)(pClient + 1);
for (i = 0 ;i < NUMBER_OF_LOCAL_MIDI_BUFFERS ; i++) {
pClient->Mid->Bufs[i].pClient = pClient;
}
}
//
// and fill it with info
//
// (note that setting everything to 0 correctly initialized our
// midi input processing static data).
pClient->DeviceType = DeviceType;
pClient->dwCallback = ((LPMIDIOPENDESC)dwParam1)->dwCallback;
pClient->dwInstance = ((LPMIDIOPENDESC)dwParam1)->dwInstance;
pClient->hMidi = ((LPMIDIOPENDESC)dwParam1)->hMidi;
pClient->dwFlags = dwParam2;
//
// See if we can open our device
// If it's only a query be sure only to open for read, otherwise
// we could get STATUS_BUSY if someone else is writing to the
// device.
//
mRet = sndOpenDev(DeviceType,
id,
&pClient->hDev,
(GENERIC_READ | GENERIC_WRITE));
if (mRet != MMSYSERR_NOERROR) {
midiCleanUp(pClient);
return mRet;
}
//
// Create our event for syncrhonization with the device driver
//
pClient->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pClient->Event == NULL) {
midiCleanUp(pClient);
return MMSYSERR_NOMEM;
}
if (DeviceType == MidiInDevice) {
//
// Create our event pair for synchronization with the auxiliary
// thread
//
pClient->AuxEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pClient->AuxEvent1 == NULL) {
midiCleanUp(pClient);
return MMSYSERR_NOMEM;
}
pClient->AuxEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pClient->AuxEvent2 == NULL) {
midiCleanUp(pClient);
return MMSYSERR_NOMEM;
}
//
// Create our auxiliary thread for sending buffers to the driver
// and collecting Apcs
//
mRet = mmTaskCreate((LPTASKCALLBACK)midiThread,
&pClient->ThreadHandle,
(DWORD)pClient);
if (mRet != MMSYSERR_NOERROR) {
midiCleanUp(pClient);
return MMSYSERR_NOMEM;
}
//
// Make sure the thread has really started
//
WaitForSingleObject(pClient->AuxEvent2, INFINITE);
}
//
// give the client my driver dw
//
{
PMIDIALLOC *pUserHandle;
pUserHandle = (PMIDIALLOC *)dwUser;
*pUserHandle = pClient;
}
//
// sent client his OPEN callback message
//
midiCallback(pClient, DeviceType == MidiOutDevice ? MOM_OPEN : MIM_OPEN,
0L, 0L);
return MMSYSERR_NOERROR;
}
/****************************************************************************
* @doc INTERNAL
*
* @api void | midiCleanUp | Free resources for a midi device
*
* @parm PMIDIALLOC | pClient | Pointer to a MIDIALLOC structure describing
* resources to be freed.
*
* @rdesc There is no return value.
*
* @comm If the pointer to the resource is NULL then the resource has not
* been allocated.
***************************************************************************/
STATIC void midiCleanUp(PMIDIALLOC pClient)
{
if (pClient->hDev != INVALID_HANDLE_VALUE) {
CloseHandle(pClient->hDev);
}
if (pClient->AuxEvent1) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?