windows-nt/Source/XPSP1/NT/drivers/wdm/audio/legacy/pcmvxd/pcmvxd.c

267 lines
7.5 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
#define DRIVER
#define NTKERN
#define _X86_
#define WIN32
#define DDK_VERSION 0x400
#define IRP_MJ_WRITE 0x04
#define CDECL
#define FAR
#define NEAR
#define NTAPI __stdcall
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
typedef ULONG BOOL;
typedef LONG DWORD;
typedef SHORT WORD;
typedef NTSTATUS (NTAPI *PCREATEFILE) (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
typedef NTSTATUS (NTAPI *PREFOBJECT) (HANDLE, ACCESS_MASK, POBJECT_TYPE, KPROCESSOR_MODE, PVOID *, POBJECT_HANDLE_INFORMATION);
typedef PIRP (NTAPI *PREQUESTIRP) (ULONG, PDEVICE_OBJECT, PVOID, ULONG, PLARGE_INTEGER, PIO_STATUS_BLOCK);
typedef NTSTATUS (FASTCALL *PCALLDRIVER) (PDEVICE_OBJECT, PIRP);
typedef PDEVICE_OBJECT (NTAPI *PGETRELATED) (PFILE_OBJECT);
typedef VOID (NTAPI *PDEREFOBJECT) (PVOID);
typedef NTSTATUS (NTAPI *PCLOSEHANDLE) (HANDLE);
typedef VOID (NTAPI *PQUEUEWORK) (PWORK_QUEUE_ITEM, WORK_QUEUE_TYPE);
/* wave data block header */
typedef struct wavehdr_tag {
LPSTR lpData; /* pointer to locked data buffer */
DWORD dwBufferLength; /* length of data buffer */
DWORD dwBytesRecorded; /* used for input only */
DWORD dwUser; /* for client's use */
DWORD dwFlags; /* assorted flags (see defines) */
DWORD dwLoops; /* loop control counter */
struct wavehdr_tag FAR *lpNext; /* reserved for driver */
DWORD reserved; /* reserved for driver */
} WAVEHDR, *PWAVEHDR, NEAR *NPWAVEHDR, FAR *LPWAVEHDR;
#include <ks.h>
#include <ksmedia.h>
typedef NTSTATUS (NTAPI *PCREATEPIN) (HANDLE, PKSPIN_CONNECT, HANDLE);
typedef struct _myConnect {
KSPIN_CONNECT;
KSDATARANGE_AUDIO;
} MY_PIN;
const CDECL GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
const CDECL GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
const CDECL GUID KSINTERFACESETID_Standard = {0x1A8766A0L, 0x62CE, 0x11CF, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00};
const CDECL GUID KSPROPSETID_Control = {0x1D58C920L, 0xAC9B, 0x11CF, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00};
const CDECL GUID KSDATAFORMAT_FORMAT_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, 0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a};
const CDECL GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00};
NTSTATUS PM_Callback(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);
VOID ClosePin(VOID);
HANDLE hMixerSink = NULL;
HANDLE hMixer = NULL;
MY_PIN pin;
BOOL MixerRunning = FALSE;
USHORT DeviceString[] = L"\\DosDevices\\KMIXER";
UNICODE_STRING UnicodeDeviceString = { 0, sizeof(DeviceString), DeviceString };
OBJECT_ATTRIBUTES ObjectAttributes = {sizeof(OBJECT_ATTRIBUTES),
NULL,
&UnicodeDeviceString,
0,
NULL,
NULL };
IO_STATUS_BLOCK IoStatusBlock;
PREQUESTIRP pRequest;
PCALLDRIVER pCallDriver;
PDEVICE_OBJECT pDeviceObject;
PFILE_OBJECT pFileObject = NULL;
HANDLE hNtosModule = NULL;
HANDLE hKsModule = NULL;
PQUEUEWORK pQueueWork;
VOID
OpenPin(VOID)
{
PCREATEPIN pCreatePin;
PCREATEFILE pCreateFile;
NTSTATUS Status;
PREFOBJECT pRefObject;
PGETRELATED pGetRelated;
/* We only support one mixer client through our VxD at a time */
if (MixerRunning)
{
_asm int 3
return;
}
ObjectAttributes.ObjectName->Length = sizeof(DeviceString) - 2;
/* Get entry points for all the WDM functions we will use */
pCreateFile = (PCREATEFILE) _PELDR_GetProcAddress("ntoskrnl.exe","ZwCreateFile",NULL);
pCreatePin = (PCREATEPIN) _PELDR_GetProcAddress("ks.sys","KsCreatePin",NULL);
pRefObject = (PREFOBJECT) _PELDR_GetProcAddress("ntoskrnl.exe","ObReferenceObjectByHandle",NULL);
pGetRelated = (PGETRELATED) _PELDR_GetProcAddress("ntoskrnl.exe","IoGetRelatedDeviceObject",NULL);
pRequest = (PREQUESTIRP) _PELDR_GetProcAddress("ntoskrnl.exe","IoBuildAsynchronousFsdRequest",NULL);
pCallDriver = (PCALLDRIVER) _PELDR_GetProcAddress("ntoskrnl.exe","IofCallDriver",NULL);
pQueueWork = (PQUEUEWORK) _PELDR_GetProcAddress("ntoskrnl.exe","ExQueueWorkItem",NULL);
if (!pCreateFile || !pCreatePin || !pRefObject || !pGetRelated || !pRequest || !pCallDriver || !pQueueWork)
{
_asm int 3
ClosePin();
return;
}
/* Open the mixer */
(*pCreateFile) (&hMixer,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
0,
NULL,
0);
if (hMixer == NULL)
{
_asm int 3
ClosePin();
return;
}
/* We connect to the KMIXER SINK */
pin.PinId = 1; // KMIXER SINK
pin.PinToHandle = NULL; // no "connect to"
pin.Interface.Set = KSINTERFACESETID_Standard;
pin.Interface.Id = KSINTERFACE_STANDARD_WAVE_QUEUED;
pin.Medium.Set = KSMEDIUMSETID_Standard;
pin.Medium.Id = KSMEDIUM_STANDARD_DEVIO;
pin.Priority.PriorityClass = KSPRIORITY_NORMAL;
pin.Priority.PrioritySubClass = 0;
pin.DataRange.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
pin.DataRange.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
pin.DataRange.Specifier = KSDATAFORMAT_FORMAT_WAVEFORMATEX;
pin.DataRange.FormatSize = sizeof( KSDATARANGE_AUDIO );
pin.MaximumChannels = 2;
pin.MinimumSampleFrequency = 44000;
pin.MaximumSampleFrequency = 44000;
pin.MinimumBitsPerSample = 16;
pin.MaximumBitsPerSample = 16;
/* Open a pin */
Status = (*pCreatePin) ( hMixer, (PKSPIN_CONNECT) &pin, &hMixerSink );
if (!NT_SUCCESS(Status))
{
_asm int 3
ClosePin();
return;
}
/* Reference the file object for this pin */
Status = (*pRefObject) (hMixerSink, FILE_WRITE_DATA, NULL, KernelMode, &pFileObject, NULL);
if (!NT_SUCCESS(Status))
{
_asm int 3
ClosePin();
return;
}
/* Get the related device object for this pin */
pDeviceObject = (PVOID) (*pGetRelated) (pFileObject);
MixerRunning = TRUE;
return;
}
VOID
ClosePin(VOID)
{
PDEREFOBJECT pDeRefObject;
PCLOSEHANDLE pClose;
/* This is designed to bring us back to square one, even if we were not completely opened */
MixerRunning = FALSE;
/* First, close the file object (pFileObject, if it exists) */
if (pFileObject)
{
/* De-reference the file object */
pDeRefObject = (PDEREFOBJECT) _PELDR_GetProcAddress("ntoskrnl.exe","ObDereferenceObject",NULL);
if (!pDeRefObject)
{
_asm int 3
}
else
(*pDeRefObject) (pFileObject);
pFileObject = NULL;
}
/* Next, close the pin handle (hMixerSink, if it exists) */
if (hMixerSink)
{
pClose = (PCLOSEHANDLE) _PELDR_GetProcAddress("ntoskrnl.exe","ZwClose",NULL);
if (!pClose)
{
_asm int 3
}
else
(*pClose) (hMixerSink);
hMixerSink = NULL;
}
/* Finally, close the KMIXER handle (hMixer, if it exists) */
if (hMixer)
{
pClose = (PCLOSEHANDLE) _PELDR_GetProcAddress("ntoskrnl.exe","ZwClose",NULL);
if (!pClose)
{
_asm int 3
}
else
(*pClose) (hMixer);
hMixer = NULL;
}
return;
}
VOID
WritePin(LPWAVEHDR pData, PVOID pMyCallback, PVOID RefData)
{
KSSTATE DeviceState = KSSTATE_RUN;
PIRP pIrp = NULL;
PIO_STACK_LOCATION pIrpStack;
if (!MixerRunning)
{
_asm int 3
return;
}
pIrp = (*pRequest) (IRP_MJ_WRITE, pDeviceObject, (PVOID)pData, sizeof(WAVEHDR), 0, NULL);
if (!pIrp)
{
_asm int 3
return;
}
pIrpStack = IoGetNextIrpStackLocation(pIrp);
pIrpStack->FileObject = pFileObject;
IoSetCompletionRoutine(pIrp, pMyCallback, RefData, TRUE, TRUE, TRUE);
(*pCallDriver) ( pDeviceObject, pIrp );
return;
}