/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel Streaming * FILE: drivers/wdm/audio/sysaudio/main.c * PURPOSE: System Audio graph builder * PROGRAMMER: Andrew Greenwood * Johannes Anderwald * HISTORY: * 8 Jul 07 Started basic implementation */ #include "sysaudio.h" #define NDEBUG #include const GUID KSCATEGORY_SYSAUDIO = {0xA7C7A5B1L, 0x5AF3, 0x11D1, {0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07}}; const GUID KSCATEGORY_AUDIO_DEVICE = {0xFBF6F530L, 0x07B9, 0x11D2, {0xA7, 0x1E, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}}; const GUID KSCATEGORY_PREFERRED_WAVEOUT_DEVICE = {0xD6C5066EL, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}}; const GUID KSCATEGORY_PREFERRED_WAVEIN_DEVICE = {0xD6C50671L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}}; const GUID KSCATEGORY_PREFERRED_MIDIOUT_DEVICE = {0xD6C50674L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}}; PVOID AllocateItem( IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes) { PVOID Item = ExAllocatePool(PoolType, NumberOfBytes); if (!Item) return Item; RtlZeroMemory(Item, NumberOfBytes); return Item; } VOID FreeItem( IN PVOID Item) { ExFreePool(Item); } VOID NTAPI SysAudio_Unload(IN PDRIVER_OBJECT DriverObject) { DPRINT("SysAudio_Unload called\n"); } NTSTATUS NTAPI SysAudio_Shutdown( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PKSAUDIO_DEVICE_ENTRY DeviceEntry; PSYSAUDIODEVEXT DeviceExtension; PLIST_ENTRY Entry; DPRINT("SysAudio_Shutdown called\n"); DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension; while(!IsListEmpty(&DeviceExtension->KsAudioDeviceList)) { Entry = RemoveHeadList(&DeviceExtension->KsAudioDeviceList); DeviceEntry = (PKSAUDIO_DEVICE_ENTRY)CONTAINING_RECORD(Entry, KSAUDIO_DEVICE_ENTRY, Entry); DPRINT("Freeing item %wZ\n", &DeviceEntry->DeviceName); /* dereference audio device file object */ ObDereferenceObject(DeviceEntry->FileObject); /* close audio device handle */ ZwClose(DeviceEntry->Handle); /* free device string */ RtlFreeUnicodeString(&DeviceEntry->DeviceName); /* free audio device entry */ FreeItem(DeviceEntry); } Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } NTSTATUS NTAPI SysAudio_Pnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IrpStack; UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio"); SYSAUDIODEVEXT *DeviceExtension; /* Get current irp stack */ IrpStack = IoGetCurrentIrpStackLocation(Irp); /* Fetch the device extension */ DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension; ASSERT(DeviceExtension); if (IrpStack->MinorFunction == IRP_MN_REMOVE_DEVICE) { /* Unregister the echo cancel hook */ if (DeviceExtension->EchoCancelNotificationEntry) IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry); /* Unregister the ks audio hook */ if (DeviceExtension->KsAudioNotificationEntry) IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry); /* Destroy our symbolic link */ IoDeleteSymbolicLink(&SymlinkName); } else if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE) { /* Sysaudio can not be disabled */ Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; } /* Perform default pnp actions */ return KsDefaultDispatchPnp(DeviceObject, Irp); } NTSTATUS NTAPI SysAudio_AddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) { NTSTATUS Status; UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\sysaudio"); UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio"); PDEVICE_OBJECT DeviceObject, NextDeviceObject; SYSAUDIODEVEXT *DeviceExtension; DPRINT("SysAudio_AddDevice called\n"); /* Create the device */ Status = IoCreateDevice(DriverObject, sizeof(SYSAUDIODEVEXT), &DeviceName, FILE_DEVICE_KS, 0, FALSE, &DeviceObject); /* Check for success */ if (!NT_SUCCESS(Status)) { DPRINT("Failed to create \\Device\\sysaudio !\n"); return Status; } /* Register device interfaces */ Status = SysAudioRegisterDeviceInterfaces(PhysicalDeviceObject); if (!NT_SUCCESS(Status)) { /* Failed to register * Create a hack interface */ Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName); if (!NT_SUCCESS(Status)) { IoDeleteDevice(DeviceObject); DPRINT1("Failed to create sysaudio symlink!\n"); return Status; } } /* Acquire device extension */ DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension; /* Initialize device extension */ RtlZeroMemory(DeviceExtension, sizeof(SYSAUDIODEVEXT)); /* Initialize the mutex */ KeInitializeSpinLock(&DeviceExtension->Lock); /* Initialize the ks audio device list */ InitializeListHead(&DeviceExtension->KsAudioDeviceList); /* Allocate kernel streaming device header */ Status = SysAudioAllocateDeviceHeader(DeviceExtension); if (!NT_SUCCESS(Status)) { DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status); goto cleanup; } /* Register device notification hooks */ Status = SysAudioRegisterNotifications(DriverObject, DeviceObject); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to register device notifications\n"); goto cleanup; } /* Load kmixer */ Status = SysAudioOpenKMixer(DeviceExtension); if (!NT_SUCCESS(Status)) { DPRINT1("SysAudioOpenKMixer failed with %x\n", Status); goto cleanup; } /* set io flags */ DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE; /* clear initializing flag */ DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING; /* atttach to device stack */ NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); KsSetDevicePnpAndBaseObject(DeviceExtension->KsDeviceHeader, NextDeviceObject, DeviceObject); /* register shutdown notification */ IoRegisterShutdownNotification(DeviceObject); /* Done */ return STATUS_SUCCESS; cleanup: if (DeviceExtension->KsAudioNotificationEntry) IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry); if (DeviceExtension->EchoCancelNotificationEntry) IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry); IoDeleteSymbolicLink(&SymlinkName); IoDeleteDevice(DeviceObject); return Status; } NTSTATUS NTAPI DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { DPRINT("System audio graph builder (sysaudio) started\n"); /* Let ks handle these */ KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CREATE); KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE); KsSetMajorFunctionHandler(DriverObject, IRP_MJ_WRITE); KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL); /* Let ks handle these */ DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp; /* Use provided ks unload function */ DriverObject->DriverUnload = KsNullDriverUnload; /* Sysaudio needs to do work on pnp, so handle it */ DriverObject->MajorFunction[IRP_MJ_PNP] = SysAudio_Pnp; DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = SysAudio_Shutdown; DriverObject->DriverExtension->AddDevice = SysAudio_AddDevice; /* done */ return STATUS_SUCCESS; }