[HDAUDBUS] Fix a DPRINT.
[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 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
17 ULONG InterruptStatus, Response, ResponseFlags, Cad;
18 UCHAR RirbStatus, CorbStatus;
19 USHORT WritePos;
20 PHDA_CODEC_ENTRY Codec;
21
22 /* get device extension */
23 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)ServiceContext;
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 WritePos = (READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) + 1) % DeviceExtension->RirbLength;
50
51 for (; DeviceExtension->RirbReadPos != WritePos; DeviceExtension->RirbReadPos = (DeviceExtension->RirbReadPos + 1) % DeviceExtension->RirbLength)
52 {
53
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);
58
59 /* get codec */
60 Codec = DeviceExtension->Codecs[Cad];
61 if (Codec == NULL)
62 {
63 DPRINT1("hda: response for unknown codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
64 continue;
65 }
66
67 /* check response count */
68 if (Codec->ResponseCount >= MAX_CODEC_RESPONSES)
69 {
70 DPRINT1("too many responses for codec %x Response %x ResponseFlags %x\n", Cad, Response, ResponseFlags);
71 continue;
72 }
73
74 // FIXME handle unsolicited responses
75 ASSERT((ResponseFlags & RESPONSE_FLAGS_UNSOLICITED) == 0);
76
77 /* store response */
78 Codec->Responses[Codec->ResponseCount] = Response;
79 Codec->ResponseCount++;
80 }
81 }
82
83 if ((RirbStatus & RIRB_STATUS_OVERRUN) != 0)
84 DPRINT1("hda: RIRB Overflow\n");
85 }
86
87 // Check for sending errors
88 if (CorbStatus) {
89 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_STATUS, CorbStatus);
90
91 if ((CorbStatus & CORB_STATUS_MEMORY_ERROR) != 0)
92 DPRINT1("hda: CORB Memory Error!\n");
93 }
94 }
95 #if 0
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;
103 }
104 }
105 else {
106 dprintf("hda: Stream interrupt for unconfigured stream "
107 "%ld!\n", index);
108 }
109 }
110 }
111 }
112 #endif
113 return TRUE;
114 }
115
116
117 VOID
118 HDA_SendVerbs(
119 IN PDEVICE_OBJECT DeviceObject,
120 IN PHDA_CODEC_ENTRY Codec,
121 IN PULONG Verbs,
122 OUT PULONG Responses,
123 IN ULONG Count)
124 {
125 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
126 ULONG Sent = 0, ReadPosition, WritePosition, Queued;
127
128 /* get device extension */
129 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
130 ASSERT(DeviceExtension->IsFDO);
131
132 /* reset response count */
133 Codec->ResponseCount = 0;
134
135 while (Sent < Count) {
136 ReadPosition = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
137
138 Queued = 0;
139
140 while (Sent < Count) {
141 WritePosition = (DeviceExtension->CorbWritePos + 1) % DeviceExtension->CorbLength;
142
143 if (WritePosition == ReadPosition) {
144 // There is no space left in the ring buffer; execute the
145 // queued commands and wait until
146 break;
147 }
148
149 DeviceExtension->CorbBase[WritePosition] = Verbs[Sent++];
150 DeviceExtension->CorbWritePos = WritePosition;
151
152 // FIXME HACK
153 // do proper synchronization
154 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
155 KeStallExecutionProcessor(30);
156 Queued++;
157 }
158
159 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
160 }
161
162 if (Responses != NULL) {
163 memcpy(Responses, Codec->Responses, Codec->ResponseCount * sizeof(ULONG));
164 }
165 }
166
167 NTSTATUS
168 HDA_InitCodec(
169 IN PDEVICE_OBJECT DeviceObject,
170 IN ULONG codecAddress)
171 {
172 PHDA_CODEC_ENTRY Entry;
173 ULONG verbs[3];
174 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
175 CODEC_RESPONSE Response;
176 ULONG NodeId, GroupType;
177 NTSTATUS Status;
178 PHDA_CODEC_AUDIO_GROUP AudioGroup;
179 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
180
181 /* lets allocate the entry */
182 Entry = (PHDA_CODEC_ENTRY)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_ENTRY));
183 if (!Entry)
184 {
185 DPRINT1("hda: failed to allocate memory");
186 return STATUS_UNSUCCESSFUL;
187 }
188
189 /* init codec */
190 Entry->Addr = codecAddress;
191
192 /* get device extension */
193 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
194
195 /* store codec */
196 DeviceExtension->Codecs[codecAddress] = Entry;
197
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);
201
202 /* get basic info */
203 HDA_SendVerbs(DeviceObject, Entry, verbs, (PULONG)&Response, 3);
204
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;
212
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);
215
216 for (NodeId = Response.start; NodeId < Response.start + Response.count; NodeId++) {
217
218 /* get function type */
219 verbs[0] = MAKE_VERB(codecAddress, NodeId, VID_GET_PARAMETER, PID_FUNCTION_GROUP_TYPE);
220
221 HDA_SendVerbs(DeviceObject, Entry, verbs, &GroupType, 1);
222 DPRINT1("NodeId %u GroupType %x\n", NodeId, GroupType);
223
224 if ((GroupType & FUNCTION_GROUP_NODETYPE_MASK) == FUNCTION_GROUP_NODETYPE_AUDIO) {
225 if (Entry->AudioGroupCount >= HDA_MAX_AUDIO_GROUPS)
226 {
227 DPRINT1("Too many audio groups in node %u. Skipping.\n", NodeId);
228 break;
229 }
230
231 AudioGroup = (PHDA_CODEC_AUDIO_GROUP)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_AUDIO_GROUP));
232 if (!AudioGroup)
233 {
234 DPRINT1("hda: insufficient memory\n");
235 return STATUS_INSUFFICIENT_RESOURCES;
236 }
237
238 /* init audio group */
239 AudioGroup->NodeId = NodeId;
240 AudioGroup->FunctionGroup = FUNCTION_GROUP_NODETYPE_AUDIO;
241
242 // Found an Audio Function Group!
243 DPRINT1("NodeId %x found an audio function group!\n", NodeId);
244
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))
247 {
248 FreeItem(AudioGroup);
249 DPRINT1("hda failed to create device object %x\n", Status);
250 return Status;
251 }
252
253 /* init child pdo*/
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;
260
261 /* setup flags */
262 AudioGroup->ChildPDO->Flags |= DO_POWER_PAGABLE;
263 AudioGroup->ChildPDO->Flags &= ~DO_DEVICE_INITIALIZING;
264
265 /* add audio group*/
266 Entry->AudioGroups[Entry->AudioGroupCount] = AudioGroup;
267 Entry->AudioGroupCount++;
268 }
269 }
270 return STATUS_SUCCESS;
271
272 }
273
274 NTSTATUS
275 NTAPI
276 HDA_InitCorbRirbPos(
277 IN PDEVICE_OBJECT DeviceObject)
278 {
279 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
280 UCHAR corbSize, value, rirbSize;
281 PHYSICAL_ADDRESS HighestPhysicalAddress, CorbPhysicalAddress;
282 ULONG Index;
283 USHORT corbReadPointer, rirbWritePointer, interruptValue, corbControl, rirbControl;
284
285 /* get device extension */
286 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
287
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;
292
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);
295 }
296 else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
297 DeviceExtension->CorbLength = 16;
298
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);
301 }
302 else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
303 DeviceExtension->CorbLength = 2;
304
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);
307 }
308
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;
313
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);
316 }
317 else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
318 DeviceExtension->RirbLength = 16;
319
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);
322 }
323 else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
324 DeviceExtension->RirbLength = 2;
325
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);
328 }
329
330 /* init corb */
331 HighestPhysicalAddress.QuadPart = 0x00000000FFFFFFFF;
332 DeviceExtension->CorbBase = (PULONG)MmAllocateContiguousMemory(PAGE_SIZE * 3, HighestPhysicalAddress);
333 ASSERT(DeviceExtension->CorbBase != NULL);
334
335 // FIXME align rirb 128bytes
336 ASSERT(DeviceExtension->CorbLength == 256);
337 ASSERT(DeviceExtension->RirbLength == 256);
338
339 CorbPhysicalAddress = MmGetPhysicalAddress(DeviceExtension->CorbBase);
340 ASSERT(CorbPhysicalAddress.QuadPart != 0LL);
341
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);
345
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);
350
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);
356
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);
359
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));
365
366 corbReadPointer |= CORB_READ_POS_RESET;
367 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
368
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)
373 break;
374 }
375 if ((corbReadPointer & CORB_READ_POS_RESET) == 0) {
376 DPRINT1("hda: CORB read pointer reset not acknowledged\n");
377
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)
383 // return B_BUSY;
384 }
385
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)
392 break;
393 }
394 if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
395 DPRINT1("hda: CORB read pointer reset failed\n");
396 return STATUS_UNSUCCESSFUL;
397 }
398
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);
402
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);
406
407 // Setup cached read/write indices
408 DeviceExtension->RirbReadPos = 1;
409 DeviceExtension->CorbWritePos = 0;
410
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);
414
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);
417
418 return STATUS_SUCCESS;
419 }
420
421 NTSTATUS
422 NTAPI
423 HDA_ResetController(
424 IN PDEVICE_OBJECT DeviceObject)
425 {
426 USHORT ValCapabilities;
427 ULONG Index;
428 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
429 ULONG InputStreams, OutputStreams, BiDirStreams, Control;
430 UCHAR corbControl, rirbControl;
431
432 /* get device extension */
433 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
434
435 /* read caps */
436 ValCapabilities = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_GLOBAL_CAP));
437
438 InputStreams = GLOBAL_CAP_INPUT_STREAMS(ValCapabilities);
439 OutputStreams = GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities);
440 BiDirStreams = GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities);
441
442 DPRINT1("NumInputStreams %u\n", InputStreams);
443 DPRINT1("NumOutputStreams %u\n", OutputStreams);
444 DPRINT1("NumBiDirStreams %u\n", BiDirStreams);
445
446 /* stop all streams */
447 for (Index = 0; Index < InputStreams; Index++)
448 {
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);
451 }
452
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);
456 }
457
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);
461 }
462
463 // stop DMA
464 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL) & ~HDAC_CORB_CONTROL_MASK;
465 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL, Control);
466
467 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL) & ~HDAC_RIRB_CONTROL_MASK;
468 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL, Control);
469
470 for (int timeout = 0; timeout < 10; timeout++) {
471 KeStallExecutionProcessor(10);
472
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)
476 break;
477 }
478 if (corbControl != 0 || rirbControl != 0) {
479 DPRINT1("hda: unable to stop dma\n");
480 return STATUS_UNSUCCESSFUL;
481 }
482
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);
486
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);
490
491 for (int timeout = 0; timeout < 10; timeout++) {
492 KeStallExecutionProcessor(10);
493
494 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
495 if ((Control & GLOBAL_CONTROL_RESET) == 0)
496 break;
497 }
498 if ((Control & GLOBAL_CONTROL_RESET) != 0)
499 {
500 DPRINT1("hda: unable to reset controller\n");
501 return STATUS_UNSUCCESSFUL;
502 }
503
504 // Unset reset bit
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);
507
508 for (int timeout = 0; timeout < 10; timeout++) {
509 KeStallExecutionProcessor(10);
510
511 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
512 if ((Control & GLOBAL_CONTROL_RESET) != 0)
513 break;
514 }
515 if ((Control & GLOBAL_CONTROL_RESET) == 0) {
516 DPRINT1("hda: unable to exit reset\n");
517 return STATUS_UNSUCCESSFUL;
518 }
519
520 // Wait for codecs to finish their own reset (apparently needs more
521 // time than documented in the specs)
522 KeStallExecutionProcessor(100);
523
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);
527
528 return STATUS_SUCCESS;
529 }
530
531 NTSTATUS
532 NTAPI
533 HDA_FDOStartDevice(
534 IN PDEVICE_OBJECT DeviceObject,
535 IN PIRP Irp)
536 {
537 PIO_STACK_LOCATION IoStack;
538 NTSTATUS Status = STATUS_SUCCESS;
539 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
540 PCM_RESOURCE_LIST Resources;
541 ULONG Index;
542 USHORT Value;
543
544 /* get device extension */
545 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
546 ASSERT(DeviceExtension->IsFDO == TRUE);
547
548 /* forward irp to lower device */
549 if (!IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp))
550 {
551 ASSERT(FALSE);
552 return STATUS_INVALID_DEVICE_REQUEST;
553 }
554 Status = Irp->IoStatus.Status;
555 if (!NT_SUCCESS(Status))
556 {
557 // failed to start
558 DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status);
559 return Status;
560 }
561
562 /* get current irp stack location */
563 IoStack = IoGetCurrentIrpStackLocation(Irp);
564
565 Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
566 for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
567 {
568 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
569
570 if (Descriptor->Type == CmResourceTypeMemory)
571 {
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)
575 {
576 DPRINT1("[HDAB] Failed to map registers\n");
577 Status = STATUS_UNSUCCESSFUL;
578 break;
579 }
580 }
581 else if (Descriptor->Type == CmResourceTypeInterrupt)
582 {
583 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
584 HDA_InterruptService,
585 (PVOID)DeviceExtension,
586 NULL,
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,
593 FALSE);
594 if (!NT_SUCCESS(Status))
595 {
596 DPRINT1("[HDAB] Failed to connect interrupt. Status=%lx\n", Status);
597 break;
598 }
599
600 }
601 }
602
603 if (NT_SUCCESS(Status))
604 {
605 // Get controller into valid state
606 Status = HDA_ResetController(DeviceObject);
607 if (!NT_SUCCESS(Status)) return Status;
608
609 // Setup CORB/RIRB/DMA POS
610 Status = HDA_InitCorbRirbPos(DeviceObject);
611 if (!NT_SUCCESS(Status)) return Status;
612
613
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);
620
621 // Enable controller interrupts
622 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_CONTROL), INTR_CONTROL_GLOBAL_ENABLE | INTR_CONTROL_CONTROLLER_ENABLE);
623
624 KeStallExecutionProcessor(100);
625
626 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS));
627 if (!Value) {
628 DPRINT1("hda: bad codec status\n");
629 return STATUS_UNSUCCESSFUL;
630 }
631 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS), Value);
632
633 // Create codecs
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);
638 }
639 }
640 }
641
642 return Status;
643 }
644
645 NTSTATUS
646 NTAPI
647 HDA_FDORemoveDevice(
648 _In_ PDEVICE_OBJECT DeviceObject,
649 _Inout_ PIRP Irp)
650 {
651 NTSTATUS Status;
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;
657
658 /* get device extension */
659 DeviceExtension = static_cast<PHDA_FDO_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
660 ASSERT(DeviceExtension->IsFDO == TRUE);
661
662 Irp->IoStatus.Status = STATUS_SUCCESS;
663 IoSkipCurrentIrpStackLocation(Irp);
664 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
665
666 IoDetachDevice(DeviceExtension->LowerDevice);
667
668 if (DeviceExtension->RegBase != NULL)
669 {
670 MmUnmapIoSpace(DeviceExtension->RegBase,
671 DeviceExtension->RegLength);
672 }
673 if (DeviceExtension->Interrupt != NULL)
674 {
675 IoDisconnectInterrupt(DeviceExtension->Interrupt);
676 }
677 if (DeviceExtension->CorbBase != NULL)
678 {
679 MmFreeContiguousMemory(DeviceExtension->CorbBase);
680 }
681
682 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
683 {
684 CodecEntry = DeviceExtension->Codecs[CodecIndex];
685 if (CodecEntry == NULL)
686 {
687 continue;
688 }
689
690 ASSERT(CodecEntry->AudioGroupCount <= HDA_MAX_AUDIO_GROUPS);
691 for (AFGIndex = 0; AFGIndex < CodecEntry->AudioGroupCount; AFGIndex++)
692 {
693 ChildPDO = CodecEntry->AudioGroups[AFGIndex]->ChildPDO;
694 if (ChildPDO != NULL)
695 {
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);
702 }
703 FreeItem(CodecEntry->AudioGroups[AFGIndex]);
704 }
705 FreeItem(CodecEntry);
706 }
707
708 IoDeleteDevice(DeviceObject);
709
710 return Status;
711 }
712
713 NTSTATUS
714 NTAPI
715 HDA_FDOQueryBusRelations(
716 IN PDEVICE_OBJECT DeviceObject,
717 IN PIRP Irp)
718 {
719 ULONG DeviceCount, CodecIndex, AFGIndex;
720 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
721 PHDA_CODEC_ENTRY Codec;
722 PDEVICE_RELATIONS DeviceRelations;
723
724 /* get device extension */
725 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
726 ASSERT(DeviceExtension->IsFDO == TRUE);
727
728 DeviceCount = 0;
729 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
730 {
731 if (DeviceExtension->Codecs[CodecIndex] == NULL)
732 continue;
733
734 Codec = DeviceExtension->Codecs[CodecIndex];
735 DeviceCount += Codec->AudioGroupCount;
736 }
737
738 if (DeviceCount == 0)
739 return STATUS_UNSUCCESSFUL;
740
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;
744
745 DeviceRelations->Count = 0;
746 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
747 {
748 if (DeviceExtension->Codecs[CodecIndex] == NULL)
749 continue;
750
751 Codec = DeviceExtension->Codecs[CodecIndex];
752 ASSERT(Codec->AudioGroupCount <= HDA_MAX_AUDIO_GROUPS);
753 for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
754 {
755 DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
756 ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
757 DeviceRelations->Count++;
758 }
759 }
760
761 /* FIXME handle existing device relations */
762 ASSERT(Irp->IoStatus.Information == 0);
763
764 /* store device relations */
765 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
766
767 /* done */
768 return STATUS_SUCCESS;
769 }
770
771