mirror of
https://github.com/reactos/reactos.git
synced 2024-11-03 13:25:57 +00:00
375 lines
11 KiB
C
375 lines
11 KiB
C
/*
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Sound System
|
|
* FILE: drivers/multimedia/audio/sndblst/sndblst.c
|
|
* PURPOSE: Sound Blaster / Pro / 16 driver
|
|
* PROGRAMMER: Andrew Greenwood (silverblade@reactos.org)
|
|
*
|
|
* UPDATE HISTORY: Feb 25, 2009: New rewrite started
|
|
*
|
|
*/
|
|
|
|
/* DEFINES AND INCLUDES ******************************************************/
|
|
|
|
#include <ntddk.h>
|
|
#include <windef.h>
|
|
#include <mmsystem.h>
|
|
#include <debug.h>
|
|
|
|
#define CompleteIrpAndReturn(irp, status) \
|
|
irp->IoStatus.Status = status; \
|
|
irp->IoStatus.Information = 0; \
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT); \
|
|
return status;
|
|
|
|
|
|
/* FORWARD DECLARATIONS *****************************************************/
|
|
|
|
static VOID NTAPI
|
|
UnloadSoundBlaster(PDRIVER_OBJECT DriverObject);
|
|
|
|
|
|
/* DEVICE "DISCOVERY" *******************************************************/
|
|
/* Nb: These need to go in the helper lib */
|
|
|
|
typedef NTSTATUS (*SOUNDDEVICEENUMERATIONCALLBACK)(
|
|
IN PUNICODE_STRING DeviceRegistryPath);
|
|
|
|
NTSTATUS
|
|
EnumerateSoundDevices(
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PWSTR RegistrySubKey,
|
|
IN SOUNDDEVICEENUMERATIONCALLBACK Callback)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES RegAttributes;
|
|
HKEY MainKeyHandle, ChildKeyHandle;
|
|
UNICODE_STRING UnicodeSubkeyName, DeviceKeyName;
|
|
KEY_BASIC_INFORMATION KeyInfo, *FinalKeyInfo;
|
|
ULONG i = 0, NeededDataLength = 0, FinalDataLength = 0, NameLength = 0;
|
|
|
|
/* Turn the subkey name into a Unicode string */
|
|
RtlInitUnicodeString(&UnicodeSubkeyName, RegistrySubKey);
|
|
|
|
/* Open the registry key for the service */
|
|
InitializeObjectAttributes(&RegAttributes,
|
|
RegistryPath,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL);
|
|
|
|
Status = ZwOpenKey(&MainKeyHandle, KEY_READ, &RegAttributes);
|
|
|
|
if ( ! NT_SUCCESS(Status) )
|
|
{
|
|
DPRINT("Failed to open registry key\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Open the subkey usually named "Parameters" */
|
|
InitializeObjectAttributes(&RegAttributes,
|
|
&UnicodeSubkeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
MainKeyHandle,
|
|
(PSECURITY_DESCRIPTOR) NULL);
|
|
|
|
Status = ZwOpenKey(&ChildKeyHandle, KEY_ENUMERATE_SUB_KEYS, &RegAttributes);
|
|
|
|
/* We're done with the main key now */
|
|
ZwClose(MainKeyHandle);
|
|
|
|
if ( ! NT_SUCCESS(Status) )
|
|
{
|
|
DPRINT("Failed to open registry subkeys for enumeration\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Enumerate through the device keys */
|
|
while ( ( Status = ZwEnumerateKey(ChildKeyHandle,
|
|
i,
|
|
KeyBasicInformation,
|
|
&KeyInfo,
|
|
sizeof(KEY_BASIC_INFORMATION),
|
|
&NeededDataLength) ) != STATUS_NO_MORE_ENTRIES )
|
|
{
|
|
PWSTR EnumeratedKeyName, StartOfEnumeratedKeyName;
|
|
|
|
DPRINT("Found subkey %d\n", i);
|
|
|
|
FinalDataLength = NeededDataLength + FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
|
|
DPRINT("Allocating %d bytes\n", FinalDataLength);
|
|
|
|
FinalKeyInfo = (PKEY_BASIC_INFORMATION) ExAllocatePool(PagedPool, FinalDataLength);
|
|
|
|
if ( ! FinalKeyInfo )
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
/* This time we get the real info */
|
|
Status = ZwEnumerateKey(ChildKeyHandle,
|
|
i,
|
|
KeyBasicInformation,
|
|
FinalKeyInfo,
|
|
FinalDataLength,
|
|
&NeededDataLength);
|
|
|
|
if ( ! NT_SUCCESS(Status) )
|
|
{
|
|
DPRINT("FAILED to enumerate key!\n");
|
|
}
|
|
else
|
|
{
|
|
NameLength = RegistryPath->Length + sizeof(WCHAR) +
|
|
UnicodeSubkeyName.Length + sizeof(WCHAR) +
|
|
FinalKeyInfo->NameLength + sizeof(UNICODE_NULL);
|
|
|
|
DPRINT("Allocating memory for name (%d bytes)\n", NameLength);
|
|
|
|
EnumeratedKeyName = (PWSTR) ExAllocatePool(PagedPool, NameLength);
|
|
|
|
if ( ! EnumeratedKeyName )
|
|
{
|
|
ExFreePool((PVOID)FinalKeyInfo);
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
StartOfEnumeratedKeyName = EnumeratedKeyName;
|
|
|
|
/* Start building the registry path using the service key */
|
|
RtlCopyMemory(EnumeratedKeyName,
|
|
RegistryPath->Buffer,
|
|
RegistryPath->Length);
|
|
|
|
EnumeratedKeyName += RegistryPath->Length / sizeof(WCHAR);
|
|
EnumeratedKeyName[0] = '\\';
|
|
++ EnumeratedKeyName;
|
|
|
|
/* Append the parameters subkey */
|
|
RtlCopyMemory(EnumeratedKeyName,
|
|
RegistrySubKey,
|
|
UnicodeSubkeyName.Length);
|
|
|
|
EnumeratedKeyName += UnicodeSubkeyName.Length / sizeof(WCHAR);
|
|
EnumeratedKeyName[0] = '\\';
|
|
++ EnumeratedKeyName;
|
|
|
|
/* And finally append the enumerated key name */
|
|
RtlCopyMemory(EnumeratedKeyName,
|
|
FinalKeyInfo->Name,
|
|
FinalKeyInfo->NameLength);
|
|
|
|
EnumeratedKeyName += FinalKeyInfo->NameLength / sizeof(WCHAR);
|
|
EnumeratedKeyName[0] = UNICODE_NULL;
|
|
|
|
/* Reset pointer */
|
|
EnumeratedKeyName = StartOfEnumeratedKeyName;
|
|
|
|
/* Convert into a Unicode string for the callback */
|
|
RtlInitUnicodeString(&DeviceKeyName, EnumeratedKeyName);
|
|
|
|
Callback(&DeviceKeyName);
|
|
|
|
/* No longer need the key name */
|
|
ExFreePool((PVOID)EnumeratedKeyName);
|
|
EnumeratedKeyName = NULL;
|
|
}
|
|
|
|
/* No longer need the key info */
|
|
ExFreePool((PVOID)FinalKeyInfo);
|
|
FinalKeyInfo = NULL;
|
|
|
|
++ i;
|
|
}
|
|
|
|
/* We're done with enumeration so close this */
|
|
ZwClose(ChildKeyHandle);
|
|
|
|
/* This isn't an error */
|
|
if ( Status == STATUS_NO_MORE_ENTRIES )
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
/* No devices configured? */
|
|
if ( i == 0 && Status == STATUS_NO_MORE_ENTRIES )
|
|
{
|
|
Status = STATUS_DEVICE_CONFIGURATION_ERROR;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PublishWaveOutDevice(
|
|
IN DWORD HardwareDeviceIndex,
|
|
IN PWSTR BaseDeviceName,
|
|
IN DWORD DeviceIndex,
|
|
IN LPWAVEOUTCAPS Capabilities)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
typedef struct _SOUND_BLASTER_DEVICE
|
|
{
|
|
DWORD BasePort;
|
|
DWORD MidiUartBasePort;
|
|
|
|
DWORD Irq;
|
|
|
|
DWORD DmaChannel_8;
|
|
DWORD DmaChannel_16;
|
|
|
|
DWORD DspVersion;
|
|
|
|
DWORD ActualDmaBufferSize;
|
|
DWORD DmaBufferSize;
|
|
} SOUND_BLASTER_DEVICE;
|
|
|
|
|
|
NTSTATUS
|
|
AllocateSoundBlasterStructure(OUT SOUND_BLASTER_DEVICE* SoundBlasterDevice)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* callback */
|
|
/*
|
|
Configuration options within the registry:
|
|
REG_DWORD Actual Dma Buffer Size 0x00004000
|
|
REG_DWORD Configuration Error 0xffffffff
|
|
REG_DWORD Dma Buffer Size 0x00004000
|
|
REG_DWORD DmaChannel 0x00000001
|
|
REG_DWORD DmaChannel16 0x00000005
|
|
REG_DWORD DSP Version 0x00000405
|
|
REG_DWORD Interrupt 0x00000005
|
|
REG_DWORD Load Type 0x00000000
|
|
REG_BINARY Mixer Settings ??
|
|
REG_DWORD MPU401 Port 0xffffffff
|
|
REG_DWORD Port 0x00000220
|
|
*/
|
|
|
|
NTSTATUS
|
|
ConfigureSoundBlasterDevice(IN PUNICODE_STRING DeviceRegistryPath)
|
|
{
|
|
OBJECT_ATTRIBUTES RegAttributes;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
HKEY ConfigKeyHandle;
|
|
|
|
DPRINT("Configuring Sound Blaster (config at %S)\n", DeviceRegistryPath->Buffer);
|
|
|
|
if ( ! DeviceRegistryPath )
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Open the registry key */
|
|
InitializeObjectAttributes(&RegAttributes,
|
|
DeviceRegistryPath,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL);
|
|
|
|
Status = ZwOpenKey(&ConfigKeyHandle, KEY_READ, &RegAttributes);
|
|
|
|
if ( ! NT_SUCCESS(Status) )
|
|
{
|
|
DPRINT("Failed to open config registry key\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Read configuration */
|
|
DPRINT("Reading configuration\n");
|
|
|
|
//Status = ZwQueryValueKey(ConfigKeyHandle,
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/* IRP DISPATCHERS **********************************************************/
|
|
|
|
static NTSTATUS NTAPI
|
|
CreateSoundBlaster(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT("Sound Blaster driver received IRP_MJ_CREATE\n");
|
|
|
|
CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
|
|
}
|
|
|
|
static NTSTATUS NTAPI
|
|
CloseSoundBlaster(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT("Sound Blaster driver received IRP_MJ_CLOSE\n");
|
|
|
|
CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
|
|
}
|
|
|
|
static NTSTATUS NTAPI
|
|
CleanupSoundBlaster(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT("Sound Blaster driver received IRP_MJ_CLEANUP\n");
|
|
|
|
CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
|
|
}
|
|
|
|
static NTSTATUS NTAPI
|
|
ControlSoundBlaster(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT("Sound Blaster driver received IRP_MJ_CONTROL\n");
|
|
|
|
CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
|
|
}
|
|
|
|
static NTSTATUS NTAPI
|
|
WriteToSoundBlaster(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT("Sound Blaster driver received IRP_MJ_WRITE\n");
|
|
|
|
CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
/* DRIVER ENTRYPOINT ********************************************************/
|
|
|
|
NTSTATUS NTAPI
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DPRINT("Sound Blaster driver by silverblade\n");
|
|
|
|
DriverObject->Flags = 0;
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = CreateSoundBlaster;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseSoundBlaster;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CleanupSoundBlaster;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlSoundBlaster;
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = WriteToSoundBlaster;
|
|
DriverObject->DriverUnload = UnloadSoundBlaster;
|
|
|
|
EnumerateSoundDevices(RegistryPath, L"Parameters", ConfigureSoundBlasterDevice);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static VOID NTAPI
|
|
UnloadSoundBlaster(IN PDRIVER_OBJECT DriverObject)
|
|
{
|
|
DPRINT("Sound Blaster driver is being unloaded\n");
|
|
}
|