1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/legacy/wdmaud/main.c 5 * PURPOSE: System Audio graph builder 6 * PROGRAMMER: Andrew Greenwood 7 * Johannes Anderwald 8 */ 9 10 #include "wdmaud.h" 11 12 #define NDEBUG 13 #include <debug.h> 14 15 const GUID KSCATEGORY_SYSAUDIO = {0xA7C7A5B1L, 0x5AF3, 0x11D1, {0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07}}; 16 const GUID KSCATEGORY_WDMAUD = {0x3E227E76L, 0x690D, 0x11D2, {0x81, 0x61, 0x00, 0x00, 0xF8, 0x77, 0x5B, 0xF1}}; 17 18 IO_WORKITEM_ROUTINE WdmAudInitWorkerRoutine; 19 IO_TIMER_ROUTINE WdmAudTimerRoutine; 20 21 VOID 22 NTAPI 23 WdmAudInitWorkerRoutine( 24 IN PDEVICE_OBJECT DeviceObject, 25 IN PVOID Context) 26 { 27 NTSTATUS Status; 28 PWDMAUD_DEVICE_EXTENSION DeviceExtension; 29 ULONG DeviceCount; 30 31 /* get device extension */ 32 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 33 34 35 if (DeviceExtension->FileObject == NULL) 36 { 37 /* find available sysaudio devices */ 38 Status = WdmAudOpenSysAudioDevices(DeviceObject, DeviceExtension); 39 if (!NT_SUCCESS(Status)) 40 { 41 DPRINT1("WdmAudOpenSysAudioDevices failed with %x\n", Status); 42 return; 43 } 44 } 45 46 47 /* get device count */ 48 DeviceCount = GetSysAudioDeviceCount(DeviceObject); 49 50 DPRINT("WdmAudInitWorkerRoutine SysAudioDeviceCount %ld\n", DeviceCount); 51 52 /* was a device added / removed */ 53 if (DeviceCount != DeviceExtension->SysAudioDeviceCount) 54 { 55 /* init mmixer library */ 56 Status = WdmAudMixerInitialize(DeviceObject); 57 DPRINT("WdmAudMixerInitialize Status %x WaveIn %lu WaveOut %lu Mixer %lu\n", Status, WdmAudGetWaveInDeviceCount(), WdmAudGetWaveOutDeviceCount(), WdmAudGetMixerDeviceCount()); 58 59 /* store sysaudio device count */ 60 DeviceExtension->SysAudioDeviceCount = DeviceCount; 61 } 62 63 /* signal completion */ 64 KeSetEvent(&DeviceExtension->InitializationCompletionEvent, IO_NO_INCREMENT, FALSE); 65 66 /* reset work item status indicator */ 67 InterlockedDecrement((volatile long *)&DeviceExtension->WorkItemActive); 68 } 69 70 VOID 71 NTAPI 72 WdmAudTimerRoutine( 73 IN PDEVICE_OBJECT DeviceObject, 74 IN PVOID Context) 75 { 76 PWDMAUD_DEVICE_EXTENSION DeviceExtension; 77 78 /* get device extension */ 79 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 80 81 if (InterlockedCompareExchange((volatile long *)&DeviceExtension->WorkItemActive, 1, 0) == 0) 82 { 83 /* queue work item */ 84 IoQueueWorkItem(DeviceExtension->WorkItem, WdmAudInitWorkerRoutine, DelayedWorkQueue, (PVOID)DeviceExtension); 85 } 86 } 87 88 NTSTATUS 89 NTAPI 90 WdmaudAddDevice( 91 IN PDRIVER_OBJECT DriverObject, 92 IN PDEVICE_OBJECT PhysicalDeviceObject) 93 { 94 PDEVICE_OBJECT DeviceObject; 95 NTSTATUS Status; 96 PWDMAUD_DEVICE_EXTENSION DeviceExtension; 97 98 DPRINT("WdmaudAddDevice called\n"); 99 100 Status = IoCreateDevice(DriverObject, 101 sizeof(WDMAUD_DEVICE_EXTENSION), 102 NULL, 103 FILE_DEVICE_KS, 104 0, 105 FALSE, 106 &DeviceObject); 107 108 if (!NT_SUCCESS(Status)) 109 { 110 DPRINT1("IoCreateDevice failed with %x\n", Status); 111 return Status; 112 } 113 114 /* get device extension */ 115 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 116 RtlZeroMemory(DeviceExtension, sizeof(WDMAUD_DEVICE_EXTENSION)); 117 118 /* allocate work item */ 119 DeviceExtension->WorkItem = IoAllocateWorkItem(DeviceObject); 120 if (!DeviceExtension->WorkItem) 121 { 122 /* failed to allocate work item */ 123 IoDeleteDevice(DeviceObject); 124 return STATUS_INSUFFICIENT_RESOURCES; 125 } 126 127 /* register device interfaces */ 128 Status = WdmAudRegisterDeviceInterface(PhysicalDeviceObject, DeviceExtension); 129 if (!NT_SUCCESS(Status)) 130 { 131 DPRINT1("WdmRegisterDeviceInterface failed with %x\n", Status); 132 IoDeleteDevice(DeviceObject); 133 return Status; 134 } 135 136 /* initialize sysaudio device list */ 137 InitializeListHead(&DeviceExtension->SysAudioDeviceList); 138 139 /* initialize client context device list */ 140 InitializeListHead(&DeviceExtension->WdmAudClientList); 141 142 /* initialize spinlock */ 143 KeInitializeSpinLock(&DeviceExtension->Lock); 144 145 /* initialization completion event */ 146 KeInitializeEvent(&DeviceExtension->InitializationCompletionEvent, NotificationEvent, FALSE); 147 148 /* initialize timer */ 149 IoInitializeTimer(DeviceObject, WdmAudTimerRoutine, (PVOID)WdmAudTimerRoutine); 150 151 /* allocate ks device header */ 152 Status = KsAllocateDeviceHeader(&DeviceExtension->DeviceHeader, 0, NULL); 153 if (!NT_SUCCESS(Status)) 154 { 155 DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status); 156 IoDeleteDevice(DeviceObject); 157 return Status; 158 } 159 160 /* attach to device stack */ 161 DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); 162 KsSetDevicePnpAndBaseObject(DeviceExtension->DeviceHeader, DeviceExtension->NextDeviceObject, DeviceObject); 163 164 165 /* start the timer */ 166 IoStartTimer(DeviceObject); 167 168 DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE; 169 DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING; 170 171 return STATUS_SUCCESS; 172 } 173 174 VOID 175 NTAPI 176 WdmAudUnload( 177 IN PDRIVER_OBJECT driver) 178 { 179 DPRINT("WdmAudUnload called\n"); 180 } 181 182 NTSTATUS 183 NTAPI 184 WdmAudPnp( 185 IN PDEVICE_OBJECT DeviceObject, 186 IN PIRP Irp) 187 { 188 PIO_STACK_LOCATION IrpStack; 189 190 DPRINT("WdmAudPnp called\n"); 191 192 IrpStack = IoGetCurrentIrpStackLocation(Irp); 193 194 if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE) 195 { 196 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; 197 return KsDefaultDispatchPnp(DeviceObject, Irp); 198 } 199 return KsDefaultDispatchPnp(DeviceObject, Irp); 200 } 201 202 203 NTSTATUS 204 NTAPI 205 WdmAudCreate( 206 IN PDEVICE_OBJECT DeviceObject, 207 IN PIRP Irp) 208 { 209 NTSTATUS Status; 210 PIO_STACK_LOCATION IoStack; 211 PWDMAUD_CLIENT pClient; 212 PWDMAUD_DEVICE_EXTENSION DeviceExtension; 213 214 /* get device extension */ 215 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 216 217 #if KS_IMPLEMENTED 218 Status = KsReferenceSoftwareBusObject((KSDEVICE_HEADER)DeviceObject->DeviceExtension); 219 if (!NT_SUCCESS(Status)) 220 { 221 DPRINT1("KsReferenceSoftwareBusObject failed with %x\n", Status); 222 return Status; 223 } 224 #endif 225 226 if (DeviceExtension->FileObject == NULL) 227 { 228 /* initialize */ 229 WdmAudInitWorkerRoutine(DeviceObject, NULL); 230 } 231 232 233 Status = WdmAudOpenSysaudio(DeviceObject, &pClient); 234 if (!NT_SUCCESS(Status)) 235 { 236 DPRINT1("Failed to open sysaudio!\n"); 237 238 /* complete and forget */ 239 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 240 IoCompleteRequest(Irp, IO_NO_INCREMENT); 241 /* done */ 242 return STATUS_UNSUCCESSFUL; 243 } 244 245 IoStack = IoGetCurrentIrpStackLocation(Irp); 246 ASSERT(IoStack->FileObject); 247 248 /* store client context in file object */ 249 IoStack->FileObject->FsContext = pClient; 250 Status = STATUS_SUCCESS; 251 252 Irp->IoStatus.Status = Status; 253 Irp->IoStatus.Information = 0; 254 IoCompleteRequest(Irp, IO_NO_INCREMENT); 255 256 return Status; 257 } 258 259 NTSTATUS 260 NTAPI 261 WdmAudClose( 262 IN PDEVICE_OBJECT DeviceObject, 263 IN PIRP Irp) 264 { 265 /* nothing to do complete request */ 266 #if KS_IMPLEMENTED 267 Status = KsDereferenceSoftwareBusObject(DeviceExtension->DeviceHeader); 268 269 if (NT_SUCCESS(Status)) 270 { 271 if (DeviceExtension->SysAudioNotification) 272 Status = IoUnregisterPlugPlayNotification(DeviceExtension->SysAudioNotification); 273 } 274 #endif 275 276 Irp->IoStatus.Status = STATUS_SUCCESS; 277 Irp->IoStatus.Information = 0; 278 IoCompleteRequest(Irp, IO_NO_INCREMENT); 279 280 /* done */ 281 return STATUS_SUCCESS; 282 } 283 284 NTSTATUS 285 NTAPI 286 WdmAudCleanup( 287 IN PDEVICE_OBJECT DeviceObject, 288 IN PIRP Irp) 289 { 290 PIO_STACK_LOCATION IoStack; 291 PWDMAUD_CLIENT pClient; 292 PWDMAUD_DEVICE_EXTENSION DeviceExtension; 293 ULONG Index; 294 KIRQL OldIrql; 295 296 /* get device extension */ 297 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 298 299 /* get current irp stack location */ 300 IoStack = IoGetCurrentIrpStackLocation(Irp); 301 302 /* sanity check */ 303 ASSERT(IoStack->FileObject); 304 305 /* get client context struct */ 306 pClient = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext; 307 308 /* sanity check */ 309 ASSERT(pClient); 310 311 /* acquire client context list lock */ 312 KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql); 313 314 /* remove entry */ 315 RemoveEntryList(&pClient->Entry); 316 317 /* release lock */ 318 KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql); 319 320 /* check if all audio pins have been closed */ 321 for (Index = 0; Index < pClient->NumPins; Index++) 322 { 323 DPRINT("Index %u Pin %p Type %x\n", Index, pClient->hPins[Index].Handle, pClient->hPins[Index].Type); 324 if (pClient->hPins[Index].Handle && pClient->hPins[Index].Type != MIXER_DEVICE_TYPE) 325 { 326 /* found an still open audio pin */ 327 ZwClose(pClient->hPins[Index].Handle); 328 } 329 WdmAudCloseAllMixers(DeviceObject, pClient, Index); 330 } 331 332 /* free pin array */ 333 if (pClient->hPins) 334 FreeItem(pClient->hPins); 335 336 /* free client context struct */ 337 FreeItem(pClient); 338 339 /* clear old client pointer */ 340 IoStack->FileObject->FsContext = NULL; 341 342 /* complete request */ 343 Irp->IoStatus.Status = STATUS_SUCCESS; 344 Irp->IoStatus.Information = 0; 345 IoCompleteRequest(Irp, IO_NO_INCREMENT); 346 347 /* done */ 348 return STATUS_SUCCESS; 349 } 350 351 NTSTATUS 352 NTAPI 353 DriverEntry( 354 IN PDRIVER_OBJECT Driver, 355 IN PUNICODE_STRING Registry_path 356 ) 357 { 358 DPRINT("Wdmaud.sys loaded\n"); 359 360 Driver->DriverUnload = WdmAudUnload; 361 362 Driver->MajorFunction[IRP_MJ_CREATE] = WdmAudCreate; 363 Driver->MajorFunction[IRP_MJ_CLOSE] = WdmAudClose; 364 Driver->MajorFunction[IRP_MJ_PNP] = WdmAudPnp; 365 Driver->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp; 366 Driver->MajorFunction[IRP_MJ_CLEANUP] = WdmAudCleanup; 367 Driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = WdmAudDeviceControl; 368 Driver->MajorFunction[IRP_MJ_WRITE] = WdmAudReadWrite; 369 Driver->MajorFunction[IRP_MJ_READ] = WdmAudReadWrite; 370 Driver->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower; 371 Driver->DriverExtension->AddDevice = WdmaudAddDevice; 372 373 return STATUS_SUCCESS; 374 } 375