ReactOS 0.4.16-dev-319-g6cf4263
fdo.cpp
Go to the documentation of this file.
1/*
2* COPYRIGHT: See COPYING in the top level directory
3* PROJECT: ReactOS Kernel Streaming
4* FILE: drivers/wdm/audio/hdaudbus/fdo.cpp
5* PURPOSE: HDA Driver Entry
6* PROGRAMMER: Johannes Anderwald
7*/
8
9#include "hdaudbus.h"
10
16{
18 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
19 ULONG InterruptStatus;
20 UCHAR RirbStatus, CorbStatus;
21
22 /* get device extension */
24 DeviceExtension = static_cast<PHDA_FDO_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
25 ASSERT(DeviceExtension->IsFDO == TRUE);
26
27 // Check if this interrupt is ours
28 InterruptStatus = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_STATUS));
29
30 DPRINT("HDA_InterruptService %lx\n", InterruptStatus);
31 if ((InterruptStatus & INTR_STATUS_GLOBAL) == 0)
32 return FALSE;
33
34 // Controller or stream related?
35 if (InterruptStatus & INTR_STATUS_CONTROLLER) {
36 RirbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS);
37 CorbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS);
38
39 // Check for incoming responses
40 if (RirbStatus) {
41 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS, RirbStatus);
42
43 if (DeviceExtension->RirbLength == 0)
44 {
45 /* HACK: spurious interrupt */
46 return FALSE;
47 }
48
49 if ((RirbStatus & RIRB_STATUS_RESPONSE) != 0) {
51 }
52
53 if ((RirbStatus & RIRB_STATUS_OVERRUN) != 0)
54 DPRINT1("hda: RIRB Overflow\n");
55 }
56
57 // Check for sending errors
58 if (CorbStatus) {
59 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS, CorbStatus);
60
61 if ((CorbStatus & CORB_STATUS_MEMORY_ERROR) != 0)
62 DPRINT1("hda: CORB Memory Error!\n");
63 }
64 }
65#if 0
66 if ((intrStatus & INTR_STATUS_STREAM_MASK) != 0) {
67 for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) {
68 if ((intrStatus & (1 << index)) != 0) {
69 if (controller->streams[index]) {
70 if (stream_handle_interrupt(controller,
71 controller->streams[index], index)) {
72 handled = B_INVOKE_SCHEDULER;
73 }
74 }
75 else {
76 dprintf("hda: Stream interrupt for unconfigured stream "
77 "%ld!\n", index);
78 }
79 }
80 }
81 }
82#endif
83 return TRUE;
84}
85
86VOID
93{
94 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
95 ULONG Response, ResponseFlags, Cad;
96 USHORT WritePos;
97 PHDA_CODEC_ENTRY Codec;
98
99 /* get device extension */
100 DeviceExtension = static_cast<PHDA_FDO_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
101 ASSERT(DeviceExtension->IsFDO == TRUE);
102
103 WritePos = (READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) + 1) % DeviceExtension->RirbLength;
104
105 for (; DeviceExtension->RirbReadPos != WritePos; DeviceExtension->RirbReadPos = (DeviceExtension->RirbReadPos + 1) % DeviceExtension->RirbLength)
106 {
107 Response = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].response;
108 ResponseFlags = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].flags;
109 Cad = ResponseFlags & RESPONSE_FLAGS_CODEC_MASK;
110 DPRINT1("Response %lx ResponseFlags %lx Cad %lx\n", Response, ResponseFlags, Cad);
111
112 /* get codec */
113 Codec = DeviceExtension->Codecs[Cad];
114 if (Codec == NULL)
115 {
116 DPRINT1("hda: response for unknown codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
117 continue;
118 }
119
120 /* check response count */
122 {
123 DPRINT1("too many responses for codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
124 continue;
125 }
126
127 // FIXME handle unsolicited responses
128 ASSERT((ResponseFlags & RESPONSE_FLAGS_UNSOLICITED) == 0);
129
130 /* store response */
131 Codec->Responses[Codec->ResponseCount] = Response;
132 Codec->ResponseCount++;
134 }
135}
136
137
141 IN PHDA_CODEC_ENTRY Codec,
142 IN PULONG Verbs,
143 OUT PULONG Responses,
144 IN ULONG Count)
145{
146 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
147 ULONG Sent = 0, ReadPosition, WritePosition, Queued;
148
149 /* get device extension */
150 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
151 ASSERT(DeviceExtension->IsFDO);
152
153 /* reset response count */
154 Codec->ResponseCount = 0;
155
156 while (Sent < Count) {
157 ReadPosition = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
158
159 Queued = 0;
160
161 while (Sent < Count) {
162 WritePosition = (DeviceExtension->CorbWritePos + 1) % DeviceExtension->CorbLength;
163
164 if (WritePosition == ReadPosition) {
165 // There is no space left in the ring buffer; execute the
166 // queued commands and wait until
167 break;
168 }
169
170 DeviceExtension->CorbBase[WritePosition] = Verbs[Sent++];
171 DeviceExtension->CorbWritePos = WritePosition;
172 Queued++;
173 }
174
175 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
176 }
177
178 while (Queued--)
179 {
181 Timeout.QuadPart = -1000LL * 10000; // 1 sec
182
183 NTSTATUS waitStatus = KeWaitForSingleObject(&Codec->ResponseSemaphore,
184 Executive,
186 FALSE,
187 &Timeout);
188
189 if (waitStatus == STATUS_TIMEOUT)
190 {
191 DPRINT1("HDA_SendVerbs: timeout! Queued: %u\n", Queued);
193 }
194 }
195
196 if (Responses != NULL) {
197 memcpy(Responses, Codec->Responses, Codec->ResponseCount * sizeof(ULONG));
198 }
199
200 return STATUS_SUCCESS;
201}
202
206 IN ULONG codecAddress)
207{
209 ULONG verbs[3];
210 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
212 ULONG NodeId, GroupType;
214 PHDA_CODEC_AUDIO_GROUP AudioGroup;
215 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
216
217 /* lets allocate the entry */
219 if (!Entry)
220 {
221 DPRINT1("hda: failed to allocate memory\n");
222 return STATUS_UNSUCCESSFUL;
223 }
224
225 /* init codec */
226 Entry->Addr = codecAddress;
227 KeInitializeSemaphore(&Entry->ResponseSemaphore, 0, MAX_CODEC_RESPONSES);
228
229 /* get device extension */
230 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
231
232 /* store codec */
233 DeviceExtension->Codecs[codecAddress] = Entry;
234
235 verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
236 verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
237 verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUB_NODE_COUNT);
238
239 /* get basic info */
241 if (!NT_SUCCESS(Status))
242 {
244 DeviceExtension->Codecs[codecAddress] = NULL;
245 return Status;
246 }
247
248 /* store codec details */
249 Entry->Major = Response.major;
250 Entry->Minor = Response.minor;
251 Entry->ProductId = Response.device;
252 Entry->Revision = Response.revision;
253 Entry->Stepping = Response.stepping;
254 Entry->VendorId = Response.vendor;
255
256 DPRINT1("hda Codec %ld Vendor: %04lx Product: %04lx, Revision: %lu.%lu.%lu.%lu NodeStart %u NodeCount %u \n", codecAddress, Response.vendor,
257 Response.device, Response.major, Response.minor, Response.revision, Response.stepping, Response.start, Response.count);
258
259 for (NodeId = Response.start; NodeId < Response.start + Response.count; NodeId++) {
260
261 /* get function type */
262 verbs[0] = MAKE_VERB(codecAddress, NodeId, VID_GET_PARAMETER, PID_FUNCTION_GROUP_TYPE);
263
264 Status = HDA_SendVerbs(DeviceObject, Entry, verbs, &GroupType, 1);
265 DPRINT1("Status %x NodeId %u GroupType %x\n", Status, NodeId, GroupType);
266
267
268 if (NT_SUCCESS(Status) &&
270 {
271 if (Entry->AudioGroupCount >= HDA_MAX_AUDIO_GROUPS)
272 {
273 DPRINT1("Too many audio groups in node %u. Skipping.\n", NodeId);
274 break;
275 }
276
278 if (!AudioGroup)
279 {
280 DPRINT1("hda: insufficient memory\n");
282 }
283
284 /* init audio group */
285 AudioGroup->NodeId = NodeId;
287
288 // Found an Audio Function Group!
289 DPRINT1("NodeId %x found an audio function group!\n", NodeId);
290
292 if (!NT_SUCCESS(Status))
293 {
294 FreeItem(AudioGroup);
295 DPRINT1("hda failed to create device object %x\n", Status);
296 return Status;
297 }
298
299 /* init child pdo*/
300 ChildDeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)AudioGroup->ChildPDO->DeviceExtension;
301 ChildDeviceExtension->IsFDO = FALSE;
302 ChildDeviceExtension->ReportedMissing = FALSE;
303 ChildDeviceExtension->Codec = Entry;
304 ChildDeviceExtension->AudioGroup = AudioGroup;
305 ChildDeviceExtension->FDO = DeviceObject;
306
307 /* setup flags */
308 AudioGroup->ChildPDO->Flags |= DO_POWER_PAGABLE;
309 AudioGroup->ChildPDO->Flags &= ~DO_DEVICE_INITIALIZING;
310
311 /* add audio group*/
312 Entry->AudioGroups[Entry->AudioGroupCount] = AudioGroup;
313 Entry->AudioGroupCount++;
314 }
315 }
316 return STATUS_SUCCESS;
317
318}
319
321NTAPI
324{
325 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
326 UCHAR corbSize, value, rirbSize;
327 PHYSICAL_ADDRESS HighestPhysicalAddress, CorbPhysicalAddress;
328 ULONG Index;
329 USHORT corbReadPointer, rirbWritePointer, interruptValue, corbControl, rirbControl;
330
331 /* get device extension */
332 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
333
334 // Determine and set size of CORB
335 corbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE);
336 if ((corbSize & CORB_SIZE_CAP_256_ENTRIES) != 0) {
337 DeviceExtension->CorbLength = 256;
338
339 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
341 }
342 else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
343 DeviceExtension->CorbLength = 16;
344
345 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
347 }
348 else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
349 DeviceExtension->CorbLength = 2;
350
351 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
353 }
354
355 // Determine and set size of RIRB
356 rirbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE);
357 if (rirbSize & RIRB_SIZE_CAP_256_ENTRIES) {
358 DeviceExtension->RirbLength = 256;
359
360 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
362 }
363 else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
364 DeviceExtension->RirbLength = 16;
365
366 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
368 }
369 else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
370 DeviceExtension->RirbLength = 2;
371
372 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
374 }
375
376 /* init corb */
377 HighestPhysicalAddress.QuadPart = 0x00000000FFFFFFFF;
378 DeviceExtension->CorbBase = (PULONG)MmAllocateContiguousMemory(PAGE_SIZE * 3, HighestPhysicalAddress);
379 ASSERT(DeviceExtension->CorbBase != NULL);
380
381 // FIXME align rirb 128bytes
382 ASSERT(DeviceExtension->CorbLength == 256);
383 ASSERT(DeviceExtension->RirbLength == 256);
384
385 CorbPhysicalAddress = MmGetPhysicalAddress(DeviceExtension->CorbBase);
386 ASSERT(CorbPhysicalAddress.QuadPart != 0LL);
387
388 // Program CORB/RIRB for these locations
389 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_LOWER), CorbPhysicalAddress.LowPart);
390 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_UPPER), CorbPhysicalAddress.HighPart);
391
392 DeviceExtension->RirbBase = (PRIRB_RESPONSE)((ULONG_PTR)DeviceExtension->CorbBase + PAGE_SIZE);
393 CorbPhysicalAddress.QuadPart += PAGE_SIZE;
394 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_LOWER), CorbPhysicalAddress.LowPart);
395 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_UPPER), CorbPhysicalAddress.HighPart);
396
397 // Program DMA position update
398 DeviceExtension->StreamPositions = (PVOID)((ULONG_PTR)DeviceExtension->RirbBase + PAGE_SIZE);
399 CorbPhysicalAddress.QuadPart += PAGE_SIZE;
400 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), CorbPhysicalAddress.LowPart);
401 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), CorbPhysicalAddress.HighPart);
402
403 value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS)) & ~HDAC_CORB_WRITE_POS_MASK;
405
406 // Reset CORB read pointer. Preserve bits marked as RsvdP.
407 // After setting the reset bit, we must wait for the hardware
408 // to acknowledge it, then manually unset it and wait for that
409 // to be acknowledged as well.
410 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
411
412 corbReadPointer |= CORB_READ_POS_RESET;
413 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
414
415 for (Index = 0; Index < 10; Index++) {
417 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
418 if ((corbReadPointer & CORB_READ_POS_RESET) != 0)
419 break;
420 }
421 if ((corbReadPointer & CORB_READ_POS_RESET) == 0) {
422 DPRINT1("hda: CORB read pointer reset not acknowledged\n");
423
424 // According to HDA spec v1.0a ch3.3.21, software must read the
425 // bit as 1 to verify that the reset completed. However, at least
426 // some nVidia HDA controllers do not update the bit after reset.
427 // Thus don't fail here on nVidia controllers.
428 //if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
429 // return B_BUSY;
430 }
431
432 corbReadPointer &= ~CORB_READ_POS_RESET;
433 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
434 for (Index = 0; Index < 10; Index++) {
436 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
437 if ((corbReadPointer & CORB_READ_POS_RESET) == 0)
438 break;
439 }
440 if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
441 DPRINT1("hda: CORB read pointer reset failed\n");
442 return STATUS_UNSUCCESSFUL;
443 }
444
445 // Reset RIRB write pointer
446 rirbWritePointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) & ~RIRB_WRITE_POS_RESET;
447 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS), rirbWritePointer | RIRB_WRITE_POS_RESET);
448
449 // Generate interrupt for every response
450 interruptValue = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT)) & ~HDAC_RESPONSE_INTR_COUNT_MASK;
451 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT), interruptValue | 1);
452
453 // Setup cached read/write indices
454 DeviceExtension->RirbReadPos = 1;
455 DeviceExtension->CorbWritePos = 0;
456
457 // Gentlemen, start your engines...
458 corbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL)) & ~HDAC_CORB_CONTROL_MASK;
460
461 rirbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL)) & ~HDAC_RIRB_CONTROL_MASK;
463
464 return STATUS_SUCCESS;
465}
466
468NTAPI
471{
472 USHORT ValCapabilities;
473 ULONG Index;
474 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
475 ULONG InputStreams, OutputStreams, BiDirStreams, Control;
476 UCHAR corbControl, rirbControl;
477
478 /* get device extension */
479 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
480
481 /* read caps */
482 ValCapabilities = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_GLOBAL_CAP));
483
484 InputStreams = GLOBAL_CAP_INPUT_STREAMS(ValCapabilities);
485 OutputStreams = GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities);
486 BiDirStreams = GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities);
487
488 DPRINT1("NumInputStreams %u\n", InputStreams);
489 DPRINT1("NumOutputStreams %u\n", OutputStreams);
490 DPRINT1("NumBiDirStreams %u\n", BiDirStreams);
491
492 /* stop all streams */
493 for (Index = 0; Index < InputStreams; Index++)
494 {
497 }
498
499 for (Index = 0; Index < OutputStreams; Index++) {
502 }
503
504 for (Index = 0; Index < BiDirStreams; Index++) {
505 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
506 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
507 }
508
509 // stop DMA
510 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL) & ~HDAC_CORB_CONTROL_MASK;
512
513 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL) & ~HDAC_RIRB_CONTROL_MASK;
515
516 for (int timeout = 0; timeout < 10; timeout++) {
518
519 corbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL);
520 rirbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL);
521 if (corbControl == 0 && rirbControl == 0)
522 break;
523 }
524 if (corbControl != 0 || rirbControl != 0) {
525 DPRINT1("hda: unable to stop dma\n");
526 return STATUS_UNSUCCESSFUL;
527 }
528
529 // reset DMA position buffer
532
533 // Set reset bit - it must be asserted for at least 100us
536
537 for (int timeout = 0; timeout < 10; timeout++) {
539
541 if ((Control & GLOBAL_CONTROL_RESET) == 0)
542 break;
543 }
544 if ((Control & GLOBAL_CONTROL_RESET) != 0)
545 {
546 DPRINT1("hda: unable to reset controller\n");
547 return STATUS_UNSUCCESSFUL;
548 }
549
550 // Unset reset bit
553
554 for (int timeout = 0; timeout < 10; timeout++) {
556
558 if ((Control & GLOBAL_CONTROL_RESET) != 0)
559 break;
560 }
561 if ((Control & GLOBAL_CONTROL_RESET) == 0) {
562 DPRINT1("hda: unable to exit reset\n");
563 return STATUS_UNSUCCESSFUL;
564 }
565
566 // Wait for codecs to finish their own reset (apparently needs more
567 // time than documented in the specs)
569
570 // Enable unsolicited responses
573
574 return STATUS_SUCCESS;
575}
576
578NTAPI
581 IN PIRP Irp)
582{
583 PIO_STACK_LOCATION IoStack;
585 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
587 ULONG Index;
589
590 /* get device extension */
591 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
592 ASSERT(DeviceExtension->IsFDO == TRUE);
593
594 /* forward irp to lower device */
595 if (!IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp))
596 {
597 ASSERT(FALSE);
599 }
600 Status = Irp->IoStatus.Status;
601 if (!NT_SUCCESS(Status))
602 {
603 // failed to start
604 DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status);
605 return Status;
606 }
607
608 /* get current irp stack location */
610
611 Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
612 for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
613 {
614 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
615
616 if (Descriptor->Type == CmResourceTypeMemory)
617 {
618 DeviceExtension->RegLength = Descriptor->u.Memory.Length;
619 DeviceExtension->RegBase = (PUCHAR)MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached);
620 if (DeviceExtension->RegBase == NULL)
621 {
622 DPRINT1("[HDAB] Failed to map registers\n");
624 break;
625 }
626 }
627 else if (Descriptor->Type == CmResourceTypeInterrupt)
628 {
629 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
632 NULL,
633 Descriptor->u.Interrupt.Vector,
634 Descriptor->u.Interrupt.Level,
635 Descriptor->u.Interrupt.Level,
637 (Descriptor->ShareDisposition != CmResourceShareDeviceExclusive),
638 Descriptor->u.Interrupt.Affinity,
639 FALSE);
640 if (!NT_SUCCESS(Status))
641 {
642 DPRINT1("[HDAB] Failed to connect interrupt. Status=%lx\n", Status);
643 break;
644 }
645
646 }
647 }
648
649 if (NT_SUCCESS(Status))
650 {
651 // Get controller into valid state
653 if (!NT_SUCCESS(Status)) return Status;
654
655 // Setup CORB/RIRB/DMA POS
657 if (!NT_SUCCESS(Status)) return Status;
658
659
660 // Don't enable codec state change interrupts. We don't handle
661 // them, as we want to use the STATE_STATUS register to identify
662 // available codecs. We'd have to clear that register in the interrupt
663 // handler to 'ack' the codec change.
664 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE)) & ~HDAC_WAKE_ENABLE_MASK;
666
667 // Enable controller interrupts
669
671
673 if (!Value) {
674 DPRINT1("hda: bad codec status\n");
675 return STATUS_UNSUCCESSFUL;
676 }
678
679 // Create codecs
680 DPRINT1("Codecs %lx\n", Value);
681 for (Index = 0; Index < HDA_MAX_CODECS; Index++) {
682 if ((Value & (1 << Index)) != 0) {
684 }
685 }
686 }
687
688 return Status;
689}
690
692NTAPI
696{
698 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
699 ULONG CodecIndex, AFGIndex;
700 PHDA_CODEC_ENTRY CodecEntry;
701 PDEVICE_OBJECT ChildPDO;
702 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
703
704 /* get device extension */
705 DeviceExtension = static_cast<PHDA_FDO_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
706 ASSERT(DeviceExtension->IsFDO == TRUE);
707
708 Irp->IoStatus.Status = STATUS_SUCCESS;
710 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
711
712 IoDetachDevice(DeviceExtension->LowerDevice);
713
714 if (DeviceExtension->RegBase != NULL)
715 {
716 MmUnmapIoSpace(DeviceExtension->RegBase,
717 DeviceExtension->RegLength);
718 }
719 if (DeviceExtension->Interrupt != NULL)
720 {
721 IoDisconnectInterrupt(DeviceExtension->Interrupt);
722 }
723 if (DeviceExtension->CorbBase != NULL)
724 {
725 MmFreeContiguousMemory(DeviceExtension->CorbBase);
726 }
727
728 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
729 {
730 CodecEntry = DeviceExtension->Codecs[CodecIndex];
731 if (CodecEntry == NULL)
732 {
733 continue;
734 }
735
737 for (AFGIndex = 0; AFGIndex < CodecEntry->AudioGroupCount; AFGIndex++)
738 {
739 ChildPDO = CodecEntry->AudioGroups[AFGIndex]->ChildPDO;
740 if (ChildPDO != NULL)
741 {
742 ChildDeviceExtension = static_cast<PHDA_PDO_DEVICE_EXTENSION>(ChildPDO->DeviceExtension);
743 ChildDeviceExtension->Codec = NULL;
744 ChildDeviceExtension->AudioGroup = NULL;
745 ChildDeviceExtension->FDO = NULL;
746 ChildDeviceExtension->ReportedMissing = TRUE;
747 HDA_PDORemoveDevice(ChildPDO);
748 }
749 FreeItem(CodecEntry->AudioGroups[AFGIndex]);
750 }
751 FreeItem(CodecEntry);
752 }
753
755
756 return Status;
757}
758
760NTAPI
763 IN PIRP Irp)
764{
765 ULONG DeviceCount, CodecIndex, AFGIndex;
766 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
767 PHDA_CODEC_ENTRY Codec;
768 PDEVICE_RELATIONS DeviceRelations;
769
770 /* get device extension */
771 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
772 ASSERT(DeviceExtension->IsFDO == TRUE);
773
774 DeviceCount = 0;
775 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
776 {
777 if (DeviceExtension->Codecs[CodecIndex] == NULL)
778 continue;
779
780 Codec = DeviceExtension->Codecs[CodecIndex];
782 }
783
784 if (DeviceCount == 0)
785 return STATUS_UNSUCCESSFUL;
786
787 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? sizeof(PDEVICE_OBJECT) * (DeviceCount - 1) : 0));
788 if (!DeviceRelations)
790
791 DeviceRelations->Count = 0;
792 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
793 {
794 if (DeviceExtension->Codecs[CodecIndex] == NULL)
795 continue;
796
797 Codec = DeviceExtension->Codecs[CodecIndex];
799 for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
800 {
801 DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
802 ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
803 DeviceRelations->Count++;
804 }
805 }
806
807 /* FIXME handle existing device relations */
808 ASSERT(Irp->IoStatus.Information == 0);
809
810 /* store device relations */
811 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
812
813 /* done */
814 return STATUS_SUCCESS;
815}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
unsigned char BOOLEAN
#define WRITE_REGISTER_USHORT(r, v)
Definition: arm.h:30
#define READ_REGISTER_USHORT(r)
Definition: arm.h:29
#define WRITE_REGISTER_ULONG(r, v)
Definition: arm.h:27
#define READ_REGISTER_ULONG(r)
Definition: arm.h:26
UINT Sent
Definition: arping.c:39
LONG NTSTATUS
Definition: precomp.h:26
unsigned int uint32
Definition: types.h:32
#define DPRINT1
Definition: precomp.h:8
PVOID NTAPI MmAllocateContiguousMemory(IN SIZE_T NumberOfBytes, IN PHYSICAL_ADDRESS HighestAcceptableAddress)
Definition: contmem.c:626
VOID NTAPI MmFreeContiguousMemory(IN PVOID BaseAddress)
Definition: contmem.c:653
_In_ PIRP Irp
Definition: csq.h:116
#define STATUS_TIMEOUT
Definition: d3dkmdt.h:49
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ULONG_PTR
Definition: config.h:101
#define HDA_MAX_AUDIO_GROUPS
Definition: driver.h:40
#define MAX_CODEC_RESPONSES
Definition: driver.h:43
#define HDA_MAX_CODECS
Definition: driver.h:41
#define HDA_MAX_STREAMS
Definition: driver.h:42
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
struct _DEVICE_OBJECT * PDEVICE_OBJECT
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define DO_DEVICE_INITIALIZING
Definition: env_spec_w32.h:399
#define NonPagedPool
Definition: env_spec_w32.h:307
NTSTATUS NTAPI HDA_FDOStartDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: fdo.cpp:579
NTSTATUS NTAPI HDA_ResetController(IN PDEVICE_OBJECT DeviceObject)
Definition: fdo.cpp:469
NTSTATUS HDA_InitCodec(IN PDEVICE_OBJECT DeviceObject, IN ULONG codecAddress)
Definition: fdo.cpp:204
NTSTATUS NTAPI HDA_FDORemoveDevice(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
Definition: fdo.cpp:693
NTSTATUS NTAPI HDA_InitCorbRirbPos(IN PDEVICE_OBJECT DeviceObject)
Definition: fdo.cpp:322
NTSTATUS NTAPI HDA_FDOQueryBusRelations(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: fdo.cpp:761
NTSTATUS HDA_SendVerbs(IN PDEVICE_OBJECT DeviceObject, IN PHDA_CODEC_ENTRY Codec, IN PULONG Verbs, OUT PULONG Responses, IN ULONG Count)
Definition: fdo.cpp:139
Status
Definition: gdiplustypes.h:25
GLuint index
Definition: glext.h:6031
#define MAKE_VERB(cad, nid, vid, payload)
#define PID_VENDOR_ID
#define FUNCTION_GROUP_NODETYPE_AUDIO
#define VID_GET_PARAMETER
#define FUNCTION_GROUP_NODETYPE_MASK
#define PID_REVISION_ID
#define PID_SUB_NODE_COUNT
#define PID_FUNCTION_GROUP_TYPE
#define RIRB_WRITE_POS_RESET
#define HDAC_STREAM_STATUS
#define GLOBAL_CAP_INPUT_STREAMS(cap)
#define INTR_STATUS_STREAM_MASK
#define CORB_SIZE_16_ENTRIES
#define CORB_SIZE_CAP_2_ENTRIES
#define CORB_SIZE_CAP_16_ENTRIES
#define HDAC_CORB_STATUS
#define HDAC_INTR_CONTROL
#define RIRB_SIZE_2_ENTRIES
#define RIRB_STATUS_RESPONSE
#define INTR_CONTROL_GLOBAL_ENABLE
#define CORB_CONTROL_MEMORY_ERROR_INTR
#define INTR_CONTROL_CONTROLLER_ENABLE
#define INTR_STATUS_CONTROLLER
#define GLOBAL_CAP_OUTPUT_STREAMS(cap)
#define HDAC_RESPONSE_INTR_COUNT
#define RIRB_SIZE_CAP_2_ENTRIES
#define HDAC_RIRB_SIZE
#define GLOBAL_CONTROL_UNSOLICITED
#define CORB_READ_POS_RESET
#define HDAC_RIRB_BASE_LOWER
#define RIRB_SIZE_256_ENTRIES
#define RIRB_SIZE_16_ENTRIES
#define HDAC_GLOBAL_CAP
#define HDAC_INTR_STATUS
#define HDAC_RIRB_WRITE_POS
#define HDAC_CORB_CONTROL
#define CORB_SIZE_256_ENTRIES
#define GLOBAL_CONTROL_RESET
#define RIRB_SIZE_CAP_16_ENTRIES
#define RIRB_CONTROL_DMA_ENABLE
#define HDAC_CORB_READ_POS
#define HDAC_RIRB_STATUS
#define RIRB_SIZE_CAP_256_ENTRIES
#define HDAC_GLOBAL_CONTROL
#define RIRB_CONTROL_OVERRUN_INTR
#define HDAC_STREAM_BASE
#define HDAC_RIRB_CONTROL
#define CORB_SIZE_CAP_256_ENTRIES
#define CORB_SIZE_2_ENTRIES
#define HDAC_STREAM_CONTROL0
#define HDAC_DMA_POSITION_BASE_UPPER
#define HDAC_RIRB_BASE_UPPER
#define HDAC_DMA_POSITION_BASE_LOWER
#define HDAC_CORB_BASE_LOWER
#define CORB_CONTROL_RUN
#define HDAC_CORB_SIZE
#define GLOBAL_CAP_BIDIR_STREAMS(cap)
#define HDAC_CORB_WRITE_POS
#define HDAC_STATE_STATUS
#define RESPONSE_FLAGS_UNSOLICITED
#define INTR_STATUS_GLOBAL
#define RIRB_CONTROL_RESPONSE_INTR
#define HDAC_CORB_BASE_UPPER
#define RIRB_STATUS_OVERRUN
#define CORB_STATUS_MEMORY_ERROR
#define RESPONSE_FLAGS_CODEC_MASK
#define HDAC_WAKE_ENABLE
IO_DPC_ROUTINE HDA_DpcForIsr
Definition: hdaudbus.h:119
struct HDA_CODEC_AUDIO_GROUP * PHDA_CODEC_AUDIO_GROUP
struct HDA_CODEC_ENTRY * PHDA_CODEC_ENTRY
struct RIRB_RESPONSE * PRIRB_RESPONSE
NTSTATUS HDA_PDORemoveDevice(_In_ PDEVICE_OBJECT DeviceObject)
Definition: pdo.cpp:11
struct HDA_PDO_DEVICE_EXTENSION * PHDA_PDO_DEVICE_EXTENSION
struct HDA_FDO_DEVICE_EXTENSION * PHDA_FDO_DEVICE_EXTENSION
#define HDAC_INPUT_STREAM_OFFSET(index)
Definition: hdaudbus.h:22
#define HDAC_OUTPUT_STREAM_OFFSET(num_input_streams, index)
Definition: hdaudbus.h:24
#define HDAC_BIDIR_STREAM_OFFSET(num_input_streams, num_output_streams, index)
Definition: hdaudbus.h:26
KSERVICE_ROUTINE HDA_InterruptService
Definition: hdaudbus.h:118
#define CmResourceTypeMemory
Definition: hwresource.cpp:125
#define CmResourceTypeInterrupt
Definition: hwresource.cpp:124
VOID NTAPI MmUnmapIoSpace(IN PVOID BaseAddress, IN SIZE_T NumberOfBytes)
Definition: iosup.c:193
PVOID NTAPI MmMapIoSpace(IN PHYSICAL_ADDRESS PhysicalAddress, IN SIZE_T NumberOfBytes, IN MEMORY_CACHING_TYPE CacheType)
Definition: iosup.c:47
PVOID AllocateItem(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes)
Definition: misc.c:29
VOID FreeItem(IN PVOID Item)
Definition: misc.c:37
if(dx< 0)
Definition: linetemp.h:194
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define ASSERT(a)
Definition: mode.c:44
#define for
Definition: utility.h:88
#define KeStallExecutionProcessor(MicroSeconds)
Definition: precomp.h:27
ULONG DeviceCount
Definition: mpu401.c:26
#define KernelMode
Definition: asm.h:34
#define CM_RESOURCE_INTERRUPT_LATCHED
Definition: cmtypes.h:144
#define FILE_AUTOGENERATED_DEVICE_NAME
Definition: iotypes.h:138
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
int Count
Definition: noreturn.cpp:7
#define IoSkipCurrentIrpStackLocation(Irp)
Definition: ntifs_ex.h:421
NTSTATUS NTAPI IoCreateDevice(IN PDRIVER_OBJECT DriverObject, IN ULONG DeviceExtensionSize, IN PUNICODE_STRING DeviceName, IN DEVICE_TYPE DeviceType, IN ULONG DeviceCharacteristics, IN BOOLEAN Exclusive, OUT PDEVICE_OBJECT *DeviceObject)
Definition: device.c:1031
VOID NTAPI IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
Definition: device.c:1296
VOID NTAPI IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: device.c:1251
BOOLEAN NTAPI IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: irp.c:1625
#define IoCallDriver
Definition: irp.c:1225
VOID NTAPI IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
Definition: irq.c:142
NTSTATUS NTAPI IoConnectInterrupt(OUT PKINTERRUPT *InterruptObject, IN PKSERVICE_ROUTINE ServiceRoutine, IN PVOID ServiceContext, IN PKSPIN_LOCK SpinLock, IN ULONG Vector, IN KIRQL Irql, IN KIRQL SynchronizeIrql, IN KINTERRUPT_MODE InterruptMode, IN BOOLEAN ShareVector, IN KAFFINITY ProcessorEnableMask, IN BOOLEAN FloatingSave)
Definition: irq.c:23
PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress(IN PVOID Address)
Definition: stubs.c:685
unsigned short USHORT
Definition: pedump.c:61
static ULONG Timeout
Definition: ping.c:61
#define FILE_DEVICE_SOUND
Definition: winioctl.h:74
#define dprintf
Definition: regdump.c:33
enum _KINTERRUPT_MODE KINTERRUPT_MODE
VOID NTAPI KeInitializeSemaphore(IN PKSEMAPHORE Semaphore, IN LONG Count, IN LONG Limit)
Definition: semphobj.c:22
LONG NTAPI KeReleaseSemaphore(IN PKSEMAPHORE Semaphore, IN KPRIORITY Increment, IN LONG Adjustment, IN BOOLEAN Wait)
Definition: semphobj.c:54
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
base of all file and directory entries
Definition: entries.h:83
PDEVICE_OBJECT ChildPDO
Definition: hdaudbus.h:39
Definition: hdaudbus.h:45
PHDA_CODEC_AUDIO_GROUP AudioGroups[HDA_MAX_AUDIO_GROUPS]
Definition: hdaudbus.h:58
ULONG ResponseCount
Definition: hdaudbus.h:55
ULONG Responses[MAX_CODEC_RESPONSES]
Definition: hdaudbus.h:54
KSEMAPHORE ResponseSemaphore
Definition: hdaudbus.h:56
ULONG AudioGroupCount
Definition: hdaudbus.h:59
PRIRB_RESPONSE RirbBase
Definition: hdaudbus.h:75
PDEVICE_OBJECT LowerDevice
Definition: hdaudbus.h:66
PHDA_CODEC_ENTRY Codecs[HDA_MAX_CODECS+1]
Definition: hdaudbus.h:80
PKINTERRUPT Interrupt
Definition: hdaudbus.h:70
PHDA_CODEC_AUDIO_GROUP AudioGroup
Definition: hdaudbus.h:89
PHDA_CODEC_ENTRY Codec
Definition: hdaudbus.h:88
PDEVICE_OBJECT FDO
Definition: hdaudbus.h:90
ULONG response
Definition: hdaudbus.h:33
ULONG flags
Definition: hdaudbus.h:34
Definition: ncftp.h:89
PVOID DeviceExtension
Definition: env_spec_w32.h:418
PDEVICE_OBJECT Objects[1]
Definition: iotypes.h:2163
union _IO_STACK_LOCATION::@1580 Parameters
struct _IO_STACK_LOCATION::@3979::@4016 StartDevice
Definition: ketypes.h:699
Definition: dhcpd.h:245
#define LL
Definition: tui.h:167
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
uint16_t * PUSHORT
Definition: typedefs.h:56
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
Definition: pdh_main.c:94
_In_ WDFCOLLECTION _In_ ULONG Index
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFINTERRUPT * Interrupt
Definition: wdfinterrupt.h:379
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
_Must_inspect_result_ _In_ WDFIORESLIST _In_ PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: wdfresource.h:342
_In_ WDF_WMI_PROVIDER_CONTROL Control
Definition: wdfwmi.h:166
@ CmResourceShareDeviceExclusive
Definition: cmtypes.h:241
NTKERNELAPI VOID NTAPI WRITE_REGISTER_UCHAR(IN PUCHAR Register, IN UCHAR Value)
FORCEINLINE VOID IoRequestDpc(_Inout_ PDEVICE_OBJECT DeviceObject, _In_opt_ PIRP Irp, _In_opt_ __drv_aliasesMem PVOID Context)
Definition: iofuncs.h:2750
NTKERNELAPI UCHAR NTAPI READ_REGISTER_UCHAR(IN PUCHAR Register)
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID ServiceContext
Definition: iofuncs.h:801
#define IO_NO_INCREMENT
Definition: iotypes.h:598
struct _DEVICE_RELATIONS * PDEVICE_RELATIONS
#define DO_POWER_PAGABLE
@ Executive
Definition: ketypes.h:415
@ MmNonCached
Definition: mmtypes.h:129
#define ObReferenceObject
Definition: obfuncs.h:204
unsigned char UCHAR
Definition: xmlstorage.h:181