[HDAUDBUS] Wait until the correct number of responses was received. CORE-15465
[reactos.git] / drivers / wdm / audio / hdaudbus / fdo.cpp
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
12 HDA_InterruptService(
13 IN PKINTERRUPT Interrupt,
14 IN PVOID ServiceContext)
15 {
16 PDEVICE_OBJECT DeviceObject;
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) {
49 IoRequestDpc(DeviceObject, NULL, NULL);
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
87 HDA_DpcForIsr(
88 _In_ PKDPC Dpc,
89 _In_opt_ PDEVICE_OBJECT DeviceObject,
90 _Inout_ PIRP Irp,
91 _In_opt_ PVOID Context)
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++;
132 KeReleaseSemaphore(&Codec->ResponseSemaphore, IO_NO_INCREMENT, 1, FALSE);
133 }
134 }
135
136
137 VOID
138 HDA_SendVerbs(
139 IN PDEVICE_OBJECT DeviceObject,
140 IN PHDA_CODEC_ENTRY Codec,
141 IN PULONG Verbs,
142 OUT PULONG Responses,
143 IN ULONG Count)
144 {
145 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
146 ULONG Sent = 0, ReadPosition, WritePosition, Queued;
147
148 /* get device extension */
149 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
150 ASSERT(DeviceExtension->IsFDO);
151
152 /* reset response count */
153 Codec->ResponseCount = 0;
154
155 while (Sent < Count) {
156 ReadPosition = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
157
158 Queued = 0;
159
160 while (Sent < Count) {
161 WritePosition = (DeviceExtension->CorbWritePos + 1) % DeviceExtension->CorbLength;
162
163 if (WritePosition == ReadPosition) {
164 // There is no space left in the ring buffer; execute the
165 // queued commands and wait until
166 break;
167 }
168
169 DeviceExtension->CorbBase[WritePosition] = Verbs[Sent++];
170 DeviceExtension->CorbWritePos = WritePosition;
171 Queued++;
172 }
173
174 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
175 }
176
177 while (Queued--)
178 {
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
192 HDA_InitCodec(
193 IN PDEVICE_OBJECT DeviceObject,
194 IN ULONG codecAddress)
195 {
196 PHDA_CODEC_ENTRY Entry;
197 ULONG verbs[3];
198 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
199 CODEC_RESPONSE Response;
200 ULONG NodeId, GroupType;
201 NTSTATUS Status;
202 PHDA_CODEC_AUDIO_GROUP AudioGroup;
203 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
204
205 /* lets allocate the entry */
206 Entry = (PHDA_CODEC_ENTRY)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_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 */
218 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
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 */
228 HDA_SendVerbs(DeviceObject, Entry, verbs, (PULONG)&Response, 3);
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
249 if ((GroupType & FUNCTION_GROUP_NODETYPE_MASK) == FUNCTION_GROUP_NODETYPE_AUDIO) {
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
256 AudioGroup = (PHDA_CODEC_AUDIO_GROUP)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_AUDIO_GROUP));
257 if (!AudioGroup)
258 {
259 DPRINT1("hda: insufficient memory\n");
260 return STATUS_INSUFFICIENT_RESOURCES;
261 }
262
263 /* init audio group */
264 AudioGroup->NodeId = NodeId;
265 AudioGroup->FunctionGroup = FUNCTION_GROUP_NODETYPE_AUDIO;
266
267 // Found an Audio Function Group!
268 DPRINT1("NodeId %x found an audio function group!\n", NodeId);
269
270 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(HDA_PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_SOUND, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &AudioGroup->ChildPDO);
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
301 HDA_InitCorbRirbPos(
302 IN PDEVICE_OBJECT DeviceObject)
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 */
311 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
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
318 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
319 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_256_ENTRIES);
320 }
321 else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
322 DeviceExtension->CorbLength = 16;
323
324 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
325 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_16_ENTRIES);
326 }
327 else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
328 DeviceExtension->CorbLength = 2;
329
330 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
331 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_2_ENTRIES);
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
339 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
340 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_256_ENTRIES);
341 }
342 else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
343 DeviceExtension->RirbLength = 16;
344
345 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
346 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_16_ENTRIES);
347 }
348 else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
349 DeviceExtension->RirbLength = 2;
350
351 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
352 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_2_ENTRIES);
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
382 value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS)) & ~HDAC_CORB_WRITE_POS_MASK;
383 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), value);
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++) {
395 KeStallExecutionProcessor(10);
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++) {
414 KeStallExecutionProcessor(10);
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
429 interruptValue = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT)) & ~HDAC_RESPONSE_INTR_COUNT_MASK;
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;
438 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL), corbControl | CORB_CONTROL_RUN | CORB_CONTROL_MEMORY_ERROR_INTR);
439
440 rirbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL)) & ~HDAC_RIRB_CONTROL_MASK;
441 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL), rirbControl | RIRB_CONTROL_DMA_ENABLE | RIRB_CONTROL_OVERRUN_INTR | RIRB_CONTROL_RESPONSE_INTR);
442
443 return STATUS_SUCCESS;
444 }
445
446 NTSTATUS
447 NTAPI
448 HDA_ResetController(
449 IN PDEVICE_OBJECT DeviceObject)
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 */
458 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
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 {
474 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
475 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
476 }
477
478 for (Index = 0; Index < OutputStreams; Index++) {
479 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
480 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
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
489 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL) & ~HDAC_CORB_CONTROL_MASK;
490 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL, Control);
491
492 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL) & ~HDAC_RIRB_CONTROL_MASK;
493 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL, Control);
494
495 for (int timeout = 0; timeout < 10; timeout++) {
496 KeStallExecutionProcessor(10);
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
509 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), 0);
510 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), 0);
511
512 // Set reset bit - it must be asserted for at least 100us
513 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
514 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control & ~GLOBAL_CONTROL_RESET);
515
516 for (int timeout = 0; timeout < 10; timeout++) {
517 KeStallExecutionProcessor(10);
518
519 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
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
530 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
531 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_RESET);
532
533 for (int timeout = 0; timeout < 10; timeout++) {
534 KeStallExecutionProcessor(10);
535
536 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
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)
547 KeStallExecutionProcessor(100);
548
549 // Enable unsolicited responses
550 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
551 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_UNSOLICITED);
552
553 return STATUS_SUCCESS;
554 }
555
556 NTSTATUS
557 NTAPI
558 HDA_FDOStartDevice(
559 IN PDEVICE_OBJECT DeviceObject,
560 IN PIRP Irp)
561 {
562 PIO_STACK_LOCATION IoStack;
563 NTSTATUS Status = STATUS_SUCCESS;
564 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
565 PCM_RESOURCE_LIST Resources;
566 ULONG Index;
567 USHORT Value;
568
569 /* get device extension */
570 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
571 ASSERT(DeviceExtension->IsFDO == TRUE);
572
573 /* forward irp to lower device */
574 if (!IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp))
575 {
576 ASSERT(FALSE);
577 return STATUS_INVALID_DEVICE_REQUEST;
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 */
588 IoStack = IoGetCurrentIrpStackLocation(Irp);
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");
602 Status = STATUS_UNSUCCESSFUL;
603 break;
604 }
605 }
606 else if (Descriptor->Type == CmResourceTypeInterrupt)
607 {
608 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
609 HDA_InterruptService,
610 DeviceObject,
611 NULL,
612 Descriptor->u.Interrupt.Vector,
613 Descriptor->u.Interrupt.Level,
614 Descriptor->u.Interrupt.Level,
615 (KINTERRUPT_MODE)(Descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED),
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
631 Status = HDA_ResetController(DeviceObject);
632 if (!NT_SUCCESS(Status)) return Status;
633
634 // Setup CORB/RIRB/DMA POS
635 Status = HDA_InitCorbRirbPos(DeviceObject);
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.
643 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE)) & ~HDAC_WAKE_ENABLE_MASK;
644 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE), Value);
645
646 // Enable controller interrupts
647 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_CONTROL), INTR_CONTROL_GLOBAL_ENABLE | INTR_CONTROL_CONTROLLER_ENABLE);
648
649 KeStallExecutionProcessor(100);
650
651 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS));
652 if (!Value) {
653 DPRINT1("hda: bad codec status\n");
654 return STATUS_UNSUCCESSFUL;
655 }
656 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS), Value);
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) {
662 HDA_InitCodec(DeviceObject, Index);
663 }
664 }
665 }
666
667 return Status;
668 }
669
670 NTSTATUS
671 NTAPI
672 HDA_FDORemoveDevice(
673 _In_ PDEVICE_OBJECT DeviceObject,
674 _Inout_ PIRP Irp)
675 {
676 NTSTATUS Status;
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;
688 IoSkipCurrentIrpStackLocation(Irp);
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
715 ASSERT(CodecEntry->AudioGroupCount <= HDA_MAX_AUDIO_GROUPS);
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
733 IoDeleteDevice(DeviceObject);
734
735 return Status;
736 }
737
738 NTSTATUS
739 NTAPI
740 HDA_FDOQueryBusRelations(
741 IN PDEVICE_OBJECT DeviceObject,
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 */
750 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
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)
768 return STATUS_INSUFFICIENT_RESOURCES;
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];
777 ASSERT(Codec->AudioGroupCount <= HDA_MAX_AUDIO_GROUPS);
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