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
13 IN PKINTERRUPT Interrupt
,
14 IN PVOID ServiceContext
)
16 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
17 ULONG InterruptStatus
, Response
, ResponseFlags
, Cad
;
18 UCHAR RirbStatus
, CorbStatus
;
20 PHDA_CODEC_ENTRY Codec
;
22 /* get device extension */
23 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)ServiceContext
;
24 ASSERT(DeviceExtension
->IsFDO
== TRUE
);
26 // Check if this interrupt is ours
27 InterruptStatus
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_INTR_STATUS
));
29 DPRINT1("HDA_InterruptService %lx\n", InterruptStatus
);
30 if ((InterruptStatus
& INTR_STATUS_GLOBAL
) == 0)
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
);
38 // Check for incoming responses
40 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_STATUS
, RirbStatus
);
42 if (DeviceExtension
->RirbLength
== 0)
44 /* HACK: spurious interrupt */
48 if ((RirbStatus
& RIRB_STATUS_RESPONSE
) != 0) {
49 WritePos
= (READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_WRITE_POS
)) + 1) % DeviceExtension
->RirbLength
;
51 for (; DeviceExtension
->RirbReadPos
!= WritePos
; DeviceExtension
->RirbReadPos
= (DeviceExtension
->RirbReadPos
+ 1) % DeviceExtension
->RirbLength
)
54 Response
= DeviceExtension
->RirbBase
[DeviceExtension
->RirbReadPos
].response
;
55 ResponseFlags
= DeviceExtension
->RirbBase
[DeviceExtension
->RirbReadPos
].flags
;
56 Cad
= ResponseFlags
& RESPONSE_FLAGS_CODEC_MASK
;
57 DPRINT1("Response %lx ResponseFlags %lx Cad %lx\n", Response
, ResponseFlags
, Cad
);
60 Codec
= DeviceExtension
->Codecs
[Cad
];
63 DPRINT1("hda: response for unknown codec %x Response %x ResponseFlags %x\n", Cad
, Response
, ResponseFlags
);
67 /* check response count */
68 if (Codec
->ResponseCount
>= MAX_CODEC_RESPONSES
)
70 DPRINT1("too many responses for codec %x Response %x ResponseFlags %x\n", Cad
, Response
, ResponseFlags
);
74 // FIXME handle unsolicited responses
75 ASSERT((ResponseFlags
& RESPONSE_FLAGS_UNSOLICITED
) == 0);
78 Codec
->Responses
[Codec
->ResponseCount
] = Response
;
79 Codec
->ResponseCount
++;
83 if ((RirbStatus
& RIRB_STATUS_OVERRUN
) != 0)
84 DPRINT1("hda: RIRB Overflow\n");
87 // Check for sending errors
89 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_STATUS
, CorbStatus
);
91 if ((CorbStatus
& CORB_STATUS_MEMORY_ERROR
) != 0)
92 DPRINT1("hda: CORB Memory Error!\n");
96 if ((intrStatus
& INTR_STATUS_STREAM_MASK
) != 0) {
97 for (uint32 index
= 0; index
< HDA_MAX_STREAMS
; index
++) {
98 if ((intrStatus
& (1 << index
)) != 0) {
99 if (controller
->streams
[index
]) {
100 if (stream_handle_interrupt(controller
,
101 controller
->streams
[index
], index
)) {
102 handled
= B_INVOKE_SCHEDULER
;
106 dprintf("hda: Stream interrupt for unconfigured stream "
119 IN PDEVICE_OBJECT DeviceObject
,
120 IN PHDA_CODEC_ENTRY Codec
,
122 OUT PULONG Responses
,
125 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
126 ULONG Sent
= 0, ReadPosition
, WritePosition
, Queued
;
128 /* get device extension */
129 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
130 ASSERT(DeviceExtension
->IsFDO
);
132 /* reset response count */
133 Codec
->ResponseCount
= 0;
135 while (Sent
< Count
) {
136 ReadPosition
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
140 while (Sent
< Count
) {
141 WritePosition
= (DeviceExtension
->CorbWritePos
+ 1) % DeviceExtension
->CorbLength
;
143 if (WritePosition
== ReadPosition
) {
144 // There is no space left in the ring buffer; execute the
145 // queued commands and wait until
149 DeviceExtension
->CorbBase
[WritePosition
] = Verbs
[Sent
++];
150 DeviceExtension
->CorbWritePos
= WritePosition
;
153 // do proper synchronization
154 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
), DeviceExtension
->CorbWritePos
);
155 KeStallExecutionProcessor(30);
159 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
), DeviceExtension
->CorbWritePos
);
162 if (Responses
!= NULL
) {
163 memcpy(Responses
, Codec
->Responses
, Codec
->ResponseCount
* sizeof(ULONG
));
169 IN PDEVICE_OBJECT DeviceObject
,
170 IN ULONG codecAddress
)
172 PHDA_CODEC_ENTRY Entry
;
174 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
175 CODEC_RESPONSE Response
;
176 ULONG NodeId
, GroupType
;
178 PHDA_CODEC_AUDIO_GROUP AudioGroup
;
179 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension
;
181 /* lets allocate the entry */
182 Entry
= (PHDA_CODEC_ENTRY
)AllocateItem(NonPagedPool
, sizeof(HDA_CODEC_ENTRY
));
185 DPRINT1("hda: failed to allocate memory");
186 return STATUS_UNSUCCESSFUL
;
190 Entry
->Addr
= codecAddress
;
192 /* get device extension */
193 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
196 DeviceExtension
->Codecs
[codecAddress
] = Entry
;
198 verbs
[0] = MAKE_VERB(codecAddress
, 0, VID_GET_PARAMETER
, PID_VENDOR_ID
);
199 verbs
[1] = MAKE_VERB(codecAddress
, 0, VID_GET_PARAMETER
, PID_REVISION_ID
);
200 verbs
[2] = MAKE_VERB(codecAddress
, 0, VID_GET_PARAMETER
, PID_SUB_NODE_COUNT
);
203 HDA_SendVerbs(DeviceObject
, Entry
, verbs
, (PULONG
)&Response
, 3);
205 /* store codec details */
206 Entry
->Major
= Response
.major
;
207 Entry
->Minor
= Response
.minor
;
208 Entry
->ProductId
= Response
.device
;
209 Entry
->Revision
= Response
.revision
;
210 Entry
->Stepping
= Response
.stepping
;
211 Entry
->VendorId
= Response
.vendor
;
213 DPRINT1("hda Codec %ld Vendor: %04lx Product: %04lx, Revision: %lu.%lu.%lu.%lu NodeStart %u NodeCount %u \n", codecAddress
, Response
.vendor
,
214 Response
.device
, Response
.major
, Response
.minor
, Response
.revision
, Response
.stepping
, Response
.start
, Response
.count
);
216 for (NodeId
= Response
.start
; NodeId
< Response
.start
+ Response
.count
; NodeId
++) {
218 /* get function type */
219 verbs
[0] = MAKE_VERB(codecAddress
, NodeId
, VID_GET_PARAMETER
, PID_FUNCTION_GROUP_TYPE
);
221 HDA_SendVerbs(DeviceObject
, Entry
, verbs
, &GroupType
, 1);
222 DPRINT1("NodeId %u GroupType %x\n", NodeId
, GroupType
);
224 if ((GroupType
& FUNCTION_GROUP_NODETYPE_MASK
) == FUNCTION_GROUP_NODETYPE_AUDIO
) {
225 if (Entry
->AudioGroupCount
>= HDA_MAX_AUDIO_GROUPS
)
227 DPRINT1("Too many audio groups in node %u. Skipping.\n", NodeId
);
231 AudioGroup
= (PHDA_CODEC_AUDIO_GROUP
)AllocateItem(NonPagedPool
, sizeof(HDA_CODEC_AUDIO_GROUP
));
234 DPRINT1("hda: insufficient memory\n");
235 return STATUS_INSUFFICIENT_RESOURCES
;
238 /* init audio group */
239 AudioGroup
->NodeId
= NodeId
;
240 AudioGroup
->FunctionGroup
= FUNCTION_GROUP_NODETYPE_AUDIO
;
242 // Found an Audio Function Group!
243 DPRINT1("NodeId %x found an audio function group!\n", NodeId
);
245 Status
= IoCreateDevice(DeviceObject
->DriverObject
, sizeof(HDA_PDO_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_SOUND
, FILE_AUTOGENERATED_DEVICE_NAME
, FALSE
, &AudioGroup
->ChildPDO
);
246 if (!NT_SUCCESS(Status
))
248 FreeItem(AudioGroup
);
249 DPRINT1("hda failed to create device object %x\n", Status
);
254 ChildDeviceExtension
= (PHDA_PDO_DEVICE_EXTENSION
)AudioGroup
->ChildPDO
->DeviceExtension
;
255 ChildDeviceExtension
->IsFDO
= FALSE
;
256 ChildDeviceExtension
->ReportedMissing
= FALSE
;
257 ChildDeviceExtension
->Codec
= Entry
;
258 ChildDeviceExtension
->AudioGroup
= AudioGroup
;
259 ChildDeviceExtension
->FDO
= DeviceObject
;
262 AudioGroup
->ChildPDO
->Flags
|= DO_POWER_PAGABLE
;
263 AudioGroup
->ChildPDO
->Flags
&= ~DO_DEVICE_INITIALIZING
;
266 Entry
->AudioGroups
[Entry
->AudioGroupCount
] = AudioGroup
;
267 Entry
->AudioGroupCount
++;
270 return STATUS_SUCCESS
;
277 IN PDEVICE_OBJECT DeviceObject
)
279 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
280 UCHAR corbSize
, value
, rirbSize
;
281 PHYSICAL_ADDRESS HighestPhysicalAddress
, CorbPhysicalAddress
;
283 USHORT corbReadPointer
, rirbWritePointer
, interruptValue
, corbControl
, rirbControl
;
285 /* get device extension */
286 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
288 // Determine and set size of CORB
289 corbSize
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
);
290 if ((corbSize
& CORB_SIZE_CAP_256_ENTRIES
) != 0) {
291 DeviceExtension
->CorbLength
= 256;
293 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
) & ~HDAC_CORB_SIZE_MASK
;
294 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
, value
| CORB_SIZE_256_ENTRIES
);
296 else if (corbSize
& CORB_SIZE_CAP_16_ENTRIES
) {
297 DeviceExtension
->CorbLength
= 16;
299 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
) & ~HDAC_CORB_SIZE_MASK
;
300 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
, value
| CORB_SIZE_16_ENTRIES
);
302 else if (corbSize
& CORB_SIZE_CAP_2_ENTRIES
) {
303 DeviceExtension
->CorbLength
= 2;
305 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
) & ~HDAC_CORB_SIZE_MASK
;
306 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
, value
| CORB_SIZE_2_ENTRIES
);
309 // Determine and set size of RIRB
310 rirbSize
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
);
311 if (rirbSize
& RIRB_SIZE_CAP_256_ENTRIES
) {
312 DeviceExtension
->RirbLength
= 256;
314 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
) & ~HDAC_RIRB_SIZE_MASK
;
315 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
, value
| RIRB_SIZE_256_ENTRIES
);
317 else if (rirbSize
& RIRB_SIZE_CAP_16_ENTRIES
) {
318 DeviceExtension
->RirbLength
= 16;
320 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
) & ~HDAC_RIRB_SIZE_MASK
;
321 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
, value
| RIRB_SIZE_16_ENTRIES
);
323 else if (rirbSize
& RIRB_SIZE_CAP_2_ENTRIES
) {
324 DeviceExtension
->RirbLength
= 2;
326 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
) & ~HDAC_RIRB_SIZE_MASK
;
327 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
, value
| RIRB_SIZE_2_ENTRIES
);
331 HighestPhysicalAddress
.QuadPart
= 0x00000000FFFFFFFF;
332 DeviceExtension
->CorbBase
= (PULONG
)MmAllocateContiguousMemory(PAGE_SIZE
* 3, HighestPhysicalAddress
);
333 ASSERT(DeviceExtension
->CorbBase
!= NULL
);
335 // FIXME align rirb 128bytes
336 ASSERT(DeviceExtension
->CorbLength
== 256);
337 ASSERT(DeviceExtension
->RirbLength
== 256);
339 CorbPhysicalAddress
= MmGetPhysicalAddress(DeviceExtension
->CorbBase
);
340 ASSERT(CorbPhysicalAddress
.QuadPart
!= 0LL);
342 // Program CORB/RIRB for these locations
343 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_CORB_BASE_LOWER
), CorbPhysicalAddress
.LowPart
);
344 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_CORB_BASE_UPPER
), CorbPhysicalAddress
.HighPart
);
346 DeviceExtension
->RirbBase
= (PRIRB_RESPONSE
)((ULONG_PTR
)DeviceExtension
->CorbBase
+ PAGE_SIZE
);
347 CorbPhysicalAddress
.QuadPart
+= PAGE_SIZE
;
348 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_RIRB_BASE_LOWER
), CorbPhysicalAddress
.LowPart
);
349 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_RIRB_BASE_UPPER
), CorbPhysicalAddress
.HighPart
);
351 // Program DMA position update
352 DeviceExtension
->StreamPositions
= (PVOID
)((ULONG_PTR
)DeviceExtension
->RirbBase
+ PAGE_SIZE
);
353 CorbPhysicalAddress
.QuadPart
+= PAGE_SIZE
;
354 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_LOWER
), CorbPhysicalAddress
.LowPart
);
355 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_UPPER
), CorbPhysicalAddress
.HighPart
);
357 value
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
)) & ~HDAC_CORB_WRITE_POS_MASK
;
358 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
), value
);
360 // Reset CORB read pointer. Preserve bits marked as RsvdP.
361 // After setting the reset bit, we must wait for the hardware
362 // to acknowledge it, then manually unset it and wait for that
363 // to be acknowledged as well.
364 corbReadPointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
366 corbReadPointer
|= CORB_READ_POS_RESET
;
367 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
), corbReadPointer
);
369 for (Index
= 0; Index
< 100; Index
++) {
370 KeStallExecutionProcessor(10);
371 corbReadPointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
372 if ((corbReadPointer
& CORB_READ_POS_RESET
) != 0)
375 if ((corbReadPointer
& CORB_READ_POS_RESET
) == 0) {
376 DPRINT1("hda: CORB read pointer reset not acknowledged\n");
378 // According to HDA spec v1.0a ch3.3.21, software must read the
379 // bit as 1 to verify that the reset completed. However, at least
380 // some nVidia HDA controllers do not update the bit after reset.
381 // Thus don't fail here on nVidia controllers.
382 //if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
386 corbReadPointer
&= ~CORB_READ_POS_RESET
;
387 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
), corbReadPointer
);
388 for (Index
= 0; Index
< 10; Index
++) {
389 KeStallExecutionProcessor(10);
390 corbReadPointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
391 if ((corbReadPointer
& CORB_READ_POS_RESET
) == 0)
394 if ((corbReadPointer
& CORB_READ_POS_RESET
) != 0) {
395 DPRINT1("hda: CORB read pointer reset failed\n");
396 return STATUS_UNSUCCESSFUL
;
399 // Reset RIRB write pointer
400 rirbWritePointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_WRITE_POS
)) & ~RIRB_WRITE_POS_RESET
;
401 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_WRITE_POS
), rirbWritePointer
| RIRB_WRITE_POS_RESET
);
403 // Generate interrupt for every response
404 interruptValue
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RESPONSE_INTR_COUNT
)) & ~HDAC_RESPONSE_INTR_COUNT_MASK
;
405 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RESPONSE_INTR_COUNT
), interruptValue
| 1);
407 // Setup cached read/write indices
408 DeviceExtension
->RirbReadPos
= 1;
409 DeviceExtension
->CorbWritePos
= 0;
411 // Gentlemen, start your engines...
412 corbControl
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
)) & ~HDAC_CORB_CONTROL_MASK
;
413 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
), corbControl
| CORB_CONTROL_RUN
| CORB_CONTROL_MEMORY_ERROR_INTR
);
415 rirbControl
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
)) & ~HDAC_RIRB_CONTROL_MASK
;
416 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
), rirbControl
| RIRB_CONTROL_DMA_ENABLE
| RIRB_CONTROL_OVERRUN_INTR
| RIRB_CONTROL_RESPONSE_INTR
);
418 return STATUS_SUCCESS
;
424 IN PDEVICE_OBJECT DeviceObject
)
426 USHORT ValCapabilities
;
428 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
429 ULONG InputStreams
, OutputStreams
, BiDirStreams
, Control
;
430 UCHAR corbControl
, rirbControl
;
432 /* get device extension */
433 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
436 ValCapabilities
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CAP
));
438 InputStreams
= GLOBAL_CAP_INPUT_STREAMS(ValCapabilities
);
439 OutputStreams
= GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities
);
440 BiDirStreams
= GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities
);
442 DPRINT1("NumInputStreams %u\n", InputStreams
);
443 DPRINT1("NumOutputStreams %u\n", OutputStreams
);
444 DPRINT1("NumBiDirStreams %u\n", BiDirStreams
);
446 /* stop all streams */
447 for (Index
= 0; Index
< InputStreams
; Index
++)
449 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_CONTROL0
+ HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(Index
), 0);
450 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_STATUS
+ HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(Index
), 0);
453 for (Index
= 0; Index
< OutputStreams
; Index
++) {
454 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_CONTROL0
+ HDAC_STREAM_BASE
+ HDAC_OUTPUT_STREAM_OFFSET(InputStreams
, Index
), 0);
455 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_STATUS
+ HDAC_STREAM_BASE
+ HDAC_OUTPUT_STREAM_OFFSET(InputStreams
, Index
), 0);
458 for (Index
= 0; Index
< BiDirStreams
; Index
++) {
459 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_CONTROL0
+ HDAC_STREAM_BASE
+ HDAC_BIDIR_STREAM_OFFSET(InputStreams
, OutputStreams
, Index
), 0);
460 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_STATUS
+ HDAC_STREAM_BASE
+ HDAC_BIDIR_STREAM_OFFSET(InputStreams
, OutputStreams
, Index
), 0);
464 Control
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
) & ~HDAC_CORB_CONTROL_MASK
;
465 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
, Control
);
467 Control
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
) & ~HDAC_RIRB_CONTROL_MASK
;
468 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
, Control
);
470 for (int timeout
= 0; timeout
< 10; timeout
++) {
471 KeStallExecutionProcessor(10);
473 corbControl
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
);
474 rirbControl
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
);
475 if (corbControl
== 0 && rirbControl
== 0)
478 if (corbControl
!= 0 || rirbControl
!= 0) {
479 DPRINT1("hda: unable to stop dma\n");
480 return STATUS_UNSUCCESSFUL
;
483 // reset DMA position buffer
484 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_LOWER
), 0);
485 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_UPPER
), 0);
487 // Set reset bit - it must be asserted for at least 100us
488 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
489 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
), Control
& ~GLOBAL_CONTROL_RESET
);
491 for (int timeout
= 0; timeout
< 10; timeout
++) {
492 KeStallExecutionProcessor(10);
494 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
495 if ((Control
& GLOBAL_CONTROL_RESET
) == 0)
498 if ((Control
& GLOBAL_CONTROL_RESET
) != 0)
500 DPRINT1("hda: unable to reset controller\n");
501 return STATUS_UNSUCCESSFUL
;
505 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
506 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
), Control
| GLOBAL_CONTROL_RESET
);
508 for (int timeout
= 0; timeout
< 10; timeout
++) {
509 KeStallExecutionProcessor(10);
511 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
512 if ((Control
& GLOBAL_CONTROL_RESET
) != 0)
515 if ((Control
& GLOBAL_CONTROL_RESET
) == 0) {
516 DPRINT1("hda: unable to exit reset\n");
517 return STATUS_UNSUCCESSFUL
;
520 // Wait for codecs to finish their own reset (apparently needs more
521 // time than documented in the specs)
522 KeStallExecutionProcessor(100);
524 // Enable unsolicited responses
525 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
526 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
), Control
| GLOBAL_CONTROL_UNSOLICITED
);
528 return STATUS_SUCCESS
;
534 IN PDEVICE_OBJECT DeviceObject
,
537 PIO_STACK_LOCATION IoStack
;
538 NTSTATUS Status
= STATUS_SUCCESS
;
539 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
540 PCM_RESOURCE_LIST Resources
;
544 /* get device extension */
545 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
546 ASSERT(DeviceExtension
->IsFDO
== TRUE
);
548 /* forward irp to lower device */
549 if (!IoForwardIrpSynchronously(DeviceExtension
->LowerDevice
, Irp
))
552 return STATUS_INVALID_DEVICE_REQUEST
;
554 Status
= Irp
->IoStatus
.Status
;
555 if (!NT_SUCCESS(Status
))
558 DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status
);
562 /* get current irp stack location */
563 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
565 Resources
= IoStack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
;
566 for (Index
= 0; Index
< Resources
->List
[0].PartialResourceList
.Count
; Index
++)
568 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
= &Resources
->List
[0].PartialResourceList
.PartialDescriptors
[Index
];
570 if (Descriptor
->Type
== CmResourceTypeMemory
)
572 DeviceExtension
->RegLength
= Descriptor
->u
.Memory
.Length
;
573 DeviceExtension
->RegBase
= (PUCHAR
)MmMapIoSpace(Descriptor
->u
.Memory
.Start
, Descriptor
->u
.Memory
.Length
, MmNonCached
);
574 if (DeviceExtension
->RegBase
== NULL
)
576 DPRINT1("[HDAB] Failed to map registers\n");
577 Status
= STATUS_UNSUCCESSFUL
;
581 else if (Descriptor
->Type
== CmResourceTypeInterrupt
)
583 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
584 HDA_InterruptService
,
585 (PVOID
)DeviceExtension
,
587 Descriptor
->u
.Interrupt
.Vector
,
588 Descriptor
->u
.Interrupt
.Level
,
589 Descriptor
->u
.Interrupt
.Level
,
590 (KINTERRUPT_MODE
)(Descriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
),
591 (Descriptor
->ShareDisposition
!= CmResourceShareDeviceExclusive
),
592 Descriptor
->u
.Interrupt
.Affinity
,
594 if (!NT_SUCCESS(Status
))
596 DPRINT1("[HDAB] Failed to connect interrupt. Status=%lx\n", Status
);
603 if (NT_SUCCESS(Status
))
605 // Get controller into valid state
606 Status
= HDA_ResetController(DeviceObject
);
607 if (!NT_SUCCESS(Status
)) return Status
;
609 // Setup CORB/RIRB/DMA POS
610 Status
= HDA_InitCorbRirbPos(DeviceObject
);
611 if (!NT_SUCCESS(Status
)) return Status
;
614 // Don't enable codec state change interrupts. We don't handle
615 // them, as we want to use the STATE_STATUS register to identify
616 // available codecs. We'd have to clear that register in the interrupt
617 // handler to 'ack' the codec change.
618 Value
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_WAKE_ENABLE
)) & ~HDAC_WAKE_ENABLE_MASK
;
619 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_WAKE_ENABLE
), Value
);
621 // Enable controller interrupts
622 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_INTR_CONTROL
), INTR_CONTROL_GLOBAL_ENABLE
| INTR_CONTROL_CONTROLLER_ENABLE
);
624 KeStallExecutionProcessor(100);
626 Value
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_STATE_STATUS
));
628 DPRINT1("hda: bad codec status\n");
629 return STATUS_UNSUCCESSFUL
;
631 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_STATE_STATUS
), Value
);
634 DPRINT1("Codecs %lx\n", Value
);
635 for (Index
= 0; Index
< HDA_MAX_CODECS
; Index
++) {
636 if ((Value
& (1 << Index
)) != 0) {
637 HDA_InitCodec(DeviceObject
, Index
);
648 _In_ PDEVICE_OBJECT DeviceObject
,
652 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
653 ULONG CodecIndex
, AFGIndex
;
654 PHDA_CODEC_ENTRY CodecEntry
;
655 PDEVICE_OBJECT ChildPDO
;
656 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension
;
658 /* get device extension */
659 DeviceExtension
= static_cast<PHDA_FDO_DEVICE_EXTENSION
>(DeviceObject
->DeviceExtension
);
660 ASSERT(DeviceExtension
->IsFDO
== TRUE
);
662 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
663 IoSkipCurrentIrpStackLocation(Irp
);
664 Status
= IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
666 IoDetachDevice(DeviceExtension
->LowerDevice
);
668 if (DeviceExtension
->RegBase
!= NULL
)
670 MmUnmapIoSpace(DeviceExtension
->RegBase
,
671 DeviceExtension
->RegLength
);
673 if (DeviceExtension
->Interrupt
!= NULL
)
675 IoDisconnectInterrupt(DeviceExtension
->Interrupt
);
677 if (DeviceExtension
->CorbBase
!= NULL
)
679 MmFreeContiguousMemory(DeviceExtension
->CorbBase
);
682 for (CodecIndex
= 0; CodecIndex
< HDA_MAX_CODECS
; CodecIndex
++)
684 CodecEntry
= DeviceExtension
->Codecs
[CodecIndex
];
685 if (CodecEntry
== NULL
)
690 ASSERT(CodecEntry
->AudioGroupCount
<= HDA_MAX_AUDIO_GROUPS
);
691 for (AFGIndex
= 0; AFGIndex
< CodecEntry
->AudioGroupCount
; AFGIndex
++)
693 ChildPDO
= CodecEntry
->AudioGroups
[AFGIndex
]->ChildPDO
;
694 if (ChildPDO
!= NULL
)
696 ChildDeviceExtension
= static_cast<PHDA_PDO_DEVICE_EXTENSION
>(ChildPDO
->DeviceExtension
);
697 ChildDeviceExtension
->Codec
= NULL
;
698 ChildDeviceExtension
->AudioGroup
= NULL
;
699 ChildDeviceExtension
->FDO
= NULL
;
700 ChildDeviceExtension
->ReportedMissing
= TRUE
;
701 HDA_PDORemoveDevice(ChildPDO
);
703 FreeItem(CodecEntry
->AudioGroups
[AFGIndex
]);
705 FreeItem(CodecEntry
);
708 IoDeleteDevice(DeviceObject
);
715 HDA_FDOQueryBusRelations(
716 IN PDEVICE_OBJECT DeviceObject
,
719 ULONG DeviceCount
, CodecIndex
, AFGIndex
;
720 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
721 PHDA_CODEC_ENTRY Codec
;
722 PDEVICE_RELATIONS DeviceRelations
;
724 /* get device extension */
725 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
726 ASSERT(DeviceExtension
->IsFDO
== TRUE
);
729 for (CodecIndex
= 0; CodecIndex
< HDA_MAX_CODECS
; CodecIndex
++)
731 if (DeviceExtension
->Codecs
[CodecIndex
] == NULL
)
734 Codec
= DeviceExtension
->Codecs
[CodecIndex
];
735 DeviceCount
+= Codec
->AudioGroupCount
;
738 if (DeviceCount
== 0)
739 return STATUS_UNSUCCESSFUL
;
741 DeviceRelations
= (PDEVICE_RELATIONS
)AllocateItem(NonPagedPool
, sizeof(DEVICE_RELATIONS
) + (DeviceCount
> 1 ? sizeof(PDEVICE_OBJECT
) * (DeviceCount
- 1) : 0));
742 if (!DeviceRelations
)
743 return STATUS_INSUFFICIENT_RESOURCES
;
745 DeviceRelations
->Count
= 0;
746 for (CodecIndex
= 0; CodecIndex
< HDA_MAX_CODECS
; CodecIndex
++)
748 if (DeviceExtension
->Codecs
[CodecIndex
] == NULL
)
751 Codec
= DeviceExtension
->Codecs
[CodecIndex
];
752 ASSERT(Codec
->AudioGroupCount
<= HDA_MAX_AUDIO_GROUPS
);
753 for (AFGIndex
= 0; AFGIndex
< Codec
->AudioGroupCount
; AFGIndex
++)
755 DeviceRelations
->Objects
[DeviceRelations
->Count
] = Codec
->AudioGroups
[AFGIndex
]->ChildPDO
;
756 ObReferenceObject(Codec
->AudioGroups
[AFGIndex
]->ChildPDO
);
757 DeviceRelations
->Count
++;
761 /* FIXME handle existing device relations */
762 ASSERT(Irp
->IoStatus
.Information
== 0);
764 /* store device relations */
765 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
768 return STATUS_SUCCESS
;