[HDAUDBUS]
[reactos.git] / reactos / 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 Status = HDA_SyncForwardIrp(DeviceExtension->LowerDevice, Irp);
544 if (!NT_SUCCESS(Status))
545 {
546 // failed to start
547 DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status);
548 return Status;
549 }
550
551 /* get current irp stack location */
552 IoStack = IoGetCurrentIrpStackLocation(Irp);
553
554 Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
555 for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
556 {
557 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
558
559 if (Descriptor->Type == CmResourceTypeMemory)
560 {
561 DeviceExtension->RegBase = (PUCHAR)MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached);
562 if (DeviceExtension->RegBase == NULL)
563 {
564 DPRINT1("[HDAB] Failed to map registers\n");
565 Status = STATUS_UNSUCCESSFUL;
566 break;
567 }
568 }
569 else if (Descriptor->Type == CmResourceTypeInterrupt)
570 {
571 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
572 HDA_InterruptService,
573 (PVOID)DeviceExtension,
574 NULL,
575 Descriptor->u.Interrupt.Vector,
576 Descriptor->u.Interrupt.Level,
577 Descriptor->u.Interrupt.Level,
578 (KINTERRUPT_MODE)(Descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED),
579 (Descriptor->ShareDisposition != CmResourceShareDeviceExclusive),
580 Descriptor->u.Interrupt.Affinity,
581 FALSE);
582 if (!NT_SUCCESS(Status))
583 {
584 DPRINT1("[HDAB] Failed to connect interrupt\n");
585 break;
586 }
587
588 }
589 }
590
591 if (NT_SUCCESS(Status))
592 {
593 // Get controller into valid state
594 Status = HDA_ResetController(DeviceObject);
595 if (!NT_SUCCESS(Status)) return Status;
596
597 // Setup CORB/RIRB/DMA POS
598 Status = HDA_InitCorbRirbPos(DeviceObject);
599 if (!NT_SUCCESS(Status)) return Status;
600
601
602 // Don't enable codec state change interrupts. We don't handle
603 // them, as we want to use the STATE_STATUS register to identify
604 // available codecs. We'd have to clear that register in the interrupt
605 // handler to 'ack' the codec change.
606 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE)) & ~HDAC_WAKE_ENABLE_MASK;
607 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE), Value);
608
609 // Enable controller interrupts
610 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_CONTROL), INTR_CONTROL_GLOBAL_ENABLE | INTR_CONTROL_CONTROLLER_ENABLE);
611
612 KeStallExecutionProcessor(100);
613
614 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS));
615 if (!Value) {
616 DPRINT1("hda: bad codec status\n");
617 return STATUS_UNSUCCESSFUL;
618 }
619 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS), Value);
620
621 // Create codecs
622 DPRINT1("Codecs %lx\n", Value);
623 for (Index = 0; Index < HDA_MAX_CODECS; Index++) {
624 if ((Value & (1 << Index)) != 0) {
625 HDA_InitCodec(DeviceObject, Index);
626 }
627 }
628 }
629
630 return Status;
631 }
632
633 NTSTATUS
634 NTAPI
635 HDA_FDOQueryBusRelations(
636 IN PDEVICE_OBJECT DeviceObject,
637 IN PIRP Irp)
638 {
639 ULONG DeviceCount, CodecIndex, AFGIndex;
640 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
641 PHDA_CODEC_ENTRY Codec;
642 PDEVICE_RELATIONS DeviceRelations;
643
644 /* get device extension */
645 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
646 ASSERT(DeviceExtension->IsFDO == TRUE);
647
648 DeviceCount = 0;
649 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
650 {
651 if (DeviceExtension->Codecs[CodecIndex] == NULL)
652 continue;
653
654 Codec = DeviceExtension->Codecs[CodecIndex];
655 DeviceCount += Codec->AudioGroupCount;
656 }
657
658 if (DeviceCount == 0)
659 return STATUS_UNSUCCESSFUL;
660
661 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? sizeof(PDEVICE_OBJECT) * (DeviceCount - 1) : 0));
662 if (!DeviceRelations)
663 return STATUS_INSUFFICIENT_RESOURCES;
664
665 DeviceRelations->Count = 0;
666 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
667 {
668 if (DeviceExtension->Codecs[CodecIndex] == NULL)
669 continue;
670
671 Codec = DeviceExtension->Codecs[CodecIndex];
672 for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
673 {
674 DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
675 ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
676 DeviceRelations->Count++;
677 }
678 }
679
680 /* FIXME handle existing device relations */
681 ASSERT(Irp->IoStatus.Information == 0);
682
683 /* store device relations */
684 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
685
686 /* done */
687 return STATUS_SUCCESS;
688 }
689
690