2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/hdaudbus/hdaudbus.cpp
5 * PURPOSE: HDA Driver Entry
6 * PROGRAMMER: Johannes Anderwald
15 IN POOL_TYPE PoolType
,
16 IN SIZE_T NumberOfBytes
)
18 PVOID Item
= ExAllocatePoolWithTag(PoolType
, NumberOfBytes
, TAG_HDA
);
22 RtlZeroMemory(Item
, NumberOfBytes
);
36 IN PKINTERRUPT Interrupt
,
37 IN PVOID ServiceContext
)
39 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
40 ULONG InterruptStatus
, Response
, ResponseFlags
, Cad
;
41 UCHAR RirbStatus
, CorbStatus
;
43 PHDA_CODEC_ENTRY Codec
;
45 /* get device extension */
46 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)ServiceContext
;
48 // Check if this interrupt is ours
49 InterruptStatus
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_INTR_STATUS
));
51 DPRINT1("HDA_InterruptService %lx\n", InterruptStatus
);
52 if ((InterruptStatus
& INTR_STATUS_GLOBAL
) == 0)
55 // Controller or stream related?
56 if (InterruptStatus
& INTR_STATUS_CONTROLLER
) {
57 RirbStatus
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_STATUS
);
58 CorbStatus
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_STATUS
);
60 // Check for incoming responses
62 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_STATUS
, RirbStatus
);
64 if ((RirbStatus
& RIRB_STATUS_RESPONSE
) != 0) {
65 WritePos
= (READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_WRITE_POS
)) + 1) % DeviceExtension
->RirbLength
;
67 for (; DeviceExtension
->RirbReadPos
!= WritePos
; DeviceExtension
->RirbReadPos
= (DeviceExtension
->RirbReadPos
+ 1) % DeviceExtension
->RirbLength
)
70 Response
= DeviceExtension
->RirbBase
[DeviceExtension
->RirbReadPos
].response
;
71 ResponseFlags
= DeviceExtension
->RirbBase
[DeviceExtension
->RirbReadPos
].flags
;
72 Cad
= ResponseFlags
& RESPONSE_FLAGS_CODEC_MASK
;
73 DPRINT1("Response %lx ResponseFlags %lx Cad %lx\n", Response
, ResponseFlags
, Cad
);
76 Codec
= DeviceExtension
->Codecs
[Cad
];
79 DPRINT1("hda: response for unknown codec %x Response %x ResponseFlags %x\n", Cad
, Response
, ResponseFlags
);
83 /* check response count */
84 if (Codec
->ResponseCount
>= MAX_CODEC_RESPONSES
)
86 DPRINT1("too many responses for codec %x Response %x ResponseFlags %x\n", Cad
, Response
, ResponseFlags
);
90 // FIXME handle unsolicited responses
91 ASSERT((ResponseFlags
& RESPONSE_FLAGS_UNSOLICITED
) == 0);
94 Codec
->Responses
[Codec
->ResponseCount
] = Response
;
95 Codec
->ResponseCount
++;
99 if ((RirbStatus
& RIRB_STATUS_OVERRUN
) != 0)
100 DPRINT1("hda: RIRB Overflow\n");
103 // Check for sending errors
105 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_STATUS
, CorbStatus
);
107 if ((CorbStatus
& CORB_STATUS_MEMORY_ERROR
) != 0)
108 DPRINT1("hda: CORB Memory Error!\n");
112 if ((intrStatus
& INTR_STATUS_STREAM_MASK
) != 0) {
113 for (uint32 index
= 0; index
< HDA_MAX_STREAMS
; index
++) {
114 if ((intrStatus
& (1 << index
)) != 0) {
115 if (controller
->streams
[index
]) {
116 if (stream_handle_interrupt(controller
,
117 controller
->streams
[index
], index
)) {
118 handled
= B_INVOKE_SCHEDULER
;
122 dprintf("hda: Stream interrupt for unconfigured stream "
134 IN PDEVICE_OBJECT DeviceObject
,
135 IN PHDA_CODEC_ENTRY Codec
,
137 OUT PULONG Responses
,
140 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
141 ULONG Sent
= 0, ReadPosition
, WritePosition
, Queued
;
143 /* get device extension */
144 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
146 /* reset response count */
147 Codec
->ResponseCount
= 0;
149 while (Sent
< Count
) {
150 ReadPosition
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
154 while (Sent
< Count
) {
155 WritePosition
= (DeviceExtension
->CorbWritePos
+ 1) % DeviceExtension
->CorbLength
;
157 if (WritePosition
== ReadPosition
) {
158 // There is no space left in the ring buffer; execute the
159 // queued commands and wait until
163 DeviceExtension
->CorbBase
[WritePosition
] = Verbs
[Sent
++];
164 DeviceExtension
->CorbWritePos
= WritePosition
;
167 // do proper synchronization
168 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
), DeviceExtension
->CorbWritePos
);
169 KeStallExecutionProcessor(30);
173 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
), DeviceExtension
->CorbWritePos
);
176 if (Responses
!= NULL
) {
177 memcpy(Responses
, Codec
->Responses
, Codec
->ResponseCount
* sizeof(ULONG
));
183 IN PDEVICE_OBJECT DeviceObject
,
184 IN ULONG codecAddress
)
186 PHDA_CODEC_ENTRY Entry
;
188 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
189 CODEC_RESPONSE Response
;
190 ULONG NodeId
, GroupType
;
192 PHDA_CODEC_AUDIO_GROUP AudioGroup
;
193 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension
;
195 /* lets allocate the entry */
196 Entry
= (PHDA_CODEC_ENTRY
)AllocateItem(NonPagedPool
, sizeof(HDA_CODEC_ENTRY
));
199 DPRINT1("hda: failed to allocate memory");
200 return STATUS_UNSUCCESSFUL
;
204 Entry
->Addr
= codecAddress
;
206 /* get device extension */
207 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
210 DeviceExtension
->Codecs
[codecAddress
] = Entry
;
212 verbs
[0] = MAKE_VERB(codecAddress
, 0, VID_GET_PARAMETER
, PID_VENDOR_ID
);
213 verbs
[1] = MAKE_VERB(codecAddress
, 0, VID_GET_PARAMETER
, PID_REVISION_ID
);
214 verbs
[2] = MAKE_VERB(codecAddress
, 0, VID_GET_PARAMETER
, PID_SUB_NODE_COUNT
);
217 HDA_SendVerbs(DeviceObject
, Entry
, verbs
, (PULONG
)&Response
, 3);
219 /* store codec details */
220 Entry
->Major
= Response
.major
;
221 Entry
->Minor
= Response
.minor
;
222 Entry
->ProductId
= Response
.device
;
223 Entry
->Revision
= Response
.revision
;
224 Entry
->Stepping
= Response
.stepping
;
225 Entry
->VendorId
= Response
.vendor
;
227 DPRINT1("hda Codec %ld Vendor: %04lx Product: %04lx, Revision: %lu.%lu.%lu.%lu NodeStart %u NodeCount %u \n", codecAddress
, Response
.vendor
,
228 Response
.device
, Response
.major
, Response
.minor
, Response
.revision
, Response
.stepping
, Response
.start
, Response
.count
);
230 for (NodeId
= Response
.start
; NodeId
< Response
.start
+ Response
.count
; NodeId
++) {
232 /* get function type */
233 verbs
[0] = MAKE_VERB(codecAddress
, NodeId
, VID_GET_PARAMETER
, PID_FUNCTION_GROUP_TYPE
);
235 HDA_SendVerbs(DeviceObject
, Entry
, verbs
, &GroupType
, 1);
236 DPRINT1("NodeId %u GroupType %x\n", NodeId
, GroupType
);
238 if ((GroupType
& FUNCTION_GROUP_NODETYPE_MASK
) == FUNCTION_GROUP_NODETYPE_AUDIO
) {
240 AudioGroup
= (PHDA_CODEC_AUDIO_GROUP
)AllocateItem(NonPagedPool
, sizeof(HDA_CODEC_AUDIO_GROUP
));
243 DPRINT1("hda: insufficient memory\n");
244 return STATUS_INSUFFICIENT_RESOURCES
;
247 /* init audio group */
248 AudioGroup
->NodeId
= NodeId
;
249 AudioGroup
->FunctionGroup
= FUNCTION_GROUP_NODETYPE_AUDIO
;
251 // Found an Audio Function Group!
252 DPRINT1("NodeId %x found an audio function group!\n");
254 Status
= IoCreateDevice(DeviceObject
->DriverObject
, sizeof(HDA_PDO_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_SOUND
, 0, FALSE
, &AudioGroup
->ChildPDO
);
255 if (!NT_SUCCESS(Status
))
257 FreeItem(AudioGroup
);
258 DPRINT1("hda failed to create device object %x\n", Status
);
263 ChildDeviceExtension
= (PHDA_PDO_DEVICE_EXTENSION
)AudioGroup
->ChildPDO
->DeviceExtension
;
264 ChildDeviceExtension
->IsFDO
= FALSE
;
265 ChildDeviceExtension
->Codec
= Entry
;
266 ChildDeviceExtension
->AudioGroup
= AudioGroup
;
269 AudioGroup
->ChildPDO
->Flags
|= DO_POWER_PAGABLE
;
270 AudioGroup
->ChildPDO
->Flags
&= ~DO_DEVICE_INITIALIZING
;
273 Entry
->AudioGroups
[Entry
->AudioGroupCount
] = AudioGroup
;
274 Entry
->AudioGroupCount
++;
277 return STATUS_SUCCESS
;
284 IN PDEVICE_OBJECT DeviceObject
)
286 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
287 UCHAR corbSize
, value
, rirbSize
;
288 PHYSICAL_ADDRESS HighestPhysicalAddress
, CorbPhysicalAddress
;
290 USHORT corbReadPointer
, rirbWritePointer
, interruptValue
, corbControl
, rirbControl
;
292 /* get device extension */
293 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
295 // Determine and set size of CORB
296 corbSize
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
);
297 if ((corbSize
& CORB_SIZE_CAP_256_ENTRIES
) != 0) {
298 DeviceExtension
->CorbLength
= 256;
300 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
) & HDAC_CORB_SIZE_MASK
;
301 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
, value
| CORB_SIZE_256_ENTRIES
);
303 else if (corbSize
& CORB_SIZE_CAP_16_ENTRIES
) {
304 DeviceExtension
->CorbLength
= 16;
306 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
) & HDAC_CORB_SIZE_MASK
;
307 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
, value
| CORB_SIZE_16_ENTRIES
);
309 else if (corbSize
& CORB_SIZE_CAP_2_ENTRIES
) {
310 DeviceExtension
->CorbLength
= 2;
312 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
) & HDAC_CORB_SIZE_MASK
;
313 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_SIZE
, value
| CORB_SIZE_2_ENTRIES
);
316 // Determine and set size of RIRB
317 rirbSize
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
);
318 if (rirbSize
& RIRB_SIZE_CAP_256_ENTRIES
) {
319 DeviceExtension
->RirbLength
= 256;
321 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
) & HDAC_RIRB_SIZE_MASK
;
322 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
, value
| RIRB_SIZE_256_ENTRIES
);
324 else if (rirbSize
& RIRB_SIZE_CAP_16_ENTRIES
) {
325 DeviceExtension
->RirbLength
= 16;
327 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
) & HDAC_RIRB_SIZE_MASK
;
328 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
, value
| RIRB_SIZE_16_ENTRIES
);
330 else if (rirbSize
& RIRB_SIZE_CAP_2_ENTRIES
) {
331 DeviceExtension
->RirbLength
= 2;
333 value
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
) & HDAC_RIRB_SIZE_MASK
;
334 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_SIZE
, value
| RIRB_SIZE_2_ENTRIES
);
338 HighestPhysicalAddress
.QuadPart
= 0x00000000FFFFFFFF;
339 DeviceExtension
->CorbBase
= (PULONG
)MmAllocateContiguousMemory(PAGE_SIZE
* 3, HighestPhysicalAddress
);
341 // FIXME align rirb 128bytes
342 ASSERT(DeviceExtension
->CorbLength
== 256);
343 ASSERT(DeviceExtension
->RirbLength
== 256);
345 CorbPhysicalAddress
= MmGetPhysicalAddress(DeviceExtension
->CorbBase
);
347 // Program CORB/RIRB for these locations
348 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_CORB_BASE_LOWER
), CorbPhysicalAddress
.LowPart
);
349 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_CORB_BASE_UPPER
), CorbPhysicalAddress
.HighPart
);
351 DeviceExtension
->RirbBase
= (PRIRB_RESPONSE
)((ULONG_PTR
)DeviceExtension
->CorbBase
+ PAGE_SIZE
);
352 CorbPhysicalAddress
.QuadPart
+= PAGE_SIZE
;
353 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_RIRB_BASE_LOWER
), CorbPhysicalAddress
.LowPart
);
354 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_RIRB_BASE_UPPER
), CorbPhysicalAddress
.HighPart
);
356 // Program DMA position update
357 DeviceExtension
->StreamPositions
= (PVOID
)((ULONG_PTR
)DeviceExtension
->RirbBase
+ PAGE_SIZE
);
358 CorbPhysicalAddress
.QuadPart
+= PAGE_SIZE
;
359 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_LOWER
), CorbPhysicalAddress
.LowPart
);
360 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_UPPER
), CorbPhysicalAddress
.HighPart
);
362 value
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
)) & HDAC_CORB_WRITE_POS_MASK
;
363 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_WRITE_POS
), value
);
365 // Reset CORB read pointer. Preseve bits marked as RsvdP.
366 // After setting the reset bit, we must wait for the hardware
367 // to acknowledge it, then manually unset it and wait for that
368 // to be acknowledged as well.
369 corbReadPointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
371 corbReadPointer
|= CORB_READ_POS_RESET
;
372 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
), corbReadPointer
);
374 for (Index
= 0; Index
< 100; Index
++) {
375 KeStallExecutionProcessor(10);
376 corbReadPointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
377 if ((corbReadPointer
& CORB_READ_POS_RESET
) != 0)
380 if ((corbReadPointer
& CORB_READ_POS_RESET
) == 0) {
381 DPRINT1("hda: CORB read pointer reset not acknowledged\n");
383 // According to HDA spec v1.0a ch3.3.21, software must read the
384 // bit as 1 to verify that the reset completed. However, at least
385 // some nVidia HDA controllers do not update the bit after reset.
386 // Thus don't fail here on nVidia controllers.
387 //if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
391 corbReadPointer
&= ~CORB_READ_POS_RESET
;
392 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
), corbReadPointer
);
393 for (Index
= 0; Index
< 10; Index
++) {
394 KeStallExecutionProcessor(10);
395 corbReadPointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_READ_POS
));
396 if ((corbReadPointer
& CORB_READ_POS_RESET
) == 0)
399 if ((corbReadPointer
& CORB_READ_POS_RESET
) != 0) {
400 DPRINT1("hda: CORB read pointer reset failed\n");
401 return STATUS_UNSUCCESSFUL
;
404 // Reset RIRB write pointer
405 rirbWritePointer
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_WRITE_POS
)) & RIRB_WRITE_POS_RESET
;
406 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_WRITE_POS
), rirbWritePointer
| RIRB_WRITE_POS_RESET
);
408 // Generate interrupt for every response
409 interruptValue
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RESPONSE_INTR_COUNT
)) & HDAC_RESPONSE_INTR_COUNT_MASK
;
410 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RESPONSE_INTR_COUNT
), interruptValue
| 1);
412 // Setup cached read/write indices
413 DeviceExtension
->RirbReadPos
= 1;
414 DeviceExtension
->CorbWritePos
= 0;
416 // Gentlemen, start your engines...
417 corbControl
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
)) &HDAC_CORB_CONTROL_MASK
;
418 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
), corbControl
| CORB_CONTROL_RUN
| CORB_CONTROL_MEMORY_ERROR_INTR
);
420 rirbControl
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
)) & HDAC_RIRB_CONTROL_MASK
;
421 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
), rirbControl
| RIRB_CONTROL_DMA_ENABLE
| RIRB_CONTROL_OVERRUN_INTR
| RIRB_CONTROL_RESPONSE_INTR
);
423 return STATUS_SUCCESS
;
429 IN PDEVICE_OBJECT DeviceObject
)
431 USHORT ValCapabilities
;
433 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
434 ULONG InputStreams
, OutputStreams
, BiDirStreams
, Control
;
435 UCHAR corbControl
, rirbControl
;
437 /* get device extension */
438 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
441 ValCapabilities
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CAP
));
443 InputStreams
= GLOBAL_CAP_INPUT_STREAMS(ValCapabilities
);
444 OutputStreams
= GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities
);
445 BiDirStreams
= GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities
);
447 DPRINT1("NumInputStreams %u\n", InputStreams
);
448 DPRINT1("NumOutputStreams %u\n", OutputStreams
);
449 DPRINT1("NumBiDirStreams %u\n", BiDirStreams
);
451 /* stop all streams */
452 for (Index
= 0; Index
< InputStreams
; Index
++)
454 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_CONTROL0
+ HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(Index
), 0);
455 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_STATUS
+ HDAC_STREAM_BASE
+ HDAC_INPUT_STREAM_OFFSET(Index
), 0);
458 for (Index
= 0; Index
< OutputStreams
; Index
++) {
459 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_CONTROL0
+ HDAC_STREAM_BASE
+ HDAC_OUTPUT_STREAM_OFFSET(InputStreams
, Index
), 0);
460 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_STATUS
+ HDAC_STREAM_BASE
+ HDAC_OUTPUT_STREAM_OFFSET(InputStreams
, Index
), 0);
463 for (Index
= 0; Index
< BiDirStreams
; Index
++) {
464 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_CONTROL0
+ HDAC_STREAM_BASE
+ HDAC_BIDIR_STREAM_OFFSET(InputStreams
, OutputStreams
, Index
), 0);
465 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_STREAM_STATUS
+ HDAC_STREAM_BASE
+ HDAC_BIDIR_STREAM_OFFSET(InputStreams
, OutputStreams
, Index
), 0);
469 Control
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
) & HDAC_CORB_CONTROL_MASK
;
470 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
, Control
);
472 Control
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
) & HDAC_RIRB_CONTROL_MASK
;
473 WRITE_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
, Control
);
475 for (int timeout
= 0; timeout
< 10; timeout
++) {
476 KeStallExecutionProcessor(10);
478 corbControl
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_CORB_CONTROL
);
479 rirbControl
= READ_REGISTER_UCHAR(DeviceExtension
->RegBase
+ HDAC_RIRB_CONTROL
);
480 if (corbControl
== 0 && rirbControl
== 0)
483 if (corbControl
!= 0 || rirbControl
!= 0) {
484 DPRINT1("hda: unable to stop dma\n");
485 return STATUS_UNSUCCESSFUL
;
488 // reset DMA position buffer
489 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_LOWER
), 0);
490 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_DMA_POSITION_BASE_UPPER
), 0);
492 // Set reset bit - it must be asserted for at least 100us
493 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
494 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
), Control
& ~GLOBAL_CONTROL_RESET
);
496 for (int timeout
= 0; timeout
< 10; timeout
++) {
497 KeStallExecutionProcessor(10);
499 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
500 if ((Control
& GLOBAL_CONTROL_RESET
) == 0)
503 if ((Control
& GLOBAL_CONTROL_RESET
) != 0)
505 DPRINT1("hda: unable to reset controller\n");
506 return STATUS_UNSUCCESSFUL
;
510 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
511 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
), Control
| GLOBAL_CONTROL_RESET
);
513 for (int timeout
= 0; timeout
< 10; timeout
++) {
514 KeStallExecutionProcessor(10);
516 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
517 if ((Control
& GLOBAL_CONTROL_RESET
) != 0)
520 if ((Control
& GLOBAL_CONTROL_RESET
) == 0) {
521 DPRINT1("hda: unable to exit reset\n");
522 return STATUS_UNSUCCESSFUL
;
525 // Wait for codecs to finish their own reset (apparently needs more
526 // time than documented in the specs)
527 KeStallExecutionProcessor(100);
529 // Enable unsolicited responses
530 Control
= READ_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
));
531 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_GLOBAL_CONTROL
), Control
| GLOBAL_CONTROL_UNSOLICITED
);
533 return STATUS_SUCCESS
;
539 IN PDEVICE_OBJECT DeviceObject
,
542 PIO_STACK_LOCATION IoStack
;
543 WCHAR DeviceName
[200];
544 PHDA_PDO_DEVICE_EXTENSION DeviceExtension
;
548 /* get device extension */
549 DeviceExtension
= (PHDA_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
550 ASSERT(DeviceExtension
->IsFDO
== FALSE
);
552 /* get current irp stack location */
553 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
555 if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryInstanceID
)
560 swprintf(DeviceName
, L
"%08x", 1);
561 Length
= wcslen(DeviceName
) + 20;
563 /* allocate result buffer*/
564 Device
= (LPWSTR
)AllocateItem(PagedPool
, Length
* sizeof(WCHAR
));
566 return STATUS_INSUFFICIENT_RESOURCES
;
568 swprintf(Device
, L
"%08x", 1);
570 DPRINT1("ID: %S\n", Device
);
572 Irp
->IoStatus
.Information
= (ULONG_PTR
)Device
;
573 return STATUS_SUCCESS
;
575 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryDeviceID
||
576 IoStack
->Parameters
.QueryId
.IdType
== BusQueryHardwareIDs
)
580 swprintf(DeviceName
, L
"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X&SUBSYS_%08X", DeviceExtension
->AudioGroup
->FunctionGroup
, DeviceExtension
->Codec
->VendorId
, DeviceExtension
->Codec
->ProductId
, DeviceExtension
->Codec
->VendorId
<< 16 | DeviceExtension
->Codec
->ProductId
);
581 Length
= wcslen(DeviceName
) + 20;
583 /* allocate result buffer*/
584 Device
= (LPWSTR
)AllocateItem(PagedPool
, Length
* sizeof(WCHAR
));
586 return STATUS_INSUFFICIENT_RESOURCES
;
588 swprintf(Device
, L
"HDAUDIO\\FUNC_%02X&VEN_%04X&DEV_%04X&SUBSYS_%08X", DeviceExtension
->AudioGroup
->FunctionGroup
, DeviceExtension
->Codec
->VendorId
, DeviceExtension
->Codec
->ProductId
, DeviceExtension
->Codec
->VendorId
<< 16 | DeviceExtension
->Codec
->ProductId
);
590 DPRINT1("ID: %S\n", Device
);
592 Irp
->IoStatus
.Information
= (ULONG_PTR
)Device
;
593 return STATUS_SUCCESS
;
597 DPRINT1("QueryID Type %x not implemented\n", IoStack
->Parameters
.QueryId
.IdType
);
598 return Irp
->IoStatus
.Status
;
600 return STATUS_NOT_IMPLEMENTED
;
606 IN PDEVICE_OBJECT DeviceObject
,
609 PIO_STACK_LOCATION IoStack
;
610 NTSTATUS Status
= STATUS_SUCCESS
;
611 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
612 PCM_RESOURCE_LIST Resources
;
616 /* get current irp stack location */
617 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
619 /* get device extension */
620 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
621 ASSERT(DeviceExtension
->IsFDO
== TRUE
);
623 Resources
= IoStack
->Parameters
.StartDevice
.AllocatedResourcesTranslated
;
624 for (Index
= 0; Index
< Resources
->List
[0].PartialResourceList
.Count
; Index
++)
626 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
= &Resources
->List
[0].PartialResourceList
.PartialDescriptors
[Index
];
628 if (Descriptor
->Type
== CmResourceTypeMemory
)
630 DeviceExtension
->RegBase
= (PUCHAR
)MmMapIoSpace(Descriptor
->u
.Memory
.Start
, Descriptor
->u
.Memory
.Length
, MmNonCached
);
631 if (DeviceExtension
->RegBase
== NULL
)
633 DPRINT1("[HDAB] Failed to map registers\n");
634 Status
= STATUS_UNSUCCESSFUL
;
638 else if (Descriptor
->Type
== CmResourceTypeInterrupt
)
640 Status
= IoConnectInterrupt(&DeviceExtension
->Interrupt
,
641 HDA_InterruptService
,
642 (PVOID
)DeviceExtension
,
644 Descriptor
->u
.Interrupt
.Vector
,
645 Descriptor
->u
.Interrupt
.Level
,
646 Descriptor
->u
.Interrupt
.Level
,
647 (KINTERRUPT_MODE
)(Descriptor
->Flags
& CM_RESOURCE_INTERRUPT_LATCHED
),
648 (Descriptor
->ShareDisposition
!= CmResourceShareDeviceExclusive
),
649 Descriptor
->u
.Interrupt
.Affinity
,
651 if (!NT_SUCCESS(Status
))
653 DPRINT1("[HDAB] Failed to connect interrupt\n");
660 if (NT_SUCCESS(Status
))
662 // Get controller into valid state
663 Status
= HDA_ResetController(DeviceObject
);
664 if (!NT_SUCCESS(Status
)) return Status
;
666 // Setup CORB/RIRB/DMA POS
667 Status
= HDA_InitCorbRirbPos(DeviceObject
);
668 if (!NT_SUCCESS(Status
)) return Status
;
671 // Don't enable codec state change interrupts. We don't handle
672 // them, as we want to use the STATE_STATUS register to identify
673 // available codecs. We'd have to clear that register in the interrupt
674 // handler to 'ack' the codec change.
675 Value
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_WAKE_ENABLE
)) & HDAC_WAKE_ENABLE_MASK
;
676 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_WAKE_ENABLE
), Value
);
678 // Enable controller interrupts
679 WRITE_REGISTER_ULONG((PULONG
)(DeviceExtension
->RegBase
+ HDAC_INTR_CONTROL
), INTR_CONTROL_GLOBAL_ENABLE
| INTR_CONTROL_CONTROLLER_ENABLE
);
681 KeStallExecutionProcessor(100);
683 Value
= READ_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_STATE_STATUS
));
685 DPRINT1("hda: bad codec status\n");
686 return STATUS_UNSUCCESSFUL
;
688 WRITE_REGISTER_USHORT((PUSHORT
)(DeviceExtension
->RegBase
+ HDAC_STATE_STATUS
), Value
);
691 DPRINT1("Codecs %lx\n", Value
);
692 for (Index
= 0; Index
< HDA_MAX_CODECS
; Index
++) {
693 if ((Value
& (1 << Index
)) != 0) {
694 HDA_InitCodec(DeviceObject
, Index
);
704 HDA_QueryBusRelations(
705 IN PDEVICE_OBJECT DeviceObject
,
708 ULONG DeviceCount
, CodecIndex
, AFGIndex
;
709 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
710 PHDA_CODEC_ENTRY Codec
;
711 PDEVICE_RELATIONS DeviceRelations
;
713 /* get device extension */
714 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
715 ASSERT(DeviceExtension
->IsFDO
== TRUE
);
718 for (CodecIndex
= 0; CodecIndex
< HDA_MAX_CODECS
; CodecIndex
++)
720 if (DeviceExtension
->Codecs
[CodecIndex
] == NULL
)
723 Codec
= DeviceExtension
->Codecs
[CodecIndex
];
724 DeviceCount
+= Codec
->AudioGroupCount
;
727 if (DeviceCount
== 0)
728 return STATUS_UNSUCCESSFUL
;
730 DeviceRelations
= (PDEVICE_RELATIONS
)AllocateItem(NonPagedPool
, sizeof(DEVICE_RELATIONS
) + (DeviceCount
> 1 ? sizeof(PDEVICE_OBJECT
) * (DeviceCount
- 1) : 0));
731 if (!DeviceRelations
)
732 return STATUS_INSUFFICIENT_RESOURCES
;
735 for (CodecIndex
= 0; CodecIndex
< HDA_MAX_CODECS
; CodecIndex
++)
737 if (DeviceExtension
->Codecs
[CodecIndex
] == NULL
)
740 Codec
= DeviceExtension
->Codecs
[CodecIndex
];
741 for (AFGIndex
= 0; AFGIndex
< Codec
->AudioGroupCount
; AFGIndex
++)
743 DeviceRelations
->Objects
[DeviceRelations
->Count
] = Codec
->AudioGroups
[AFGIndex
]->ChildPDO
;
744 ObReferenceObject(Codec
->AudioGroups
[AFGIndex
]->ChildPDO
);
745 DeviceRelations
->Count
++;
749 /* FIXME handle existing device relations */
750 ASSERT(Irp
->IoStatus
.Information
== 0);
752 /* store device relations */
753 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
756 return STATUS_SUCCESS
;
760 HDA_QueryBusInformation(
763 PPNP_BUS_INFORMATION BusInformation
;
765 /* allocate bus information */
766 BusInformation
= (PPNP_BUS_INFORMATION
)AllocateItem(PagedPool
, sizeof(PNP_BUS_INFORMATION
));
771 return STATUS_INSUFFICIENT_RESOURCES
;
775 BusInformation
->BusNumber
= 0;
776 BusInformation
->LegacyBusType
= PCIBus
;
777 RtlMoveMemory(&BusInformation
->BusTypeGuid
, &GUID_HDAUDIO_BUS_INTERFACE
, sizeof(GUID
));
780 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInformation
;
783 return STATUS_SUCCESS
;
787 HDA_QueryBusDeviceCapabilities(
790 PDEVICE_CAPABILITIES Capabilities
;
791 PIO_STACK_LOCATION IoStack
;
793 /* get stack location */
794 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
796 /* get capabilities */
797 Capabilities
= IoStack
->Parameters
.DeviceCapabilities
.Capabilities
;
799 RtlZeroMemory(Capabilities
, sizeof(DEVICE_CAPABILITIES
));
801 /* setup capabilities */
802 Capabilities
->UniqueID
= TRUE
;
803 Capabilities
->SilentInstall
= TRUE
;
804 Capabilities
->SurpriseRemovalOK
= TRUE
;
805 Capabilities
->Address
= 0;
806 Capabilities
->UINumber
= 0;
807 Capabilities
->SystemWake
= PowerSystemWorking
; /* FIXME common device extension */
808 Capabilities
->DeviceWake
= PowerDeviceD0
;
811 return STATUS_SUCCESS
;
815 HDA_QueryBusDevicePnpState(
818 /* set device flags */
819 Irp
->IoStatus
.Information
= PNP_DEVICE_DONT_DISPLAY_IN_UI
| PNP_DEVICE_NOT_DISABLEABLE
;
822 return STATUS_SUCCESS
;
826 HDA_PdoHandleQueryDeviceText(
829 PIO_STACK_LOCATION IoStack
;
831 static WCHAR DeviceText
[] = L
"Audio Device on High Definition Audio Bus";
833 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
834 if (IoStack
->Parameters
.QueryDeviceText
.DeviceTextType
== DeviceTextDescription
)
836 DPRINT("HDA_PdoHandleQueryDeviceText DeviceTextDescription\n");
838 Buffer
= (LPWSTR
)AllocateItem(PagedPool
, sizeof(DeviceText
));
841 Irp
->IoStatus
.Information
= 0;
842 return STATUS_INSUFFICIENT_RESOURCES
;
845 wcscpy(Buffer
, DeviceText
);
847 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
848 return STATUS_SUCCESS
;
852 DPRINT("HDA_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
854 Buffer
= (LPWSTR
)AllocateItem(PagedPool
, sizeof(DeviceText
));
857 Irp
->IoStatus
.Information
= 0;
858 return STATUS_INSUFFICIENT_RESOURCES
;
861 wcscpy(Buffer
, DeviceText
);
864 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
865 return STATUS_SUCCESS
;
873 IN PDEVICE_OBJECT DeviceObject
,
876 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
877 PIO_STACK_LOCATION IoStack
;
878 PDEVICE_RELATIONS DeviceRelation
;
879 PHDA_FDO_DEVICE_EXTENSION FDODeviceExtension
;
880 //PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
882 FDODeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
883 //ChildDeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
885 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
886 DPRINT1("HDA_Pnp Minor: %u IsFDO%d\n", IoStack
->MinorFunction
, FDODeviceExtension
->IsFDO
);
888 if (FDODeviceExtension
->IsFDO
)
890 if (IoStack
->MinorFunction
== IRP_MN_START_DEVICE
)
892 DPRINT1("IRP_MN_START_DEVICE\n");
893 Status
= HDA_StartDevice(DeviceObject
, Irp
);
895 else if (IoStack
->MinorFunction
== IRP_MN_QUERY_DEVICE_RELATIONS
)
897 DPRINT1("IRP_MN_QUERY_DEVICE_RELATIONS\n");
898 /* handle bus device relations */
899 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
== BusRelations
)
901 Status
= HDA_QueryBusRelations(DeviceObject
, Irp
);
905 Status
= Irp
->IoStatus
.Status
;
910 /* get default status */
911 Status
= Irp
->IoStatus
.Status
;
916 if (IoStack
->MinorFunction
== IRP_MN_START_DEVICE
)
918 DPRINT1("IRP_MN_START_DEVICE\n");
920 Status
= STATUS_SUCCESS
;
922 else if (IoStack
->MinorFunction
== IRP_MN_QUERY_BUS_INFORMATION
)
924 DPRINT1("IRP_MN_QUERY_BUS_INFORMATION\n");
925 /* query bus information */
926 Status
= HDA_QueryBusInformation(Irp
);
928 else if (IoStack
->MinorFunction
== IRP_MN_QUERY_PNP_DEVICE_STATE
)
930 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE\n");
931 /* query pnp state */
932 Status
= HDA_QueryBusDevicePnpState(Irp
);
934 else if (IoStack
->MinorFunction
== IRP_MN_QUERY_DEVICE_RELATIONS
)
936 DPRINT1("IRP_MN_QUERY_DEVICE_RELATIONS\n");
937 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
== TargetDeviceRelation
)
939 /* handle target device relations */
940 ASSERT(IoStack
->Parameters
.QueryDeviceRelations
.Type
== TargetDeviceRelation
);
941 ASSERT(Irp
->IoStatus
.Information
== 0);
943 /* allocate device relation */
944 DeviceRelation
= (PDEVICE_RELATIONS
)AllocateItem(PagedPool
, sizeof(DEVICE_RELATIONS
));
947 DeviceRelation
->Count
= 1;
948 DeviceRelation
->Objects
[0] = DeviceObject
;
951 ObReferenceObject(DeviceObject
);
954 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelation
;
957 Status
= STATUS_SUCCESS
;
962 Status
= STATUS_INSUFFICIENT_RESOURCES
;
966 else if (IoStack
->MinorFunction
== IRP_MN_QUERY_CAPABILITIES
)
968 DPRINT1("IRP_MN_QUERY_CAPABILITIES\n");
969 /* query capabilities */
970 Status
= HDA_QueryBusDeviceCapabilities(Irp
);
972 else if (IoStack
->MinorFunction
== IRP_MN_QUERY_RESOURCE_REQUIREMENTS
)
974 DPRINT1("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
976 Status
= STATUS_SUCCESS
;
978 else if (IoStack
->MinorFunction
== IRP_MN_QUERY_ID
)
980 DPRINT1("IRP_MN_QUERY_ID\n");
981 Status
= HDA_QueryId(DeviceObject
, Irp
);
983 else if (IoStack
->MinorFunction
== IRP_MN_QUERY_DEVICE_TEXT
)
985 DPRINT1("IRP_MN_QUERY_DEVICE_TEXT\n");
986 Status
= HDA_PdoHandleQueryDeviceText(Irp
);
990 /* get default status */
991 Status
= Irp
->IoStatus
.Status
;
995 Irp
->IoStatus
.Status
= Status
;
996 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1003 //PDRIVER_ADD_DEVICE HDA_AddDevice;
1008 IN PDRIVER_OBJECT DriverObject
,
1009 IN PDEVICE_OBJECT PhysicalDeviceObject
)
1011 PDEVICE_OBJECT DeviceObject
;
1012 PHDA_FDO_DEVICE_EXTENSION DeviceExtension
;
1015 /* create device object */
1016 Status
= IoCreateDevice(DriverObject
, sizeof(HDA_FDO_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_BUS_EXTENDER
, 0, FALSE
, &DeviceObject
);
1017 if (!NT_SUCCESS(Status
))
1023 /* get device extension*/
1024 DeviceExtension
= (PHDA_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1026 /* init device extension*/
1027 DeviceExtension
->IsFDO
= TRUE
;
1028 DeviceExtension
->LowerDevice
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
1029 RtlZeroMemory(DeviceExtension
->Codecs
, sizeof(PHDA_CODEC_ENTRY
) * (HDA_MAX_CODECS
+ 1));
1032 /* set device flags */
1033 DeviceObject
->Flags
|= DO_POWER_PAGABLE
;
1042 IN PDRIVER_OBJECT DriverObject
,
1043 IN PUNICODE_STRING RegistryPathName
)
1045 DriverObject
->DriverExtension
->AddDevice
= HDA_AddDevice
;
1046 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = HDA_Pnp
;
1048 return STATUS_SUCCESS
;