Hello everyone!
This list and your efforts here are a great resource.
I'm a fairly experienced software engineer, but my knowledge in regards
to OS (and in particular Windows) programming is limited.
Hopefully there's someone out there that can lend a helping hand in my
endeavor.
The ultimate goal is as follows:
Have bi-directional stream exchange between the raw operating system
audio and JACK (jackaudio.org).
In other words, the audio samples rendered through Windows should be
available in a user-space application instead of being sent to a DAC,
and the samples recorded from the microphone should be read from
user-space memory instead of from an ADC.
To achieve this, I am trying my luck with MSVAD.
Since JACK (a really potent audio framework) is used, it would be
beneficial to have very little latency between both systems.
My initial approach is thus to modify the SaveData part of MSVAD and
share a fixed-size buffer between the driver and the JACK user-space
application.
Now from most research it seems that this ultimately will require IOCTL
structures to break the boundary between kernel and user space (in a way
that is regarded as sane and not a massive security hole).
As additional reference, I found the NT Insider sample about IOCTL
(www.osronline.com/article.cfm%5Earticle=39.htm) really helpful.
In another thread on this list
(www.freelists.org/post/wdmaudiodev/for-help-in-implementation-virtual-audio-driver),
there is a similar approach with a little code to start with.
I combined both of these resources with the MS samples about IOCTL
(github.com/microsoft/Windows-driver-samples/blob/master/general/ioctl/wdm/sys/sioctl.c)
and ended up with most of the required boilerplate for the driver (which
is at the very bottom). But it fails. Installing the driver is no
problem as is evident by the kernel debug traces. As soon as an
application tries to create a handle to the driver with CreateFile() or
as soon as you manually inspect its properties with WinObj, you get a
fatal system error (STATUS_ACCESS_VIOLATION):
SYSTEM_SERVICE_EXCEPTION (3b)
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p
referenced memory at 0x%p. The memory could not be %s.
STACK_TEXT:
fffff882`bff483e0 fffff800`3742afeb : ffffd409`00000010
fffff882`bff48458 ffffd409`000000d8 fffff882`bff48450 :
portcls!AcquireRemoveLock+0x4
fffff882`bff48420 fffff807`042bc189 : ffffd409`71eef410
fffff882`bff48750 00000000`00000025 ffffd409`7da3c2a0 :
portcls!DispatchCreate+0x2b
fffff882`bff48450 fffff807`042631f4 : 00000000`00000000
00000000`00000025 00000000`00000000 fffff807`04262663 :
nt!IofCallDriver+0x59
fffff882`bff48490 fffff807`047331a2 : fffff882`bff48750
ffffd409`71eef410 00000000`00000025 ffffd409`7da3c2a0 :
nt!IoCallDriverWithTracing+0x34
fffff882`bff484e0 fffff807`047aa029 : ffffd409`7da3c2a0
ffffd409`7da3c200 ffffd409`73e3a870 00000000`00000001 :
nt!IopParseDevice+0x632
fffff882`bff48650 fffff807`047a862f : ffffd409`73e3a800
fffff882`bff488b8 00000000`00000040 ffffd409`71f35bc0 :
nt!ObpLookupObjectName+0x719
fffff882`bff48820 fffff807`0470e874 : 00000000`00000001
00000000`00000000 00000000`00000000 00000000`00000028 :
nt!ObOpenObjectByNameEx+0x1df
fffff882`bff48960 fffff807`0470e459 : 00000000`0014fd40
00000000`00000000 00000000`0014fd98 00000000`0014fd58 :
nt!IopCreateFile+0x404
fffff882`bff48a00 fffff807`043c3285 : 00000000`00000000
00000000`00000000 00000000`00000000 fffff807`047375df :
nt!NtCreateFile+0x79
fffff882`bff48a90 00007ff9`363df034 : 00007ff9`3311fb26
00000000`00000000 00000000`c0000000 ffffffff`fffffffe :
nt!KiSystemServiceCopyEnd+0x25
00000000`0014fcc8 00007ff9`3311fb26 : 00000000`00000000
00000000`c0000000 ffffffff`fffffffe 00000000`00000000 :
ntdll!NtCreateFile+0x14
00000000`0014fcd0 00007ff9`3311f816 : 00000000`0000000a
00000000`00000000 00000001`40043ff4 00000000`00568b20 :
KERNELBASE!CreateFileInternal+0x2f6
00000000`0014fe40 00000001`40001185 : 00007ff9`327eb510
00007ff9`00000001 00000001`400454b0 00000001`40034469 :
KERNELBASE!CreateFileW+0x66
00000000`0014fea0 00007ff9`327eb510 : 00007ff9`00000001
00000001`400454b0 00000001`40034469 00000000`00000003 :
BridgeDaemon+0x1185
00000000`0014fea8 00007ff9`00000001 : 00000001`400454b0
00000001`40034469 00000000`00000003 00000000`40000000 :
ucrtbase!iob+0xb0
00000000`0014feb0 00000001`400454b0 : 00000001`40034469
00000000`00000003 00000000`40000000 00000000`00000000 :
0x00007ff9`00000001
00000000`0014feb8 00000001`40034469 : 00000000`00000003
00000000`40000000 00000000`00000000 00000000`00000000 :
BridgeDaemon+0x454b0
00000000`0014fec0 00000000`00000003 : 00000000`40000000
00000000`00000000 00000000`00000000 00000000`00000000 :
BridgeDaemon+0x34469
00000000`0014fec8 00000000`40000000 : 00000000`00000000
00000000`00000000 00000000`00000000 00000001`40033f50 : 0x3
00000000`0014fed0 00000000`00000000 : 00000000`00000000
00000000`00000000 00000001`40033f50 00000000`00000000 : 0x40000000
I'm lost at this point. The use of dispatch routines is probably not
correct, but it's not obvious to me how to do it correctly.
This approach has likely been tried numerous times before. Can you point
me to any working solutions or references on how to proceed?
Best regards,
Fabian
#include <portcls.h>
#define PUT_GUIDS_HERE
#define MAX_MINIPORTS 3
#define NT_DEVICE_NAME L"\\Device\\MSVAD"
#define DOS_DEVICE_NAME L"\\??\\MSVAD"
#define DPF_ENTER(...) { DbgPrint(__VA_ARGS__); DbgPrint("\n"); }
extern "C" DRIVER_INITIALIZE DriverEntry;
DRIVER_ADD_DEVICE AddDevice;
NTSTATUS StartDevice(IN PDEVICE_OBJECT, IN PIRP, IN PRESOURCELIST);
DRIVER_UNLOAD DriverUnload;
DRIVER_DISPATCH IOCTLDeviceControl;
typedef void(*fnPcDriverUnload) (PDRIVER_OBJECT);
fnPcDriverUnload g_DriverUnloadRoutine = NULL;
//=============================================================================
#pragma code_seg("INIT")
extern "C" NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPathName
)
{
DPF_ENTER("[DriverEntry]");
NTSTATUS ntStatus;
ntStatus = PcInitializeAdapterDriver(
DriverObject,
RegistryPathName,
(PDRIVER_ADD_DEVICE)AddDevice
);
if (!NT_SUCCESS(ntStatus)) { DPF_ENTER("PcInitializeAdapterDriver failed
(%p)", ntStatus); }
else { DPF_ENTER("PcInitializeAdapterDriver succeeded."); }
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOCTLDeviceControl;
g_DriverUnloadRoutine = DriverObject->DriverUnload;
DriverObject->DriverUnload = DriverUnload;
return ntStatus;
} // DriverEntry
#pragma code_seg()
#pragma code_seg("PAGE")
//=============================================================================
NTSTATUS
AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
{
DPF_ENTER("[AddDevice]");
NTSTATUS ntStatus;
UNICODE_STRING ntUnicodeString, ntWin32NameString;
PDEVICE_OBJECT deviceObject = NULL;
PAGED_CODE();
ntStatus = PcAddAdapterDevice(
DriverObject,
PhysicalDeviceObject,
PCPFNSTARTDEVICE(StartDevice),
MAX_MINIPORTS,
0
);
if (!NT_SUCCESS(ntStatus)) { DPF_ENTER("PcAddAdapterDevice failed (%p)",
ntStatus); }
else { DPF_ENTER("PcAddAdapterDevice succeeded."); }
RtlInitUnicodeString(&ntUnicodeString, NT_DEVICE_NAME);
RtlInitUnicodeString(&ntWin32NameString, DOS_DEVICE_NAME);
ntStatus = IoCreateDevice(
DriverObject,
0,
&ntUnicodeString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject
);
if (!NT_SUCCESS(ntStatus)) { DPF_ENTER("IoCreateDevice failed (%p)",
ntStatus); }
else { DPF_ENTER("IoCreateDevice succeeded."); }
ntStatus = IoCreateSymbolicLink(&ntWin32NameString, &ntUnicodeString);
if (!NT_SUCCESS(ntStatus)) { DPF_ENTER("IoCreateSymbolicLink failed
(%p)", ntStatus); }
else { DPF_ENTER("IoCreateSymbolicLink succeeded."); }
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
deviceObject->Flags |= DO_DIRECT_IO;
return ntStatus;
} // AddDevice
//=============================================================================
NTSTATUS
StartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PRESOURCELIST ResourceList
)
{
DPF_ENTER("[StartDevice]");
PAGED_CODE();
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(ResourceList);
NTSTATUS ntStatus= STATUS_SUCCESS;
return ntStatus;
} // StartDevice
//=============================================================================
VOID
DriverUnload
(
_In_ PDRIVER_OBJECT DriverObject
)
{
DPF_ENTER("[DriverUnload]");
PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
UNICODE_STRING uniWin32NameString;
PAGED_CODE();
RtlInitUnicodeString(&uniWin32NameString, DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&uniWin32NameString);
if (deviceObject != NULL)
{
IoDeleteDevice(deviceObject);
}
if (g_DriverUnloadRoutine != NULL)
{
g_DriverUnloadRoutine(DriverObject);
}
} // DriverUnload
//=============================================================================
NTSTATUS
IOCTLDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
DPF_ENTER("[IOCTLDeviceControl]");
PIO_STACK_LOCATION irpSp;
PAGED_CODE();
irpSp = IoGetCurrentIrpStackLocation(Irp);
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
case 0:
default:
return PcDispatchIrp(DeviceObject, Irp);
}
} // IOCTLDeviceControl
******************
WDMAUDIODEV addresses:
Post message: mailto:wdmaudiodev@xxxxxxxxxxxxx
Subscribe: mailto:wdmaudiodev-request@xxxxxxxxxxxxx?subject=subscribe
Unsubscribe: mailto:wdmaudiodev-request@xxxxxxxxxxxxx?subject=unsubscribe
Moderator: mailto:wdmaudiodev-moderators@xxxxxxxxxxxxx
URL to WDMAUDIODEV page:
http://www.wdmaudiodev.com/