[HDAUDBUS] Use IoForwardIrpSynchronously instead of HDA_SyncForwardIrp.
[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
226 AudioGroup = (PHDA_CODEC_AUDIO_GROUP)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_AUDIO_GROUP));
227 if (!AudioGroup)
228 {
229 DPRINT1("hda: insufficient memory\n");
230 return STATUS_INSUFFICIENT_RESOURCES;
231 }
232
233 /* init audio group */
234 AudioGroup->NodeId = NodeId;
235 AudioGroup->FunctionGroup = FUNCTION_GROUP_NODETYPE_AUDIO;
236
237 // Found an Audio Function Group!
238 DPRINT1("NodeId %x found an audio function group!\n");
239
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))
242 {
243 FreeItem(AudioGroup);
244 DPRINT1("hda failed to create device object %x\n", Status);
245 return Status;
246 }
247
248 /* init child pdo*/
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;
254
255 /* setup flags */
256 AudioGroup->ChildPDO->Flags |= DO_POWER_PAGABLE;
257 AudioGroup->ChildPDO->Flags &= ~DO_DEVICE_INITIALIZING;
258
259 /* add audio group*/
260 Entry->AudioGroups[Entry->AudioGroupCount] = AudioGroup;
261 Entry->AudioGroupCount++;
262 }
263 }
264 return STATUS_SUCCESS;
265
266 }
267
268 NTSTATUS
269 NTAPI
270 HDA_InitCorbRirbPos(
271 IN PDEVICE_OBJECT DeviceObject)
272 {
273 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
274 UCHAR corbSize, value, rirbSize;
275 PHYSICAL_ADDRESS HighestPhysicalAddress, CorbPhysicalAddress;
276 ULONG Index;
277 USHORT corbReadPointer, rirbWritePointer, interruptValue, corbControl, rirbControl;
278
279 /* get device extension */
280 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
281
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;
286
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);
289 }
290 else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
291 DeviceExtension->CorbLength = 16;
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_16_ENTRIES);
295 }
296 else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
297 DeviceExtension->CorbLength = 2;
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_2_ENTRIES);
301 }
302
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;
307
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);
310 }
311 else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
312 DeviceExtension->RirbLength = 16;
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_16_ENTRIES);
316 }
317 else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
318 DeviceExtension->RirbLength = 2;
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_2_ENTRIES);
322 }
323
324 /* init corb */
325 HighestPhysicalAddress.QuadPart = 0x00000000FFFFFFFF;
326 DeviceExtension->CorbBase = (PULONG)MmAllocateContiguousMemory(PAGE_SIZE * 3, HighestPhysicalAddress);
327 ASSERT(DeviceExtension->CorbBase != NULL);
328
329 // FIXME align rirb 128bytes
330 ASSERT(DeviceExtension->CorbLength == 256);
331 ASSERT(DeviceExtension->RirbLength == 256);
332
333 CorbPhysicalAddress = MmGetPhysicalAddress(DeviceExtension->CorbBase);
334 ASSERT(CorbPhysicalAddress.QuadPart != 0LL);
335
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);
339
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);
344
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);
350
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);
353
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));
359
360 corbReadPointer |= CORB_READ_POS_RESET;
361 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
362
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)
367 break;
368 }
369 if ((corbReadPointer & CORB_READ_POS_RESET) == 0) {
370 DPRINT1("hda: CORB read pointer reset not acknowledged\n");
371
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)
377 // return B_BUSY;
378 }
379
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)
386 break;
387 }
388 if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
389 DPRINT1("hda: CORB read pointer reset failed\n");
390 return STATUS_UNSUCCESSFUL;
391 }
392
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);
396
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);
400
401 // Setup cached read/write indices
402 DeviceExtension->RirbReadPos = 1;
403 DeviceExtension->CorbWritePos = 0;
404
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);
408
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);
411
412 return STATUS_SUCCESS;
413 }
414
415 NTSTATUS
416 NTAPI
417 HDA_ResetController(
418 IN PDEVICE_OBJECT DeviceObject)
419 {
420 USHORT ValCapabilities;
421 ULONG Index;
422 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
423 ULONG InputStreams, OutputStreams, BiDirStreams, Control;
424 UCHAR corbControl, rirbControl;
425
426 /* get device extension */
427 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
428
429 /* read caps */
430 ValCapabilities = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_GLOBAL_CAP));
431
432 InputStreams = GLOBAL_CAP_INPUT_STREAMS(ValCapabilities);
433 OutputStreams = GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities);
434 BiDirStreams = GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities);
435
436 DPRINT1("NumInputStreams %u\n", InputStreams);
437 DPRINT1("NumOutputStreams %u\n", OutputStreams);
438 DPRINT1("NumBiDirStreams %u\n", BiDirStreams);
439
440 /* stop all streams */
441 for (Index = 0; Index < InputStreams; Index++)
442 {
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);
445 }
446
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);
450 }
451
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);
455 }
456
457 // stop DMA
458 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL) & HDAC_CORB_CONTROL_MASK;
459 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL, Control);
460
461 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL) & HDAC_RIRB_CONTROL_MASK;
462 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL, Control);
463
464 for (int timeout = 0; timeout < 10; timeout++) {
465 KeStallExecutionProcessor(10);
466
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)
470 break;
471 }
472 if (corbControl != 0 || rirbControl != 0) {
473 DPRINT1("hda: unable to stop dma\n");
474 return STATUS_UNSUCCESSFUL;
475 }
476
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);
480
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);
484
485 for (int timeout = 0; timeout < 10; timeout++) {
486 KeStallExecutionProcessor(10);
487
488 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
489 if ((Control & GLOBAL_CONTROL_RESET) == 0)
490 break;
491 }
492 if ((Control & GLOBAL_CONTROL_RESET) != 0)
493 {
494 DPRINT1("hda: unable to reset controller\n");
495 return STATUS_UNSUCCESSFUL;
496 }
497
498 // Unset reset bit
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);
501
502 for (int timeout = 0; timeout < 10; timeout++) {
503 KeStallExecutionProcessor(10);
504
505 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
506 if ((Control & GLOBAL_CONTROL_RESET) != 0)
507 break;
508 }
509 if ((Control & GLOBAL_CONTROL_RESET) == 0) {
510 DPRINT1("hda: unable to exit reset\n");
511 return STATUS_UNSUCCESSFUL;
512 }
513
514 // Wait for codecs to finish their own reset (apparently needs more
515 // time than documented in the specs)
516 KeStallExecutionProcessor(100);
517
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);
521
522 return STATUS_SUCCESS;
523 }
524
525 NTSTATUS
526 NTAPI
527 HDA_FDOStartDevice(
528 IN PDEVICE_OBJECT DeviceObject,
529 IN PIRP Irp)
530 {
531 PIO_STACK_LOCATION IoStack;
532 NTSTATUS Status = STATUS_SUCCESS;
533 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
534 PCM_RESOURCE_LIST Resources;
535 ULONG Index;
536 USHORT Value;
537
538 /* get device extension */
539 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
540 ASSERT(DeviceExtension->IsFDO == TRUE);
541
542 /* forward irp to lower device */
543 if (!IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp))
544 {
545 ASSERT(FALSE);
546 return STATUS_INVALID_DEVICE_REQUEST;
547 }
548 Status = Irp->IoStatus.Status;
549 if (!NT_SUCCESS(Status))
550 {
551 // failed to start
552 DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status);
553 return Status;
554 }
555
556 /* get current irp stack location */
557 IoStack = IoGetCurrentIrpStackLocation(Irp);
558
559 Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
560 for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
561 {
562 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
563
564 if (Descriptor->Type == CmResourceTypeMemory)
565 {
566 DeviceExtension->RegBase = (PUCHAR)MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached);
567 if (DeviceExtension->RegBase == NULL)
568 {
569 DPRINT1("[HDAB] Failed to map registers\n");
570 Status = STATUS_UNSUCCESSFUL;
571 break;
572 }
573 }
574 else if (Descriptor->Type == CmResourceTypeInterrupt)
575 {
576 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
577 HDA_InterruptService,
578 (PVOID)DeviceExtension,
579 NULL,
580 Descriptor->u.Interrupt.Vector,
581 Descriptor->u.Interrupt.Level,
582 Descriptor->u.Interrupt.Level,
583 (KINTERRUPT_MODE)(Descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED),
584 (Descriptor->ShareDisposition != CmResourceShareDeviceExclusive),
585 Descriptor->u.Interrupt.Affinity,
586 FALSE);
587 if (!NT_SUCCESS(Status))
588 {
589 DPRINT1("[HDAB] Failed to connect interrupt. Status=%lx\n", Status);
590 break;
591 }
592
593 }
594 }
595
596 if (NT_SUCCESS(Status))
597 {
598 // Get controller into valid state
599 Status = HDA_ResetController(DeviceObject);
600 if (!NT_SUCCESS(Status)) return Status;
601
602 // Setup CORB/RIRB/DMA POS
603 Status = HDA_InitCorbRirbPos(DeviceObject);
604 if (!NT_SUCCESS(Status)) return Status;
605
606
607 // Don't enable codec state change interrupts. We don't handle
608 // them, as we want to use the STATE_STATUS register to identify
609 // available codecs. We'd have to clear that register in the interrupt
610 // handler to 'ack' the codec change.
611 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE)) & ~HDAC_WAKE_ENABLE_MASK;
612 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE), Value);
613
614 // Enable controller interrupts
615 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_CONTROL), INTR_CONTROL_GLOBAL_ENABLE | INTR_CONTROL_CONTROLLER_ENABLE);
616
617 KeStallExecutionProcessor(100);
618
619 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS));
620 if (!Value) {
621 DPRINT1("hda: bad codec status\n");
622 return STATUS_UNSUCCESSFUL;
623 }
624 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS), Value);
625
626 // Create codecs
627 DPRINT1("Codecs %lx\n", Value);
628 for (Index = 0; Index < HDA_MAX_CODECS; Index++) {
629 if ((Value & (1 << Index)) != 0) {
630 HDA_InitCodec(DeviceObject, Index);
631 }
632 }
633 }
634
635 return Status;
636 }
637
638 NTSTATUS
639 NTAPI
640 HDA_FDOQueryBusRelations(
641 IN PDEVICE_OBJECT DeviceObject,
642 IN PIRP Irp)
643 {
644 ULONG DeviceCount, CodecIndex, AFGIndex;
645 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
646 PHDA_CODEC_ENTRY Codec;
647 PDEVICE_RELATIONS DeviceRelations;
648
649 /* get device extension */
650 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
651 ASSERT(DeviceExtension->IsFDO == TRUE);
652
653 DeviceCount = 0;
654 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
655 {
656 if (DeviceExtension->Codecs[CodecIndex] == NULL)
657 continue;
658
659 Codec = DeviceExtension->Codecs[CodecIndex];
660 DeviceCount += Codec->AudioGroupCount;
661 }
662
663 if (DeviceCount == 0)
664 return STATUS_UNSUCCESSFUL;
665
666 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? sizeof(PDEVICE_OBJECT) * (DeviceCount - 1) : 0));
667 if (!DeviceRelations)
668 return STATUS_INSUFFICIENT_RESOURCES;
669
670 DeviceRelations->Count = 0;
671 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
672 {
673 if (DeviceExtension->Codecs[CodecIndex] == NULL)
674 continue;
675
676 Codec = DeviceExtension->Codecs[CodecIndex];
677 for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
678 {
679 DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
680 ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
681 DeviceRelations->Count++;
682 }
683 }
684
685 /* FIXME handle existing device relations */
686 ASSERT(Irp->IoStatus.Information == 0);
687
688 /* store device relations */
689 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
690
691 /* done */
692 return STATUS_SUCCESS;
693 }
694
695