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