1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/sysaudio/main.c 5 * PURPOSE: System Audio graph builder 6 * PROGRAMMER: Andrew Greenwood 7 * Johannes Anderwald 8 * HISTORY: 9 * 8 Jul 07 Started basic implementation 10 */ 11 12 #include "sysaudio.h" 13 14 #define NDEBUG 15 #include <debug.h> 16 17 #define TAG_SYSAUDIO 'AsyS' 18 19 const GUID KSCATEGORY_SYSAUDIO = {0xA7C7A5B1L, 0x5AF3, 0x11D1, {0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07}}; 20 const GUID KSCATEGORY_AUDIO_DEVICE = {0xFBF6F530L, 0x07B9, 0x11D2, {0xA7, 0x1E, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}}; 21 const GUID KSCATEGORY_PREFERRED_WAVEOUT_DEVICE = {0xD6C5066EL, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}}; 22 const GUID KSCATEGORY_PREFERRED_WAVEIN_DEVICE = {0xD6C50671L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}}; 23 const GUID KSCATEGORY_PREFERRED_MIDIOUT_DEVICE = {0xD6C50674L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}}; 24 25 PVOID 26 AllocateItem( 27 IN POOL_TYPE PoolType, 28 IN SIZE_T NumberOfBytes) 29 { 30 return ExAllocatePoolZero(PoolType, NumberOfBytes, TAG_SYSAUDIO); 31 } 32 33 VOID 34 FreeItem( 35 IN PVOID Item) 36 { 37 ExFreePoolWithTag(Item, TAG_SYSAUDIO); 38 } 39 40 VOID 41 NTAPI 42 SysAudio_Unload(IN PDRIVER_OBJECT DriverObject) 43 { 44 DPRINT("SysAudio_Unload called\n"); 45 } 46 47 NTSTATUS 48 NTAPI 49 SysAudio_Shutdown( 50 IN PDEVICE_OBJECT DeviceObject, 51 IN PIRP Irp) 52 { 53 PKSAUDIO_DEVICE_ENTRY DeviceEntry; 54 PSYSAUDIODEVEXT DeviceExtension; 55 PLIST_ENTRY Entry; 56 57 DPRINT("SysAudio_Shutdown called\n"); 58 59 DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension; 60 61 while(!IsListEmpty(&DeviceExtension->KsAudioDeviceList)) 62 { 63 Entry = RemoveHeadList(&DeviceExtension->KsAudioDeviceList); 64 DeviceEntry = (PKSAUDIO_DEVICE_ENTRY)CONTAINING_RECORD(Entry, KSAUDIO_DEVICE_ENTRY, Entry); 65 66 DPRINT("Freeing item %wZ\n", &DeviceEntry->DeviceName); 67 68 /* dereference audio device file object */ 69 ObDereferenceObject(DeviceEntry->FileObject); 70 71 /* close audio device handle */ 72 ZwClose(DeviceEntry->Handle); 73 74 /* free device string */ 75 RtlFreeUnicodeString(&DeviceEntry->DeviceName); 76 77 /* free audio device entry */ 78 FreeItem(DeviceEntry); 79 } 80 81 Irp->IoStatus.Information = 0; 82 Irp->IoStatus.Status = STATUS_SUCCESS; 83 IoCompleteRequest(Irp, IO_NO_INCREMENT); 84 return STATUS_SUCCESS; 85 } 86 87 NTSTATUS 88 NTAPI 89 SysAudio_Pnp( 90 IN PDEVICE_OBJECT DeviceObject, 91 IN PIRP Irp) 92 { 93 PIO_STACK_LOCATION IrpStack; 94 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio"); 95 SYSAUDIODEVEXT *DeviceExtension; 96 97 /* Get current irp stack */ 98 IrpStack = IoGetCurrentIrpStackLocation(Irp); 99 100 /* Fetch the device extension */ 101 DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension; 102 ASSERT(DeviceExtension); 103 104 if (IrpStack->MinorFunction == IRP_MN_REMOVE_DEVICE) 105 { 106 /* Unregister the echo cancel hook */ 107 if (DeviceExtension->EchoCancelNotificationEntry) 108 IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry); 109 110 /* Unregister the ks audio hook */ 111 if (DeviceExtension->KsAudioNotificationEntry) 112 IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry); 113 114 /* Destroy our symbolic link */ 115 IoDeleteSymbolicLink(&SymlinkName); 116 } 117 else if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE) 118 { 119 /* Sysaudio can not be disabled */ 120 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; 121 } 122 123 /* Perform default pnp actions */ 124 return KsDefaultDispatchPnp(DeviceObject, Irp); 125 } 126 127 NTSTATUS 128 NTAPI 129 SysAudio_AddDevice( 130 IN PDRIVER_OBJECT DriverObject, 131 IN PDEVICE_OBJECT PhysicalDeviceObject) 132 { 133 NTSTATUS Status; 134 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\sysaudio"); 135 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio"); 136 PDEVICE_OBJECT DeviceObject, NextDeviceObject; 137 SYSAUDIODEVEXT *DeviceExtension; 138 139 DPRINT("SysAudio_AddDevice called\n"); 140 141 /* Create the device */ 142 Status = IoCreateDevice(DriverObject, 143 sizeof(SYSAUDIODEVEXT), 144 &DeviceName, 145 FILE_DEVICE_KS, 146 0, 147 FALSE, 148 &DeviceObject); 149 150 /* Check for success */ 151 if (!NT_SUCCESS(Status)) 152 { 153 DPRINT("Failed to create \\Device\\sysaudio !\n"); 154 return Status; 155 } 156 157 /* Register device interfaces */ 158 Status = SysAudioRegisterDeviceInterfaces(PhysicalDeviceObject); 159 if (!NT_SUCCESS(Status)) 160 { 161 /* Failed to register 162 * Create a hack interface 163 */ 164 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName); 165 if (!NT_SUCCESS(Status)) 166 { 167 IoDeleteDevice(DeviceObject); 168 DPRINT1("Failed to create sysaudio symlink!\n"); 169 return Status; 170 } 171 } 172 /* Acquire device extension */ 173 DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension; 174 /* Initialize device extension */ 175 RtlZeroMemory(DeviceExtension, sizeof(SYSAUDIODEVEXT)); 176 177 /* Initialize the mutex */ 178 KeInitializeSpinLock(&DeviceExtension->Lock); 179 180 /* Initialize the ks audio device list */ 181 InitializeListHead(&DeviceExtension->KsAudioDeviceList); 182 183 /* Allocate kernel streaming device header */ 184 Status = SysAudioAllocateDeviceHeader(DeviceExtension); 185 if (!NT_SUCCESS(Status)) 186 { 187 DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status); 188 goto cleanup; 189 } 190 191 /* Register device notification hooks */ 192 Status = SysAudioRegisterNotifications(DriverObject, 193 DeviceObject); 194 if (!NT_SUCCESS(Status)) 195 { 196 DPRINT1("Failed to register device notifications\n"); 197 goto cleanup; 198 } 199 200 /* Load kmixer */ 201 Status = SysAudioOpenKMixer(DeviceExtension); 202 if (!NT_SUCCESS(Status)) 203 { 204 DPRINT1("SysAudioOpenKMixer failed with %x\n", Status); 205 goto cleanup; 206 } 207 208 /* set io flags */ 209 DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE; 210 /* clear initializing flag */ 211 DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING; 212 213 /* atttach to device stack */ 214 NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); 215 KsSetDevicePnpAndBaseObject(DeviceExtension->KsDeviceHeader, NextDeviceObject, DeviceObject); 216 217 /* register shutdown notification */ 218 IoRegisterShutdownNotification(DeviceObject); 219 220 /* Done */ 221 return STATUS_SUCCESS; 222 223 cleanup: 224 225 if (DeviceExtension->KsAudioNotificationEntry) 226 IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry); 227 228 if (DeviceExtension->EchoCancelNotificationEntry) 229 IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry); 230 231 IoDeleteSymbolicLink(&SymlinkName); 232 IoDeleteDevice(DeviceObject); 233 return Status; 234 } 235 236 NTSTATUS 237 NTAPI 238 DriverEntry( 239 IN PDRIVER_OBJECT DriverObject, 240 IN PUNICODE_STRING RegistryPath) 241 { 242 DPRINT("System audio graph builder (sysaudio) started\n"); 243 244 /* Let ks handle these */ 245 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CREATE); 246 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE); 247 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_WRITE); 248 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL); 249 250 /* Let ks handle these */ 251 DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower; 252 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp; 253 254 /* Use provided ks unload function */ 255 DriverObject->DriverUnload = KsNullDriverUnload; 256 257 /* Sysaudio needs to do work on pnp, so handle it */ 258 DriverObject->MajorFunction[IRP_MJ_PNP] = SysAudio_Pnp; 259 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = SysAudio_Shutdown; 260 DriverObject->DriverExtension->AddDevice = SysAudio_AddDevice; 261 262 /* done */ 263 return STATUS_SUCCESS; 264 } 265