ReactOS  0.4.13-dev-100-gc8611ae
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 
10 BOOLEAN
11 NTAPI
13  IN PKINTERRUPT Interrupt,
15 {
17  PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
18  ULONG InterruptStatus;
19  UCHAR RirbStatus, CorbStatus;
20 
21  /* get device extension */
22  DeviceObject = static_cast<PDEVICE_OBJECT>(ServiceContext);
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 
85 VOID
86 NTAPI
88  _In_ PKDPC Dpc,
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 */
120  if (Codec->ResponseCount >= MAX_CODEC_RESPONSES)
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 
137 VOID
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 */
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  {
179  KeWaitForSingleObject(&Codec->ResponseSemaphore,
180  Executive,
181  KernelMode,
182  FALSE,
183  NULL);
184  }
185 
186  if (Responses != NULL) {
187  memcpy(Responses, Codec->Responses, Codec->ResponseCount * sizeof(ULONG));
188  }
189 }
190 
191 NTSTATUS
194  IN ULONG codecAddress)
195 {
197  ULONG verbs[3];
198  PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
200  ULONG NodeId, GroupType;
202  PHDA_CODEC_AUDIO_GROUP AudioGroup;
203  PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
204 
205  /* lets allocate the entry */
207  if (!Entry)
208  {
209  DPRINT1("hda: failed to allocate memory");
210  return STATUS_UNSUCCESSFUL;
211  }
212 
213  /* init codec */
214  Entry->Addr = codecAddress;
215  KeInitializeSemaphore(&Entry->ResponseSemaphore, 0, MAX_CODEC_RESPONSES);
216 
217  /* get device extension */
219 
220  /* store codec */
221  DeviceExtension->Codecs[codecAddress] = Entry;
222 
223  verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
224  verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
225  verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUB_NODE_COUNT);
226 
227  /* get basic info */
229 
230  /* store codec details */
231  Entry->Major = Response.major;
232  Entry->Minor = Response.minor;
233  Entry->ProductId = Response.device;
234  Entry->Revision = Response.revision;
235  Entry->Stepping = Response.stepping;
236  Entry->VendorId = Response.vendor;
237 
238  DPRINT1("hda Codec %ld Vendor: %04lx Product: %04lx, Revision: %lu.%lu.%lu.%lu NodeStart %u NodeCount %u \n", codecAddress, Response.vendor,
239  Response.device, Response.major, Response.minor, Response.revision, Response.stepping, Response.start, Response.count);
240 
241  for (NodeId = Response.start; NodeId < Response.start + Response.count; NodeId++) {
242 
243  /* get function type */
244  verbs[0] = MAKE_VERB(codecAddress, NodeId, VID_GET_PARAMETER, PID_FUNCTION_GROUP_TYPE);
245 
246  HDA_SendVerbs(DeviceObject, Entry, verbs, &GroupType, 1);
247  DPRINT1("NodeId %u GroupType %x\n", NodeId, GroupType);
248 
250  if (Entry->AudioGroupCount >= HDA_MAX_AUDIO_GROUPS)
251  {
252  DPRINT1("Too many audio groups in node %u. Skipping.\n", NodeId);
253  break;
254  }
255 
257  if (!AudioGroup)
258  {
259  DPRINT1("hda: insufficient memory\n");
261  }
262 
263  /* init audio group */
264  AudioGroup->NodeId = NodeId;
266 
267  // Found an Audio Function Group!
268  DPRINT1("NodeId %x found an audio function group!\n", NodeId);
269 
271  if (!NT_SUCCESS(Status))
272  {
273  FreeItem(AudioGroup);
274  DPRINT1("hda failed to create device object %x\n", Status);
275  return Status;
276  }
277 
278  /* init child pdo*/
279  ChildDeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)AudioGroup->ChildPDO->DeviceExtension;
280  ChildDeviceExtension->IsFDO = FALSE;
281  ChildDeviceExtension->ReportedMissing = FALSE;
282  ChildDeviceExtension->Codec = Entry;
283  ChildDeviceExtension->AudioGroup = AudioGroup;
284  ChildDeviceExtension->FDO = DeviceObject;
285 
286  /* setup flags */
287  AudioGroup->ChildPDO->Flags |= DO_POWER_PAGABLE;
288  AudioGroup->ChildPDO->Flags &= ~DO_DEVICE_INITIALIZING;
289 
290  /* add audio group*/
291  Entry->AudioGroups[Entry->AudioGroupCount] = AudioGroup;
292  Entry->AudioGroupCount++;
293  }
294  }
295  return STATUS_SUCCESS;
296 
297 }
298 
299 NTSTATUS
300 NTAPI
303 {
304  PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
305  UCHAR corbSize, value, rirbSize;
306  PHYSICAL_ADDRESS HighestPhysicalAddress, CorbPhysicalAddress;
307  ULONG Index;
308  USHORT corbReadPointer, rirbWritePointer, interruptValue, corbControl, rirbControl;
309 
310  /* get device extension */
312 
313  // Determine and set size of CORB
314  corbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE);
315  if ((corbSize & CORB_SIZE_CAP_256_ENTRIES) != 0) {
316  DeviceExtension->CorbLength = 256;
317 
320  }
321  else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
322  DeviceExtension->CorbLength = 16;
323 
326  }
327  else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
328  DeviceExtension->CorbLength = 2;
329 
332  }
333 
334  // Determine and set size of RIRB
335  rirbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE);
336  if (rirbSize & RIRB_SIZE_CAP_256_ENTRIES) {
337  DeviceExtension->RirbLength = 256;
338 
341  }
342  else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
343  DeviceExtension->RirbLength = 16;
344 
347  }
348  else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
349  DeviceExtension->RirbLength = 2;
350 
353  }
354 
355  /* init corb */
356  HighestPhysicalAddress.QuadPart = 0x00000000FFFFFFFF;
357  DeviceExtension->CorbBase = (PULONG)MmAllocateContiguousMemory(PAGE_SIZE * 3, HighestPhysicalAddress);
358  ASSERT(DeviceExtension->CorbBase != NULL);
359 
360  // FIXME align rirb 128bytes
361  ASSERT(DeviceExtension->CorbLength == 256);
362  ASSERT(DeviceExtension->RirbLength == 256);
363 
364  CorbPhysicalAddress = MmGetPhysicalAddress(DeviceExtension->CorbBase);
365  ASSERT(CorbPhysicalAddress.QuadPart != 0LL);
366 
367  // Program CORB/RIRB for these locations
368  WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_LOWER), CorbPhysicalAddress.LowPart);
369  WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_UPPER), CorbPhysicalAddress.HighPart);
370 
371  DeviceExtension->RirbBase = (PRIRB_RESPONSE)((ULONG_PTR)DeviceExtension->CorbBase + PAGE_SIZE);
372  CorbPhysicalAddress.QuadPart += PAGE_SIZE;
373  WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_LOWER), CorbPhysicalAddress.LowPart);
374  WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_UPPER), CorbPhysicalAddress.HighPart);
375 
376  // Program DMA position update
377  DeviceExtension->StreamPositions = (PVOID)((ULONG_PTR)DeviceExtension->RirbBase + PAGE_SIZE);
378  CorbPhysicalAddress.QuadPart += PAGE_SIZE;
379  WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), CorbPhysicalAddress.LowPart);
380  WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), CorbPhysicalAddress.HighPart);
381 
384 
385  // Reset CORB read pointer. Preserve bits marked as RsvdP.
386  // After setting the reset bit, we must wait for the hardware
387  // to acknowledge it, then manually unset it and wait for that
388  // to be acknowledged as well.
389  corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
390 
391  corbReadPointer |= CORB_READ_POS_RESET;
392  WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
393 
394  for (Index = 0; Index < 100; Index++) {
396  corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
397  if ((corbReadPointer & CORB_READ_POS_RESET) != 0)
398  break;
399  }
400  if ((corbReadPointer & CORB_READ_POS_RESET) == 0) {
401  DPRINT1("hda: CORB read pointer reset not acknowledged\n");
402 
403  // According to HDA spec v1.0a ch3.3.21, software must read the
404  // bit as 1 to verify that the reset completed. However, at least
405  // some nVidia HDA controllers do not update the bit after reset.
406  // Thus don't fail here on nVidia controllers.
407  //if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
408  // return B_BUSY;
409  }
410 
411  corbReadPointer &= ~CORB_READ_POS_RESET;
412  WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
413  for (Index = 0; Index < 10; Index++) {
415  corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
416  if ((corbReadPointer & CORB_READ_POS_RESET) == 0)
417  break;
418  }
419  if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
420  DPRINT1("hda: CORB read pointer reset failed\n");
421  return STATUS_UNSUCCESSFUL;
422  }
423 
424  // Reset RIRB write pointer
425  rirbWritePointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) & ~RIRB_WRITE_POS_RESET;
426  WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS), rirbWritePointer | RIRB_WRITE_POS_RESET);
427 
428  // Generate interrupt for every response
430  WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT), interruptValue | 1);
431 
432  // Setup cached read/write indices
433  DeviceExtension->RirbReadPos = 1;
434  DeviceExtension->CorbWritePos = 0;
435 
436  // Gentlemen, start your engines...
437  corbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL)) & ~HDAC_CORB_CONTROL_MASK;
439 
440  rirbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL)) & ~HDAC_RIRB_CONTROL_MASK;
442 
443  return STATUS_SUCCESS;
444 }
445 
446 NTSTATUS
447 NTAPI
450 {
451  USHORT ValCapabilities;
452  ULONG Index;
453  PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
454  ULONG InputStreams, OutputStreams, BiDirStreams, Control;
455  UCHAR corbControl, rirbControl;
456 
457  /* get device extension */
459 
460  /* read caps */
461  ValCapabilities = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_GLOBAL_CAP));
462 
463  InputStreams = GLOBAL_CAP_INPUT_STREAMS(ValCapabilities);
464  OutputStreams = GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities);
465  BiDirStreams = GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities);
466 
467  DPRINT1("NumInputStreams %u\n", InputStreams);
468  DPRINT1("NumOutputStreams %u\n", OutputStreams);
469  DPRINT1("NumBiDirStreams %u\n", BiDirStreams);
470 
471  /* stop all streams */
472  for (Index = 0; Index < InputStreams; Index++)
473  {
476  }
477 
478  for (Index = 0; Index < OutputStreams; Index++) {
481  }
482 
483  for (Index = 0; Index < BiDirStreams; Index++) {
484  WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
485  WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
486  }
487 
488  // stop DMA
491 
494 
495  for (int timeout = 0; timeout < 10; timeout++) {
497 
498  corbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL);
499  rirbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL);
500  if (corbControl == 0 && rirbControl == 0)
501  break;
502  }
503  if (corbControl != 0 || rirbControl != 0) {
504  DPRINT1("hda: unable to stop dma\n");
505  return STATUS_UNSUCCESSFUL;
506  }
507 
508  // reset DMA position buffer
511 
512  // Set reset bit - it must be asserted for at least 100us
515 
516  for (int timeout = 0; timeout < 10; timeout++) {
518 
520  if ((Control & GLOBAL_CONTROL_RESET) == 0)
521  break;
522  }
523  if ((Control & GLOBAL_CONTROL_RESET) != 0)
524  {
525  DPRINT1("hda: unable to reset controller\n");
526  return STATUS_UNSUCCESSFUL;
527  }
528 
529  // Unset reset bit
532 
533  for (int timeout = 0; timeout < 10; timeout++) {
535 
537  if ((Control & GLOBAL_CONTROL_RESET) != 0)
538  break;
539  }
540  if ((Control & GLOBAL_CONTROL_RESET) == 0) {
541  DPRINT1("hda: unable to exit reset\n");
542  return STATUS_UNSUCCESSFUL;
543  }
544 
545  // Wait for codecs to finish their own reset (apparently needs more
546  // time than documented in the specs)
548 
549  // Enable unsolicited responses
552 
553  return STATUS_SUCCESS;
554 }
555 
556 NTSTATUS
557 NTAPI
560  IN PIRP Irp)
561 {
562  PIO_STACK_LOCATION IoStack;
564  PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
566  ULONG Index;
567  USHORT Value;
568 
569  /* get device extension */
571  ASSERT(DeviceExtension->IsFDO == TRUE);
572 
573  /* forward irp to lower device */
574  if (!IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp))
575  {
576  ASSERT(FALSE);
578  }
579  Status = Irp->IoStatus.Status;
580  if (!NT_SUCCESS(Status))
581  {
582  // failed to start
583  DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status);
584  return Status;
585  }
586 
587  /* get current irp stack location */
589 
590  Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
591  for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
592  {
593  PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
594 
595  if (Descriptor->Type == CmResourceTypeMemory)
596  {
597  DeviceExtension->RegLength = Descriptor->u.Memory.Length;
598  DeviceExtension->RegBase = (PUCHAR)MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached);
599  if (DeviceExtension->RegBase == NULL)
600  {
601  DPRINT1("[HDAB] Failed to map registers\n");
603  break;
604  }
605  }
606  else if (Descriptor->Type == CmResourceTypeInterrupt)
607  {
608  Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
610  DeviceObject,
611  NULL,
612  Descriptor->u.Interrupt.Vector,
613  Descriptor->u.Interrupt.Level,
614  Descriptor->u.Interrupt.Level,
616  (Descriptor->ShareDisposition != CmResourceShareDeviceExclusive),
617  Descriptor->u.Interrupt.Affinity,
618  FALSE);
619  if (!NT_SUCCESS(Status))
620  {
621  DPRINT1("[HDAB] Failed to connect interrupt. Status=%lx\n", Status);
622  break;
623  }
624 
625  }
626  }
627 
628  if (NT_SUCCESS(Status))
629  {
630  // Get controller into valid state
632  if (!NT_SUCCESS(Status)) return Status;
633 
634  // Setup CORB/RIRB/DMA POS
636  if (!NT_SUCCESS(Status)) return Status;
637 
638 
639  // Don't enable codec state change interrupts. We don't handle
640  // them, as we want to use the STATE_STATUS register to identify
641  // available codecs. We'd have to clear that register in the interrupt
642  // handler to 'ack' the codec change.
645 
646  // Enable controller interrupts
648 
650 
652  if (!Value) {
653  DPRINT1("hda: bad codec status\n");
654  return STATUS_UNSUCCESSFUL;
655  }
657 
658  // Create codecs
659  DPRINT1("Codecs %lx\n", Value);
660  for (Index = 0; Index < HDA_MAX_CODECS; Index++) {
661  if ((Value & (1 << Index)) != 0) {
663  }
664  }
665  }
666 
667  return Status;
668 }
669 
670 NTSTATUS
671 NTAPI
674  _Inout_ PIRP Irp)
675 {
677  PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
678  ULONG CodecIndex, AFGIndex;
679  PHDA_CODEC_ENTRY CodecEntry;
680  PDEVICE_OBJECT ChildPDO;
681  PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
682 
683  /* get device extension */
684  DeviceExtension = static_cast<PHDA_FDO_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
685  ASSERT(DeviceExtension->IsFDO == TRUE);
686 
687  Irp->IoStatus.Status = STATUS_SUCCESS;
689  Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
690 
691  IoDetachDevice(DeviceExtension->LowerDevice);
692 
693  if (DeviceExtension->RegBase != NULL)
694  {
695  MmUnmapIoSpace(DeviceExtension->RegBase,
696  DeviceExtension->RegLength);
697  }
698  if (DeviceExtension->Interrupt != NULL)
699  {
700  IoDisconnectInterrupt(DeviceExtension->Interrupt);
701  }
702  if (DeviceExtension->CorbBase != NULL)
703  {
704  MmFreeContiguousMemory(DeviceExtension->CorbBase);
705  }
706 
707  for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
708  {
709  CodecEntry = DeviceExtension->Codecs[CodecIndex];
710  if (CodecEntry == NULL)
711  {
712  continue;
713  }
714 
716  for (AFGIndex = 0; AFGIndex < CodecEntry->AudioGroupCount; AFGIndex++)
717  {
718  ChildPDO = CodecEntry->AudioGroups[AFGIndex]->ChildPDO;
719  if (ChildPDO != NULL)
720  {
721  ChildDeviceExtension = static_cast<PHDA_PDO_DEVICE_EXTENSION>(ChildPDO->DeviceExtension);
722  ChildDeviceExtension->Codec = NULL;
723  ChildDeviceExtension->AudioGroup = NULL;
724  ChildDeviceExtension->FDO = NULL;
725  ChildDeviceExtension->ReportedMissing = TRUE;
726  HDA_PDORemoveDevice(ChildPDO);
727  }
728  FreeItem(CodecEntry->AudioGroups[AFGIndex]);
729  }
730  FreeItem(CodecEntry);
731  }
732 
734 
735  return Status;
736 }
737 
738 NTSTATUS
739 NTAPI
742  IN PIRP Irp)
743 {
744  ULONG DeviceCount, CodecIndex, AFGIndex;
745  PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
746  PHDA_CODEC_ENTRY Codec;
747  PDEVICE_RELATIONS DeviceRelations;
748 
749  /* get device extension */
751  ASSERT(DeviceExtension->IsFDO == TRUE);
752 
753  DeviceCount = 0;
754  for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
755  {
756  if (DeviceExtension->Codecs[CodecIndex] == NULL)
757  continue;
758 
759  Codec = DeviceExtension->Codecs[CodecIndex];
760  DeviceCount += Codec->AudioGroupCount;
761  }
762 
763  if (DeviceCount == 0)
764  return STATUS_UNSUCCESSFUL;
765 
766  DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? sizeof(PDEVICE_OBJECT) * (DeviceCount - 1) : 0));
767  if (!DeviceRelations)
769 
770  DeviceRelations->Count = 0;
771  for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
772  {
773  if (DeviceExtension->Codecs[CodecIndex] == NULL)
774  continue;
775 
776  Codec = DeviceExtension->Codecs[CodecIndex];
778  for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
779  {
780  DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
781  ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
782  DeviceRelations->Count++;
783  }
784  }
785 
786  /* FIXME handle existing device relations */
787  ASSERT(Irp->IoStatus.Information == 0);
788 
789  /* store device relations */
790  Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
791 
792  /* done */
793  return STATUS_SUCCESS;
794 }
795 
796 
#define DO_DEVICE_INITIALIZING
Definition: env_spec_w32.h:399
_In_opt_ ULONG _Out_ PULONG Value
Definition: rtlfuncs.h:2327
#define RIRB_STATUS_RESPONSE
#define DO_POWER_PAGABLE
#define GLOBAL_CONTROL_RESET
#define HDAC_RIRB_STATUS
#define HDAC_DMA_POSITION_BASE_UPPER
#define IN
Definition: typedefs.h:38
NTKERNELAPI VOID NTAPI WRITE_REGISTER_ULONG(IN PULONG Register, IN ULONG Value)
#define TRUE
Definition: types.h:120
#define HDA_MAX_AUDIO_GROUPS
Definition: driver.h:40
#define LL
Definition: tui.h:72
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
PHDA_CODEC_ENTRY Codec
Definition: hdaudbus.h:89
struct _Entry Entry
Definition: kefuncs.h:640
#define CORB_CONTROL_MEMORY_ERROR_INTR
#define HDAC_INPUT_STREAM_OFFSET(index)
Definition: hdaudbus.h:21
#define HDAC_RESPONSE_INTR_COUNT_MASK
_In_ PIRP Irp
Definition: csq.h:116
#define INTR_STATUS_CONTROLLER
#define PID_SUB_NODE_COUNT
#define GLOBAL_CAP_OUTPUT_STREAMS(cap)
struct _DEVICE_OBJECT * PDEVICE_OBJECT
#define HDAC_INTR_CONTROL
BOOLEAN NTAPI IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: irp.c:1625
#define RESPONSE_FLAGS_CODEC_MASK
PDEVICE_OBJECT Objects[1]
Definition: iotypes.h:2054
unsigned int uint32
Definition: types.h:32
unsigned char * PUCHAR
Definition: retypes.h:3
PVOID AllocateItem(IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes)
Definition: misc.c:30
struct HDA_FDO_DEVICE_EXTENSION * PHDA_FDO_DEVICE_EXTENSION
struct HDA_PDO_DEVICE_EXTENSION * PHDA_PDO_DEVICE_EXTENSION
LONG NTSTATUS
Definition: precomp.h:26
#define HDAC_STREAM_CONTROL0
#define HDAC_RIRB_SIZE_MASK
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
PDEVICE_OBJECT FDO
Definition: hdaudbus.h:91
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
VOID NTAPI IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
Definition: device.c:1295
#define GLOBAL_CAP_INPUT_STREAMS(cap)
NTKERNELAPI VOID NTAPI WRITE_REGISTER_USHORT(IN PUSHORT Register, IN USHORT Value)
Definition: dhcpd.h:245
PVOID NTAPI MmMapIoSpace(IN PHYSICAL_ADDRESS PhysicalAddress, IN SIZE_T NumberOfBytes, IN MEMORY_CACHING_TYPE CacheType)
Definition: iosup.c:47
NTKERNELAPI ULONG NTAPI READ_REGISTER_ULONG(IN PULONG Register)
#define RIRB_SIZE_16_ENTRIES
NTSTATUS NTAPI HDA_ResetController(IN PDEVICE_OBJECT DeviceObject)
Definition: fdo.cpp:448
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
#define PID_REVISION_ID
#define HDAC_RIRB_CONTROL
VOID NTAPI MmFreeContiguousMemory(IN PVOID BaseAddress)
Definition: contmem.c:648
#define _In_opt_
Definition: no_sal2.h:213
#define INTR_STATUS_GLOBAL
NTSTATUS NTAPI HDA_FDOStartDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: fdo.cpp:558
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define HDAC_RIRB_WRITE_POS
NTSTATUS NTAPI HDA_FDOQueryBusRelations(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: fdo.cpp:740
VOID FreeItem(IN PVOID Item)
Definition: misc.c:43
#define HDAC_STREAM_BASE
#define HDAC_INTR_STATUS
PHDA_CODEC_ENTRY Codecs[HDA_MAX_CODECS+1]
Definition: hdaudbus.h:81
#define HDAC_GLOBAL_CONTROL
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
NTSTATUS NTAPI HDA_InitCorbRirbPos(IN PDEVICE_OBJECT DeviceObject)
Definition: fdo.cpp:301
#define CORB_SIZE_2_ENTRIES
ULONG AudioGroupCount
Definition: hdaudbus.h:59
#define PID_VENDOR_ID
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
struct RIRB_RESPONSE * PRIRB_RESPONSE
#define dprintf
Definition: regdump.c:33
ULONG DeviceCount
Definition: mpu401.c:26
ULONG response
Definition: hdaudbus.h:33
#define HDAC_WAKE_ENABLE
struct HDA_CODEC_AUDIO_GROUP * PHDA_CODEC_AUDIO_GROUP
#define MAX_CODEC_RESPONSES
Definition: driver.h:43
PHDA_CODEC_AUDIO_GROUP AudioGroups[HDA_MAX_AUDIO_GROUPS]
Definition: hdaudbus.h:58
#define HDAC_RESPONSE_INTR_COUNT
#define HDAC_RIRB_SIZE
struct _DEVICE_RELATIONS * PDEVICE_RELATIONS
PVOID DeviceExtension
Definition: env_spec_w32.h:418
unsigned char BOOLEAN
#define RIRB_SIZE_2_ENTRIES
smooth NULL
Definition: ftsmooth.c:416
enum _KINTERRUPT_MODE KINTERRUPT_MODE
VOID NTAPI IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
Definition: irq.c:140
#define INTR_CONTROL_GLOBAL_ENABLE
#define HDAC_WAKE_ENABLE_MASK
#define RIRB_SIZE_CAP_2_ENTRIES
#define GLOBAL_CONTROL_UNSOLICITED
#define CORB_SIZE_256_ENTRIES
GLuint index
Definition: glext.h:6031
void * PVOID
Definition: retypes.h:9
#define RIRB_WRITE_POS_RESET
#define FILE_AUTOGENERATED_DEVICE_NAME
Definition: iotypes.h:138
NTSTATUS HDA_InitCodec(IN PDEVICE_OBJECT DeviceObject, IN ULONG codecAddress)
Definition: fdo.cpp:192
#define RIRB_STATUS_OVERRUN
_In_ LARGE_INTEGER _In_opt_ PKDPC Dpc
Definition: kefuncs.h:524
#define HDAC_RIRB_BASE_UPPER
ULONG Responses[MAX_CODEC_RESPONSES]
Definition: hdaudbus.h:54
VOID NTAPI KeInitializeSemaphore(IN PKSEMAPHORE Semaphore, IN LONG Count, IN LONG Limit)
Definition: semphobj.c:22
#define HDAC_CORB_BASE_LOWER
if(!(yy_init))
Definition: macro.lex.yy.c:714
VOID NTAPI HDA_DpcForIsr(_In_ PKDPC Dpc, _In_opt_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _In_opt_ PVOID Context)
Definition: fdo.cpp:87
NTSTATUS HDA_PDORemoveDevice(_In_ PDEVICE_OBJECT DeviceObject)
Definition: pdo.cpp:11
#define HDAC_RIRB_CONTROL_MASK
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID HDA_SendVerbs(IN PDEVICE_OBJECT DeviceObject, IN PHDA_CODEC_ENTRY Codec, IN PULONG Verbs, OUT PULONG Responses, IN ULONG Count)
Definition: fdo.cpp:138
static const UCHAR Index[8]
Definition: usbohci.c:18
FORCEINLINE VOID IoRequestDpc(_Inout_ PDEVICE_OBJECT DeviceObject, _In_opt_ PIRP Irp, _In_opt_ __drv_aliasesMem PVOID Context)
Definition: iofuncs.h:2702
#define PID_FUNCTION_GROUP_TYPE
ULONG flags
Definition: hdaudbus.h:34
#define MAKE_VERB(cad, nid, vid, payload)
#define for
Definition: utility.h:88
#define CORB_SIZE_CAP_256_ENTRIES
#define HDAC_CORB_STATUS
#define _Inout_
Definition: no_sal2.h:244
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID ServiceContext
Definition: iofuncs.h:798
#define HDAC_RIRB_BASE_LOWER
Definition: ncftp.h:89
#define HDAC_GLOBAL_CAP
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
unsigned char UCHAR
Definition: xmlstorage.h:181
#define INTR_CONTROL_CONTROLLER_ENABLE
#define RIRB_CONTROL_RESPONSE_INTR
Definition: ketypes.h:687
PDEVICE_OBJECT LowerDevice
Definition: hdaudbus.h:67
ULONG LowPart
Definition: typedefs.h:104
#define HDA_MAX_STREAMS
Definition: driver.h:42
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define HDAC_CORB_CONTROL
#define FILE_DEVICE_SOUND
Definition: winioctl.h:134
#define HDAC_STATE_STATUS
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define HDAC_CORB_BASE_UPPER
Definition: hdaudbus.h:44
#define HDAC_CORB_WRITE_POS_MASK
#define FUNCTION_GROUP_NODETYPE_MASK
#define VID_GET_PARAMETER
GLsizei const GLfloat * value
Definition: glext.h:6069
#define CORB_SIZE_16_ENTRIES
NTKERNELAPI UCHAR NTAPI READ_REGISTER_UCHAR(IN PUCHAR Register)
static const WCHAR Control[]
Definition: interface.c:27
#define HDAC_CORB_WRITE_POS
BOOLEAN NTAPI HDA_InterruptService(IN PKINTERRUPT Interrupt, IN PVOID ServiceContext)
Definition: fdo.cpp:12
#define CORB_READ_POS_RESET
Status
Definition: gdiplustypes.h:24
#define _In_
Definition: no_sal2.h:204
#define RIRB_SIZE_256_ENTRIES
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
#define HDAC_STREAM_STATUS
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
VOID NTAPI IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: device.c:1250
#define HDA_MAX_CODECS
Definition: driver.h:41
struct HDA_CODEC_ENTRY * PHDA_CODEC_ENTRY
LONG NTAPI KeReleaseSemaphore(IN PKSEMAPHORE Semaphore, IN KPRIORITY Increment, IN LONG Adjustment, IN BOOLEAN Wait)
Definition: semphobj.c:54
#define CORB_SIZE_CAP_2_ENTRIES
unsigned short USHORT
Definition: pedump.c:61
#define INTR_STATUS_STREAM_MASK
VOID NTAPI MmUnmapIoSpace(IN PVOID BaseAddress, IN SIZE_T NumberOfBytes)
Definition: iosup.c:193
#define GLOBAL_CAP_BIDIR_STREAMS(cap)
unsigned int * PULONG
Definition: retypes.h:1
#define RESPONSE_FLAGS_UNSOLICITED
#define HDAC_CORB_CONTROL_MASK
NTSTATUS NTAPI IoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: irp.c:1218
PHDA_CODEC_AUDIO_GROUP AudioGroup
Definition: hdaudbus.h:90
PVOID NTAPI MmAllocateContiguousMemory(IN SIZE_T NumberOfBytes, IN PHYSICAL_ADDRESS HighestAcceptableAddress)
Definition: contmem.c:621
UINT Sent
Definition: arping.c:39
#define CORB_STATUS_MEMORY_ERROR
#define IoSkipCurrentIrpStackLocation(Irp)
Definition: ntifs_ex.h:421
#define HDAC_OUTPUT_STREAM_OFFSET(num_input_streams, index)
Definition: hdaudbus.h:23
#define CmResourceTypeInterrupt
Definition: hwresource.cpp:124
#define DPRINT1
Definition: precomp.h:8
#define CORB_CONTROL_RUN
#define RIRB_SIZE_CAP_256_ENTRIES
#define HDAC_CORB_READ_POS
#define OUT
Definition: typedefs.h:39
#define ObReferenceObject
Definition: obfuncs.h:204
#define CM_RESOURCE_INTERRUPT_LATCHED
Definition: cmtypes.h:144
PDEVICE_OBJECT ChildPDO
Definition: hdaudbus.h:39
#define HDAC_DMA_POSITION_BASE_LOWER
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
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
NTKERNELAPI USHORT NTAPI READ_REGISTER_USHORT(IN PUSHORT Register)
struct Response Response
#define ULONG_PTR
Definition: config.h:101
PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress(IN PVOID Address)
Definition: stubs.c:682
#define RIRB_SIZE_CAP_16_ENTRIES
#define RIRB_CONTROL_DMA_ENABLE
PKINTERRUPT Interrupt
Definition: hdaudbus.h:71
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2771
#define CmResourceTypeMemory
Definition: hwresource.cpp:125
#define FUNCTION_GROUP_NODETYPE_AUDIO
#define HDAC_CORB_SIZE_MASK
#define HDAC_CORB_SIZE
NTSTATUS NTAPI HDA_FDORemoveDevice(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
Definition: fdo.cpp:672
return STATUS_SUCCESS
Definition: btrfs.c:2725
PRIRB_RESPONSE RirbBase
Definition: hdaudbus.h:76
NTKERNELAPI VOID NTAPI WRITE_REGISTER_UCHAR(IN PUCHAR Register, IN UCHAR Value)
unsigned short * PUSHORT
Definition: retypes.h:2
VOID NTAPI KeStallExecutionProcessor(IN ULONG MicroSeconds)
Definition: ntoskrnl.c:99
base of all file and directory entries
Definition: entries.h:82
LONGLONG QuadPart
Definition: typedefs.h:112
ULONG ResponseCount
Definition: hdaudbus.h:55
#define HDAC_BIDIR_STREAM_OFFSET(num_input_streams, num_output_streams, index)
Definition: hdaudbus.h:25
#define CORB_SIZE_CAP_16_ENTRIES
#define RIRB_CONTROL_OVERRUN_INTR
KSEMAPHORE ResponseSemaphore
Definition: hdaudbus.h:56
_In_ PSTORAGE_PROPERTY_ID _Outptr_ PSTORAGE_DESCRIPTOR_HEADER * Descriptor
Definition: classpnp.h:966