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
) {
226 AudioGroup
= (PHDA_CODEC_AUDIO_GROUP
)AllocateItem(NonPagedPool
, sizeof(HDA_CODEC_AUDIO_GROUP
));
229 DPRINT1("hda: insufficient memory\n");
230 return STATUS_INSUFFICIENT_RESOURCES
;
233 /* init audio group */
234 AudioGroup
->NodeId
= NodeId
;
235 AudioGroup
->FunctionGroup
= FUNCTION_GROUP_NODETYPE_AUDIO
;
237 // Found an Audio Function Group!
238 DPRINT1("NodeId %x found an audio function group!\n");
240 Status
= IoCreateDevice(DeviceObject
->DriverObject
, sizeof(HDA_PDO_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_SOUND
, FILE_AUTOGENERATED_DEVICE_NAME
, FALSE
, &AudioGroup
->ChildPDO
);
241 if (!NT_SUCCESS(Status
))
243 FreeItem(AudioGroup
);
244 DPRINT1("hda failed to create device object %x\n", Status
);
249 ChildDeviceExtension
= (PHDA_PDO_DEVICE_EXTENSION
)AudioGroup
->ChildPDO
->DeviceExtension
;
250 ChildDeviceExtension
->IsFDO
= FALSE
;
251 ChildDeviceExtension
->Codec
= Entry
;
252 ChildDeviceExtension
->AudioGroup
= AudioGroup
;
253 ChildDeviceExtension
->FDO
= DeviceObject
;
256 AudioGroup
->ChildPDO
->Flags
|= DO_POWER_PAGABLE
;
257 AudioGroup
->ChildPDO
->Flags
&= ~DO_DEVICE_INITIALIZING
;
260 Entry
->AudioGroups
[Entry
->AudioGroupCount
] = AudioGroup
;
261 Entry
->AudioGroupCount
++;
264 return STATUS_SUCCESS
;
271 IN PDEVICE_OBJECT DeviceObject
)
273 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
274 UCHAR corbSize
, value
, rirbSize
;
275 PHYSICAL_ADDRESS HighestPhysicalAddress
, CorbPhysicalAddress
;
277 USHORT corbReadPointer
, rirbWritePointer
, interruptValue
, corbControl
, rirbControl
;
279 /* get device extension */
280 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
282 // Determine and set size of CORB
283 corbSize
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
);
284 if ((corbSize
& CORB_SIZE_CAP_256_ENTRIES
) != 0) {
285 DeviceExtension
->CorbLength
= 256;
287 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
) & HDAC_CORB_SIZE_MASK
;
288 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
, value
| CORB_SIZE_256_ENTRIES
);
290 else if (corbSize
& CORB_SIZE_CAP_16_ENTRIES
) {
291 DeviceExtension
->CorbLength
= 16;
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_16_ENTRIES
);
296 else if (corbSize
& CORB_SIZE_CAP_2_ENTRIES
) {
297 DeviceExtension
->CorbLength
= 2;
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_2_ENTRIES
);
303 // Determine and set size of RIRB
304 rirbSize
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
);
305 if (rirbSize
& RIRB_SIZE_CAP_256_ENTRIES
) {
306 DeviceExtension
->RirbLength
= 256;
308 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
) & HDAC_RIRB_SIZE_MASK
;
309 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
, value
| RIRB_SIZE_256_ENTRIES
);
311 else if (rirbSize
& RIRB_SIZE_CAP_16_ENTRIES
) {
312 DeviceExtension
->RirbLength
= 16;
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_16_ENTRIES
);
317 else if (rirbSize
& RIRB_SIZE_CAP_2_ENTRIES
) {
318 DeviceExtension
->RirbLength
= 2;
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_2_ENTRIES
);
325 HighestPhysicalAddress
.QuadPart
= 0x00000000FFFFFFFF;
326 DeviceExtension
->CorbBase
= (PULONG
)MmAllocateContiguousMemory(PAGE_SIZE
* 3, HighestPhysicalAddress
);
327 ASSERT(DeviceExtension
->CorbBase
!= NULL
);
329 // FIXME align rirb 128bytes
330 ASSERT(DeviceExtension
->CorbLength
== 256);
331 ASSERT(DeviceExtension
->RirbLength
== 256);
333 CorbPhysicalAddress
= MmGetPhysicalAddress(DeviceExtension
->CorbBase
);
334 ASSERT(CorbPhysicalAddress
.QuadPart
!= 0LL);
336 // Program CORB/RIRB for these locations
337 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_CORB_BASE_LOWER
), CorbPhysicalAddress
.LowPart
);
338 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_CORB_BASE_UPPER
), CorbPhysicalAddress
.HighPart
);
340 DeviceExtension
->RirbBase
= (PRIRB_RESPONSE
)((ULONG_PTR
)DeviceExtension
->CorbBase
+ PAGE_SIZE
);
341 CorbPhysicalAddress
.QuadPart
+= PAGE_SIZE
;
342 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_RIRB_BASE_LOWER
), CorbPhysicalAddress
.LowPart
);
343 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_RIRB_BASE_UPPER
), CorbPhysicalAddress
.HighPart
);
345 // Program DMA position update
346 DeviceExtension
->StreamPositions
= (PVOID
)((ULONG_PTR
)DeviceExtension
->RirbBase
+ PAGE_SIZE
);
347 CorbPhysicalAddress
.QuadPart
+= PAGE_SIZE
;
348 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_LOWER
), CorbPhysicalAddress
.LowPart
);
349 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_UPPER
), CorbPhysicalAddress
.HighPart
);
351 value
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
)) & HDAC_CORB_WRITE_POS_MASK
;
352 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
), value
);
354 // Reset CORB read pointer. Preserve bits marked as RsvdP.
355 // After setting the reset bit, we must wait for the hardware
356 // to acknowledge it, then manually unset it and wait for that
357 // to be acknowledged as well.
358 corbReadPointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
360 corbReadPointer
|= CORB_READ_POS_RESET
;
361 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
), corbReadPointer
);
363 for (Index
= 0; Index
< 100; Index
++) {
364 KeStallExecutionProcessor(10);
365 corbReadPointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
366 if ((corbReadPointer
& CORB_READ_POS_RESET
) != 0)
369 if ((corbReadPointer
& CORB_READ_POS_RESET
) == 0) {
370 DPRINT1("hda: CORB read pointer reset not acknowledged\n");
372 // According to HDA spec v1.0a ch3.3.21, software must read the
373 // bit as 1 to verify that the reset completed. However, at least
374 // some nVidia HDA controllers do not update the bit after reset.
375 // Thus don't fail here on nVidia controllers.
376 //if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
380 corbReadPointer
&= ~CORB_READ_POS_RESET
;
381 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
), corbReadPointer
);
382 for (Index
= 0; Index
< 10; Index
++) {
383 KeStallExecutionProcessor(10);
384 corbReadPointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
385 if ((corbReadPointer
& CORB_READ_POS_RESET
) == 0)
388 if ((corbReadPointer
& CORB_READ_POS_RESET
) != 0) {
389 DPRINT1("hda: CORB read pointer reset failed\n");
390 return STATUS_UNSUCCESSFUL
;
393 // Reset RIRB write pointer
394 rirbWritePointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_WRITE_POS
)) & RIRB_WRITE_POS_RESET
;
395 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_WRITE_POS
), rirbWritePointer
| RIRB_WRITE_POS_RESET
);
397 // Generate interrupt for every response
398 interruptValue
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RESPONSE_INTR_COUNT
)) & HDAC_RESPONSE_INTR_COUNT_MASK
;
399 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RESPONSE_INTR_COUNT
), interruptValue
| 1);
401 // Setup cached read/write indices
402 DeviceExtension
->RirbReadPos
= 1;
403 DeviceExtension
->CorbWritePos
= 0;
405 // Gentlemen, start your engines...
406 corbControl
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
)) &HDAC_CORB_CONTROL_MASK
;
407 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
), corbControl
| CORB_CONTROL_RUN
| CORB_CONTROL_MEMORY_ERROR_INTR
);
409 rirbControl
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
)) & HDAC_RIRB_CONTROL_MASK
;
410 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
), rirbControl
| RIRB_CONTROL_DMA_ENABLE
| RIRB_CONTROL_OVERRUN_INTR
| RIRB_CONTROL_RESPONSE_INTR
);
412 return STATUS_SUCCESS
;
418 IN PDEVICE_OBJECT DeviceObject
)
420 USHORT ValCapabilities
;
422 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
423 ULONG InputStreams
, OutputStreams
, BiDirStreams
, Control
;
424 UCHAR corbControl
, rirbControl
;
426 /* get device extension */
427 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
430 ValCapabilities
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CAP
));
432 InputStreams
= GLOBAL_CAP_INPUT_STREAMS(ValCapabilities
);
433 OutputStreams
= GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities
);
434 BiDirStreams
= GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities
);
436 DPRINT1("NumInputStreams %u\n", InputStreams
);
437 DPRINT1("NumOutputStreams %u\n", OutputStreams
);
438 DPRINT1("NumBiDirStreams %u\n", BiDirStreams
);
440 /* stop all streams */
441 for (Index
= 0; Index
< InputStreams
; Index
++)
443 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_CONTROL0
+ HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(Index
), 0);
444 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_STATUS
+ HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(Index
), 0);
447 for (Index
= 0; Index
< OutputStreams
; Index
++) {
448 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_CONTROL0
+ HDAC_STREAM_BASE
+ HDAC_OUTPUT_STREAM_OFFSET(InputStreams
, Index
), 0);
449 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_STATUS
+ HDAC_STREAM_BASE
+ HDAC_OUTPUT_STREAM_OFFSET(InputStreams
, Index
), 0);
452 for (Index
= 0; Index
< BiDirStreams
; Index
++) {
453 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_CONTROL0
+ HDAC_STREAM_BASE
+ HDAC_BIDIR_STREAM_OFFSET(InputStreams
, OutputStreams
, Index
), 0);
454 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_STATUS
+ HDAC_STREAM_BASE
+ HDAC_BIDIR_STREAM_OFFSET(InputStreams
, OutputStreams
, Index
), 0);
458 Control
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
) & HDAC_CORB_CONTROL_MASK
;
459 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
, Control
);
461 Control
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
) & HDAC_RIRB_CONTROL_MASK
;
462 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
, Control
);
464 for (int timeout
= 0; timeout
< 10; timeout
++) {
465 KeStallExecutionProcessor(10);
467 corbControl
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
);
468 rirbControl
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
);
469 if (corbControl
== 0 && rirbControl
== 0)
472 if (corbControl
!= 0 || rirbControl
!= 0) {
473 DPRINT1("hda: unable to stop dma\n");
474 return STATUS_UNSUCCESSFUL
;
477 // reset DMA position buffer
478 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_LOWER
), 0);
479 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_UPPER
), 0);
481 // Set reset bit - it must be asserted for at least 100us
482 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
483 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
), Control
& ~GLOBAL_CONTROL_RESET
);
485 for (int timeout
= 0; timeout
< 10; timeout
++) {
486 KeStallExecutionProcessor(10);
488 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
489 if ((Control
& GLOBAL_CONTROL_RESET
) == 0)
492 if ((Control
& GLOBAL_CONTROL_RESET
) != 0)
494 DPRINT1("hda: unable to reset controller\n");
495 return STATUS_UNSUCCESSFUL
;
499 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
500 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
), Control
| GLOBAL_CONTROL_RESET
);
502 for (int timeout
= 0; timeout
< 10; timeout
++) {
503 KeStallExecutionProcessor(10);
505 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
506 if ((Control
& GLOBAL_CONTROL_RESET
) != 0)
509 if ((Control
& GLOBAL_CONTROL_RESET
) == 0) {
510 DPRINT1("hda: unable to exit reset\n");
511 return STATUS_UNSUCCESSFUL
;
514 // Wait for codecs to finish their own reset (apparently needs more
515 // time than documented in the specs)
516 KeStallExecutionProcessor(100);
518 // Enable unsolicited responses
519 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
520 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
), Control
| GLOBAL_CONTROL_UNSOLICITED
);
522 return STATUS_SUCCESS
;
528 IN PDEVICE_OBJECT DeviceObject
,
531 PIO_STACK_LOCATION IoStack
;
532 NTSTATUS Status
= STATUS_SUCCESS
;
533 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
534 PCM_RESOURCE_LIST Resources
;
538 /* get device extension */
539 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
540 ASSERT(DeviceExtension
->IsFDO
== TRUE
);
542 /* forward irp to lower device */
543 Status
= HDA_SyncForwardIrp(DeviceExtension
->LowerDevice
, Irp
);
544 if (!NT_SUCCESS(Status
))
547 DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status
);
551 /* get current irp stack location */
552 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
554 Resources
= IoStack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
;
555 for (Index
= 0; Index
< Resources
->List
[0].PartialResourceList
.Count
; Index
++)
557 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
= &Resources
->List
[0].PartialResourceList
.PartialDescriptors
[Index
];
559 if (Descriptor
->Type
== CmResourceTypeMemory
)
561 DeviceExtension
->RegBase
= (PUCHAR
)MmMapIoSpace(Descriptor
->u
.Memory
.Start
, Descriptor
->u
.Memory
.Length
, MmNonCached
);
562 if (DeviceExtension
->RegBase
== NULL
)
564 DPRINT1("[HDAB] Failed to map registers\n");
565 Status
= STATUS_UNSUCCESSFUL
;
569 else if (Descriptor
->Type
== CmResourceTypeInterrupt
)
571 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
572 HDA_InterruptService
,
573 (PVOID
)DeviceExtension
,
575 Descriptor
->u
.Interrupt
.Vector
,
576 Descriptor
->u
.Interrupt
.Level
,
577 Descriptor
->u
.Interrupt
.Level
,
578 (KINTERRUPT_MODE
)(Descriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
),
579 (Descriptor
->ShareDisposition
!= CmResourceShareDeviceExclusive
),
580 Descriptor
->u
.Interrupt
.Affinity
,
582 if (!NT_SUCCESS(Status
))
584 DPRINT1("[HDAB] Failed to connect interrupt\n");
591 if (NT_SUCCESS(Status
))
593 // Get controller into valid state
594 Status
= HDA_ResetController(DeviceObject
);
595 if (!NT_SUCCESS(Status
)) return Status
;
597 // Setup CORB/RIRB/DMA POS
598 Status
= HDA_InitCorbRirbPos(DeviceObject
);
599 if (!NT_SUCCESS(Status
)) return Status
;
602 // Don't enable codec state change interrupts. We don't handle
603 // them, as we want to use the STATE_STATUS register to identify
604 // available codecs. We'd have to clear that register in the interrupt
605 // handler to 'ack' the codec change.
606 Value
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_WAKE_ENABLE
)) & HDAC_WAKE_ENABLE_MASK
;
607 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_WAKE_ENABLE
), Value
);
609 // Enable controller interrupts
610 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_INTR_CONTROL
), INTR_CONTROL_GLOBAL_ENABLE
| INTR_CONTROL_CONTROLLER_ENABLE
);
612 KeStallExecutionProcessor(100);
614 Value
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_STATE_STATUS
));
616 DPRINT1("hda: bad codec status\n");
617 return STATUS_UNSUCCESSFUL
;
619 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_STATE_STATUS
), Value
);
622 DPRINT1("Codecs %lx\n", Value
);
623 for (Index
= 0; Index
< HDA_MAX_CODECS
; Index
++) {
624 if ((Value
& (1 << Index
)) != 0) {
625 HDA_InitCodec(DeviceObject
, Index
);
635 HDA_FDOQueryBusRelations(
636 IN PDEVICE_OBJECT DeviceObject
,
639 ULONG DeviceCount
, CodecIndex
, AFGIndex
;
640 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
641 PHDA_CODEC_ENTRY Codec
;
642 PDEVICE_RELATIONS DeviceRelations
;
644 /* get device extension */
645 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
646 ASSERT(DeviceExtension
->IsFDO
== TRUE
);
649 for (CodecIndex
= 0; CodecIndex
< HDA_MAX_CODECS
; CodecIndex
++)
651 if (DeviceExtension
->Codecs
[CodecIndex
] == NULL
)
654 Codec
= DeviceExtension
->Codecs
[CodecIndex
];
655 DeviceCount
+= Codec
->AudioGroupCount
;
658 if (DeviceCount
== 0)
659 return STATUS_UNSUCCESSFUL
;
661 DeviceRelations
= (PDEVICE_RELATIONS
)AllocateItem(NonPagedPool
, sizeof(DEVICE_RELATIONS
) + (DeviceCount
> 1 ? sizeof(PDEVICE_OBJECT
) * (DeviceCount
- 1) : 0));
662 if (!DeviceRelations
)
663 return STATUS_INSUFFICIENT_RESOURCES
;
666 for (CodecIndex
= 0; CodecIndex
< HDA_MAX_CODECS
; CodecIndex
++)
668 if (DeviceExtension
->Codecs
[CodecIndex
] == NULL
)
671 Codec
= DeviceExtension
->Codecs
[CodecIndex
];
672 for (AFGIndex
= 0; AFGIndex
< Codec
->AudioGroupCount
; AFGIndex
++)
674 DeviceRelations
->Objects
[DeviceRelations
->Count
] = Codec
->AudioGroups
[AFGIndex
]->ChildPDO
;
675 ObReferenceObject(Codec
->AudioGroups
[AFGIndex
]->ChildPDO
);
676 DeviceRelations
->Count
++;
680 /* FIXME handle existing device relations */
681 ASSERT(Irp
->IoStatus
.Information
== 0);
683 /* store device relations */
684 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
687 return STATUS_SUCCESS
;