ReactOS 0.4.15-dev-5893-g1bb4167
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#include "hdaudbus.h"
9
15{
17 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
18 ULONG InterruptStatus;
19 UCHAR RirbStatus, CorbStatus;
20
21 /* get device extension */
23 DeviceExtension = static_cast<PHDA_FDO_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
24 ASSERT(DeviceExtension->IsFDO == TRUE);
25
26 // Check if this interrupt is ours
27 InterruptStatus = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_STATUS));
28
29 DPRINT1("HDA_InterruptService %lx\n", InterruptStatus);
30 if ((InterruptStatus & INTR_STATUS_GLOBAL) == 0)
31 return FALSE;
32
33 // Controller or stream related?
34 if (InterruptStatus & INTR_STATUS_CONTROLLER) {
35 RirbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS);
36 CorbStatus = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS);
37
38 // Check for incoming responses
39 if (RirbStatus) {
40 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_STATUS, RirbStatus);
41
42 if (DeviceExtension->RirbLength == 0)
43 {
44 /* HACK: spurious interrupt */
45 return FALSE;
46 }
47
48 if ((RirbStatus & RIRB_STATUS_RESPONSE) != 0) {
50 }
51
52 if ((RirbStatus & RIRB_STATUS_OVERRUN) != 0)
53 DPRINT1("hda: RIRB Overflow\n");
54 }
55
56 // Check for sending errors
57 if (CorbStatus) {
58 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS, CorbStatus);
59
60 if ((CorbStatus & CORB_STATUS_MEMORY_ERROR) != 0)
61 DPRINT1("hda: CORB Memory Error!\n");
62 }
63 }
64#if 0
65 if ((intrStatus & INTR_STATUS_STREAM_MASK) != 0) {
66 for (uint32 index = 0; index < HDA_MAX_STREAMS; index++) {
67 if ((intrStatus & (1 << index)) != 0) {
68 if (controller->streams[index]) {
69 if (stream_handle_interrupt(controller,
70 controller->streams[index], index)) {
71 handled = B_INVOKE_SCHEDULER;
72 }
73 }
74 else {
75 dprintf("hda: Stream interrupt for unconfigured stream "
76 "%ld!\n", index);
77 }
78 }
79 }
80 }
81#endif
82 return TRUE;
83}
84
85VOID
92{
93 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
94 ULONG Response, ResponseFlags, Cad;
95 USHORT WritePos;
96 PHDA_CODEC_ENTRY Codec;
97
98 /* get device extension */
99 DeviceExtension = static_cast<PHDA_FDO_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
100 ASSERT(DeviceExtension->IsFDO == TRUE);
101
102 WritePos = (READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) + 1) % DeviceExtension->RirbLength;
103
104 for (; DeviceExtension->RirbReadPos != WritePos; DeviceExtension->RirbReadPos = (DeviceExtension->RirbReadPos + 1) % DeviceExtension->RirbLength)
105 {
106 Response = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].response;
107 ResponseFlags = DeviceExtension->RirbBase[DeviceExtension->RirbReadPos].flags;
108 Cad = ResponseFlags & RESPONSE_FLAGS_CODEC_MASK;
109 DPRINT1("Response %lx ResponseFlags %lx Cad %lx\n", Response, ResponseFlags, Cad);
110
111 /* get codec */
112 Codec = DeviceExtension->Codecs[Cad];
113 if (Codec == NULL)
114 {
115 DPRINT1("hda: response for unknown codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
116 continue;
117 }
118
119 /* check response count */
121 {
122 DPRINT1("too many responses for codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
123 continue;
124 }
125
126 // FIXME handle unsolicited responses
127 ASSERT((ResponseFlags & RESPONSE_FLAGS_UNSOLICITED) == 0);
128
129 /* store response */
130 Codec->Responses[Codec->ResponseCount] = Response;
131 Codec->ResponseCount++;
133 }
134}
135
136
140 IN PHDA_CODEC_ENTRY Codec,
141 IN PULONG Verbs,
142 OUT PULONG Responses,
143 IN ULONG Count)
144{
145 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
146 ULONG Sent = 0, ReadPosition, WritePosition, Queued;
147
148 /* get device extension */
149 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
150 ASSERT(DeviceExtension->IsFDO);
151
152 /* reset response count */
153 Codec->ResponseCount = 0;
154
155 while (Sent < Count) {
156 ReadPosition = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
157
158 Queued = 0;
159
160 while (Sent < Count) {
161 WritePosition = (DeviceExtension->CorbWritePos + 1) % DeviceExtension->CorbLength;
162
163 if (WritePosition == ReadPosition) {
164 // There is no space left in the ring buffer; execute the
165 // queued commands and wait until
166 break;
167 }
168
169 DeviceExtension->CorbBase[WritePosition] = Verbs[Sent++];
170 DeviceExtension->CorbWritePos = WritePosition;
171 Queued++;
172 }
173
174 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
175 }
176
177 while (Queued--)
178 {
180 Timeout.QuadPart = -1000LL * 10000; // 1 sec
181
182 NTSTATUS waitStatus = KeWaitForSingleObject(&Codec->ResponseSemaphore,
183 Executive,
185 FALSE,
186 &Timeout);
187
188 if (waitStatus == STATUS_TIMEOUT)
189 {
190 DPRINT1("HDA_SendVerbs: timeout! Queued: %u\n", Queued);
192 }
193 }
194
195 if (Responses != NULL) {
196 memcpy(Responses, Codec->Responses, Codec->ResponseCount * sizeof(ULONG));
197 }
198
199 return STATUS_SUCCESS;
200}
201
205 IN ULONG codecAddress)
206{
208 ULONG verbs[3];
209 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
211 ULONG NodeId, GroupType;
213 PHDA_CODEC_AUDIO_GROUP AudioGroup;
214 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
215
216 /* lets allocate the entry */
218 if (!Entry)
219 {
220 DPRINT1("hda: failed to allocate memory");
221 return STATUS_UNSUCCESSFUL;
222 }
223
224 /* init codec */
225 Entry->Addr = codecAddress;
226 KeInitializeSemaphore(&Entry->ResponseSemaphore, 0, MAX_CODEC_RESPONSES);
227
228 /* get device extension */
229 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
230
231 /* store codec */
232 DeviceExtension->Codecs[codecAddress] = Entry;
233
234 verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
235 verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
236 verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUB_NODE_COUNT);
237
238 /* get basic info */
240 if (!NT_SUCCESS(Status))
241 {
243 DeviceExtension->Codecs[codecAddress] = NULL;
244 return Status;
245 }
246
247 /* store codec details */
248 Entry->Major = Response.major;
249 Entry->Minor = Response.minor;
250 Entry->ProductId = Response.device;
251 Entry->Revision = Response.revision;
252 Entry->Stepping = Response.stepping;
253 Entry->VendorId = Response.vendor;
254
255 DPRINT1("hda Codec %ld Vendor: %04lx Product: %04lx, Revision: %lu.%lu.%lu.%lu NodeStart %u NodeCount %u \n", codecAddress, Response.vendor,
256 Response.device, Response.major, Response.minor, Response.revision, Response.stepping, Response.start, Response.count);
257
258 for (NodeId = Response.start; NodeId < Response.start + Response.count; NodeId++) {
259
260 /* get function type */
261 verbs[0] = MAKE_VERB(codecAddress, NodeId, VID_GET_PARAMETER, PID_FUNCTION_GROUP_TYPE);
262
263 Status = HDA_SendVerbs(DeviceObject, Entry, verbs, &GroupType, 1);
264 DPRINT1("Status %x NodeId %u GroupType %x\n", Status, NodeId, GroupType);
265
266
267 if (NT_SUCCESS(Status) &&
269 {
270 if (Entry->AudioGroupCount >= HDA_MAX_AUDIO_GROUPS)
271 {
272 DPRINT1("Too many audio groups in node %u. Skipping.\n", NodeId);
273 break;
274 }
275
277 if (!AudioGroup)
278 {
279 DPRINT1("hda: insufficient memory\n");
281 }
282
283 /* init audio group */
284 AudioGroup->NodeId = NodeId;
286
287 // Found an Audio Function Group!
288 DPRINT1("NodeId %x found an audio function group!\n", NodeId);
289
291 if (!NT_SUCCESS(Status))
292 {
293 FreeItem(AudioGroup);
294 DPRINT1("hda failed to create device object %x\n", Status);
295 return Status;
296 }
297
298 /* init child pdo*/
299 ChildDeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)AudioGroup->ChildPDO->DeviceExtension;
300 ChildDeviceExtension->IsFDO = FALSE;
301 ChildDeviceExtension->ReportedMissing = FALSE;
302 ChildDeviceExtension->Codec = Entry;
303 ChildDeviceExtension->AudioGroup = AudioGroup;
304 ChildDeviceExtension->FDO = DeviceObject;
305
306 /* setup flags */
307 AudioGroup->ChildPDO->Flags |= DO_POWER_PAGABLE;
308 AudioGroup->ChildPDO->Flags &= ~DO_DEVICE_INITIALIZING;
309
310 /* add audio group*/
311 Entry->AudioGroups[Entry->AudioGroupCount] = AudioGroup;
312 Entry->AudioGroupCount++;
313 }
314 }
315 return STATUS_SUCCESS;
316
317}
318
320NTAPI
323{
324 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
325 UCHAR corbSize, value, rirbSize;
326 PHYSICAL_ADDRESS HighestPhysicalAddress, CorbPhysicalAddress;
327 ULONG Index;
328 USHORT corbReadPointer, rirbWritePointer, interruptValue, corbControl, rirbControl;
329
330 /* get device extension */
331 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
332
333 // Determine and set size of CORB
334 corbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE);
335 if ((corbSize & CORB_SIZE_CAP_256_ENTRIES) != 0) {
336 DeviceExtension->CorbLength = 256;
337
338 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
340 }
341 else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
342 DeviceExtension->CorbLength = 16;
343
344 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
346 }
347 else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
348 DeviceExtension->CorbLength = 2;
349
350 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
352 }
353
354 // Determine and set size of RIRB
355 rirbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE);
356 if (rirbSize & RIRB_SIZE_CAP_256_ENTRIES) {
357 DeviceExtension->RirbLength = 256;
358
359 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
361 }
362 else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
363 DeviceExtension->RirbLength = 16;
364
365 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
367 }
368 else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
369 DeviceExtension->RirbLength = 2;
370
371 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
373 }
374
375 /* init corb */
376 HighestPhysicalAddress.QuadPart = 0x00000000FFFFFFFF;
377 DeviceExtension->CorbBase = (PULONG)MmAllocateContiguousMemory(PAGE_SIZE * 3, HighestPhysicalAddress);
378 ASSERT(DeviceExtension->CorbBase != NULL);
379
380 // FIXME align rirb 128bytes
381 ASSERT(DeviceExtension->CorbLength == 256);
382 ASSERT(DeviceExtension->RirbLength == 256);
383
384 CorbPhysicalAddress = MmGetPhysicalAddress(DeviceExtension->CorbBase);
385 ASSERT(CorbPhysicalAddress.QuadPart != 0LL);
386
387 // Program CORB/RIRB for these locations
388 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_LOWER), CorbPhysicalAddress.LowPart);
389 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_UPPER), CorbPhysicalAddress.HighPart);
390
391 DeviceExtension->RirbBase = (PRIRB_RESPONSE)((ULONG_PTR)DeviceExtension->CorbBase + PAGE_SIZE);
392 CorbPhysicalAddress.QuadPart += PAGE_SIZE;
393 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_LOWER), CorbPhysicalAddress.LowPart);
394 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_UPPER), CorbPhysicalAddress.HighPart);
395
396 // Program DMA position update
397 DeviceExtension->StreamPositions = (PVOID)((ULONG_PTR)DeviceExtension->RirbBase + PAGE_SIZE);
398 CorbPhysicalAddress.QuadPart += PAGE_SIZE;
399 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), CorbPhysicalAddress.LowPart);
400 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), CorbPhysicalAddress.HighPart);
401
402 value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS)) & ~HDAC_CORB_WRITE_POS_MASK;
404
405 // Reset CORB read pointer. Preserve bits marked as RsvdP.
406 // After setting the reset bit, we must wait for the hardware
407 // to acknowledge it, then manually unset it and wait for that
408 // to be acknowledged as well.
409 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
410
411 corbReadPointer |= CORB_READ_POS_RESET;
412 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
413
414 for (Index = 0; Index < 10; Index++) {
416 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
417 if ((corbReadPointer & CORB_READ_POS_RESET) != 0)
418 break;
419 }
420 if ((corbReadPointer & CORB_READ_POS_RESET) == 0) {
421 DPRINT1("hda: CORB read pointer reset not acknowledged\n");
422
423 // According to HDA spec v1.0a ch3.3.21, software must read the
424 // bit as 1 to verify that the reset completed. However, at least
425 // some nVidia HDA controllers do not update the bit after reset.
426 // Thus don't fail here on nVidia controllers.
427 //if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
428 // return B_BUSY;
429 }
430
431 corbReadPointer &= ~CORB_READ_POS_RESET;
432 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
433 for (Index = 0; Index < 10; Index++) {
435 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
436 if ((corbReadPointer & CORB_READ_POS_RESET) == 0)
437 break;
438 }
439 if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
440 DPRINT1("hda: CORB read pointer reset failed\n");
441 return STATUS_UNSUCCESSFUL;
442 }
443
444 // Reset RIRB write pointer
445 rirbWritePointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) & ~RIRB_WRITE_POS_RESET;
446 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS), rirbWritePointer | RIRB_WRITE_POS_RESET);
447
448 // Generate interrupt for every response
449 interruptValue = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT)) & ~HDAC_RESPONSE_INTR_COUNT_MASK;
450 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT), interruptValue | 1);
451
452 // Setup cached read/write indices
453 DeviceExtension->RirbReadPos = 1;
454 DeviceExtension->CorbWritePos = 0;
455
456 // Gentlemen, start your engines...
457 corbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL)) & ~HDAC_CORB_CONTROL_MASK;
459
460 rirbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL)) & ~HDAC_RIRB_CONTROL_MASK;
462
463 return STATUS_SUCCESS;
464}
465
467NTAPI
470{
471 USHORT ValCapabilities;
472 ULONG Index;
473 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
474 ULONG InputStreams, OutputStreams, BiDirStreams, Control;
475 UCHAR corbControl, rirbControl;
476
477 /* get device extension */
478 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
479
480 /* read caps */
481 ValCapabilities = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_GLOBAL_CAP));
482
483 InputStreams = GLOBAL_CAP_INPUT_STREAMS(ValCapabilities);
484 OutputStreams = GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities);
485 BiDirStreams = GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities);
486
487 DPRINT1("NumInputStreams %u\n", InputStreams);
488 DPRINT1("NumOutputStreams %u\n", OutputStreams);
489 DPRINT1("NumBiDirStreams %u\n", BiDirStreams);
490
491 /* stop all streams */
492 for (Index = 0; Index < InputStreams; Index++)
493 {
496 }
497
498 for (Index = 0; Index < OutputStreams; Index++) {
501 }
502
503 for (Index = 0; Index < BiDirStreams; Index++) {
504 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
505 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
506 }
507
508 // stop DMA
509 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL) & ~HDAC_CORB_CONTROL_MASK;
511
512 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL) & ~HDAC_RIRB_CONTROL_MASK;
514
515 for (int timeout = 0; timeout < 10; timeout++) {
517
518 corbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL);
519 rirbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL);
520 if (corbControl == 0 && rirbControl == 0)
521 break;
522 }
523 if (corbControl != 0 || rirbControl != 0) {
524 DPRINT1("hda: unable to stop dma\n");
525 return STATUS_UNSUCCESSFUL;
526 }
527
528 // reset DMA position buffer
531
532 // Set reset bit - it must be asserted for at least 100us
535
536 for (int timeout = 0; timeout < 10; timeout++) {
538
540 if ((Control & GLOBAL_CONTROL_RESET) == 0)
541 break;
542 }
543 if ((Control & GLOBAL_CONTROL_RESET) != 0)
544 {
545 DPRINT1("hda: unable to reset controller\n");
546 return STATUS_UNSUCCESSFUL;
547 }
548
549 // Unset reset bit
552
553 for (int timeout = 0; timeout < 10; timeout++) {
555
557 if ((Control & GLOBAL_CONTROL_RESET) != 0)
558 break;
559 }
560 if ((Control & GLOBAL_CONTROL_RESET) == 0) {
561 DPRINT1("hda: unable to exit reset\n");
562 return STATUS_UNSUCCESSFUL;
563 }
564
565 // Wait for codecs to finish their own reset (apparently needs more
566 // time than documented in the specs)
568
569 // Enable unsolicited responses
572
573 return STATUS_SUCCESS;
574}
575
577NTAPI
580 IN PIRP Irp)
581{
582 PIO_STACK_LOCATION IoStack;
584 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
586 ULONG Index;
588
589 /* get device extension */
590 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
591 ASSERT(DeviceExtension->IsFDO == TRUE);
592
593 /* forward irp to lower device */
594 if (!IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp))
595 {
596 ASSERT(FALSE);
598 }
599 Status = Irp->IoStatus.Status;
600 if (!NT_SUCCESS(Status))
601 {
602 // failed to start
603 DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status);
604 return Status;
605 }
606
607 /* get current irp stack location */
609
610 Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
611 for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
612 {
613 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
614
615 if (Descriptor->Type == CmResourceTypeMemory)
616 {
617 DeviceExtension->RegLength = Descriptor->u.Memory.Length;
618 DeviceExtension->RegBase = (PUCHAR)MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached);
619 if (DeviceExtension->RegBase == NULL)
620 {
621 DPRINT1("[HDAB] Failed to map registers\n");
623 break;
624 }
625 }
626 else if (Descriptor->Type == CmResourceTypeInterrupt)
627 {
628 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
631 NULL,
632 Descriptor->u.Interrupt.Vector,
633 Descriptor->u.Interrupt.Level,
634 Descriptor->u.Interrupt.Level,
636 (Descriptor->ShareDisposition != CmResourceShareDeviceExclusive),
637 Descriptor->u.Interrupt.Affinity,
638 FALSE);
639 if (!NT_SUCCESS(Status))
640 {
641 DPRINT1("[HDAB] Failed to connect interrupt. Status=%lx\n", Status);
642 break;
643 }
644
645 }
646 }
647
648 if (NT_SUCCESS(Status))
649 {
650 // Get controller into valid state
652 if (!NT_SUCCESS(Status)) return Status;
653
654 // Setup CORB/RIRB/DMA POS
656 if (!NT_SUCCESS(Status)) return Status;
657
658
659 // Don't enable codec state change interrupts. We don't handle
660 // them, as we want to use the STATE_STATUS register to identify
661 // available codecs. We'd have to clear that register in the interrupt
662 // handler to 'ack' the codec change.
663 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE)) & ~HDAC_WAKE_ENABLE_MASK;
665
666 // Enable controller interrupts
668
670
672 if (!Value) {
673 DPRINT1("hda: bad codec status\n");
674 return STATUS_UNSUCCESSFUL;
675 }
677
678 // Create codecs
679 DPRINT1("Codecs %lx\n", Value);
680 for (Index = 0; Index < HDA_MAX_CODECS; Index++) {
681 if ((Value & (1 << Index)) != 0) {
683 }
684 }
685 }
686
687 return Status;
688}
689
691NTAPI
695{
697 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
698 ULONG CodecIndex, AFGIndex;
699 PHDA_CODEC_ENTRY CodecEntry;
700 PDEVICE_OBJECT ChildPDO;
701 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
702
703 /* get device extension */
704 DeviceExtension = static_cast<PHDA_FDO_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
705 ASSERT(DeviceExtension->IsFDO == TRUE);
706
707 Irp->IoStatus.Status = STATUS_SUCCESS;
709 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
710
711 IoDetachDevice(DeviceExtension->LowerDevice);
712
713 if (DeviceExtension->RegBase != NULL)
714 {
715 MmUnmapIoSpace(DeviceExtension->RegBase,
716 DeviceExtension->RegLength);
717 }
718 if (DeviceExtension->Interrupt != NULL)
719 {
720 IoDisconnectInterrupt(DeviceExtension->Interrupt);
721 }
722 if (DeviceExtension->CorbBase != NULL)
723 {
724 MmFreeContiguousMemory(DeviceExtension->CorbBase);
725 }
726
727 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
728 {
729 CodecEntry = DeviceExtension->Codecs[CodecIndex];
730 if (CodecEntry == NULL)
731 {
732 continue;
733 }
734
736 for (AFGIndex = 0; AFGIndex < CodecEntry->AudioGroupCount; AFGIndex++)
737 {
738 ChildPDO = CodecEntry->AudioGroups[AFGIndex]->ChildPDO;
739 if (ChildPDO != NULL)
740 {
741 ChildDeviceExtension = static_cast<PHDA_PDO_DEVICE_EXTENSION>(ChildPDO->DeviceExtension);
742 ChildDeviceExtension->Codec = NULL;
743 ChildDeviceExtension->AudioGroup = NULL;
744 ChildDeviceExtension->FDO = NULL;
745 ChildDeviceExtension->ReportedMissing = TRUE;
746 HDA_PDORemoveDevice(ChildPDO);
747 }
748 FreeItem(CodecEntry->AudioGroups[AFGIndex]);
749 }
750 FreeItem(CodecEntry);
751 }
752
754
755 return Status;
756}
757
759NTAPI
762 IN PIRP Irp)
763{
764 ULONG DeviceCount, CodecIndex, AFGIndex;
765 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
766 PHDA_CODEC_ENTRY Codec;
767 PDEVICE_RELATIONS DeviceRelations;
768
769 /* get device extension */
770 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
771 ASSERT(DeviceExtension->IsFDO == TRUE);
772
773 DeviceCount = 0;
774 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
775 {
776 if (DeviceExtension->Codecs[CodecIndex] == NULL)
777 continue;
778
779 Codec = DeviceExtension->Codecs[CodecIndex];
781 }
782
783 if (DeviceCount == 0)
784 return STATUS_UNSUCCESSFUL;
785
786 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? sizeof(PDEVICE_OBJECT) * (DeviceCount - 1) : 0));
787 if (!DeviceRelations)
789
790 DeviceRelations->Count = 0;
791 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
792 {
793 if (DeviceExtension->Codecs[CodecIndex] == NULL)
794 continue;
795
796 Codec = DeviceExtension->Codecs[CodecIndex];
798 for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
799 {
800 DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
801 ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
802 DeviceRelations->Count++;
803 }
804 }
805
806 /* FIXME handle existing device relations */
807 ASSERT(Irp->IoStatus.Information == 0);
808
809 /* store device relations */
810 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
811
812 /* done */
813 return STATUS_SUCCESS;
814}
815
816
unsigned char BOOLEAN
#define WRITE_REGISTER_USHORT(r, v)
Definition: arm.h:24
#define READ_REGISTER_USHORT(r)
Definition: arm.h:23
#define WRITE_REGISTER_ULONG(r, v)
Definition: arm.h:21
#define READ_REGISTER_ULONG(r)
Definition: arm.h:20
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
VOID NTAPI KeStallExecutionProcessor(IN ULONG MicroSeconds)
Definition: ntoskrnl.c:81
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 NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#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:578
NTSTATUS NTAPI HDA_ResetController(IN PDEVICE_OBJECT DeviceObject)
Definition: fdo.cpp:468
NTSTATUS HDA_InitCodec(IN PDEVICE_OBJECT DeviceObject, IN ULONG codecAddress)
Definition: fdo.cpp:203
NTSTATUS NTAPI HDA_FDORemoveDevice(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
Definition: fdo.cpp:692
NTSTATUS NTAPI HDA_InitCorbRirbPos(IN PDEVICE_OBJECT DeviceObject)
Definition: fdo.cpp:321
NTSTATUS NTAPI HDA_FDOQueryBusRelations(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: fdo.cpp:760
NTSTATUS HDA_SendVerbs(IN PDEVICE_OBJECT DeviceObject, IN PHDA_CODEC_ENTRY Codec, IN PULONG Verbs, OUT PULONG Responses, IN ULONG Count)
Definition: fdo.cpp:138
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:122
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:121
#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:30
VOID FreeItem(IN PVOID Item)
Definition: misc.c:43
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
ULONG DeviceCount
Definition: mpu401.c:26
#define _Inout_
Definition: ms_sal.h:378
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
#define KernelMode
Definition: asm.h:34
#define CM_RESOURCE_INTERRUPT_LATCHED
Definition: cmtypes.h:144
#define FILE_AUTOGENERATED_DEVICE_NAME
Definition: iotypes.h:138
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:140
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:22
PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress(IN PVOID Address)
Definition: stubs.c:685
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
unsigned short USHORT
Definition: pedump.c:61
static ULONG Timeout
Definition: ping.c:61
#define FILE_DEVICE_SOUND
Definition: winioctl.h:135
#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
base of all file and directory entries
Definition: entries.h:83
PDEVICE_OBJECT ChildPDO
Definition: hdaudbus.h:40
Definition: hdaudbus.h:46
PHDA_CODEC_AUDIO_GROUP AudioGroups[HDA_MAX_AUDIO_GROUPS]
Definition: hdaudbus.h:59
ULONG ResponseCount
Definition: hdaudbus.h:56
ULONG Responses[MAX_CODEC_RESPONSES]
Definition: hdaudbus.h:55
KSEMAPHORE ResponseSemaphore
Definition: hdaudbus.h:57
ULONG AudioGroupCount
Definition: hdaudbus.h:60
PRIRB_RESPONSE RirbBase
Definition: hdaudbus.h:77
PDEVICE_OBJECT LowerDevice
Definition: hdaudbus.h:68
PHDA_CODEC_ENTRY Codecs[HDA_MAX_CODECS+1]
Definition: hdaudbus.h:82
PKINTERRUPT Interrupt
Definition: hdaudbus.h:72
PHDA_CODEC_AUDIO_GROUP AudioGroup
Definition: hdaudbus.h:91
PHDA_CODEC_ENTRY Codec
Definition: hdaudbus.h:90
PDEVICE_OBJECT FDO
Definition: hdaudbus.h:92
ULONG response
Definition: hdaudbus.h:34
ULONG flags
Definition: hdaudbus.h:35
Definition: ncftp.h:89
PVOID DeviceExtension
Definition: env_spec_w32.h:418
PDEVICE_OBJECT Objects[1]
Definition: iotypes.h:2163
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:3128
Definition: ketypes.h:687
Definition: dhcpd.h:245
#define LL
Definition: tui.h:150
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
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2793
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:403
@ MmNonCached
Definition: mmtypes.h:129
#define ObReferenceObject
Definition: obfuncs.h:204
unsigned char UCHAR
Definition: xmlstorage.h:181