a6d2ca8f11442bff0686155c35318f92c4cbc828
[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 }
133 }
134
135
136 VOID
137 HDA_SendVerbs(
138 IN PDEVICE_OBJECT DeviceObject,
139 IN PHDA_CODEC_ENTRY Codec,
140 IN PULONG Verbs,
141 OUT PULONG Responses,
142 IN ULONG Count)
143 {
144 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
145 ULONG Sent = 0, ReadPosition, WritePosition, Queued;
146
147 /* get device extension */
148 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
149 ASSERT(DeviceExtension->IsFDO);
150
151 /* reset response count */
152 Codec->ResponseCount = 0;
153
154 while (Sent < Count) {
155 ReadPosition = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
156
157 Queued = 0;
158
159 while (Sent < Count) {
160 WritePosition = (DeviceExtension->CorbWritePos + 1) % DeviceExtension->CorbLength;
161
162 if (WritePosition == ReadPosition) {
163 // There is no space left in the ring buffer; execute the
164 // queued commands and wait until
165 break;
166 }
167
168 DeviceExtension->CorbBase[WritePosition] = Verbs[Sent++];
169 DeviceExtension->CorbWritePos = WritePosition;
170
171 // FIXME HACK
172 // do proper synchronization
173 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
174 KeStallExecutionProcessor(30);
175 Queued++;
176 }
177
178 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), DeviceExtension->CorbWritePos);
179 }
180
181 if (Responses != NULL) {
182 memcpy(Responses, Codec->Responses, Codec->ResponseCount * sizeof(ULONG));
183 }
184 }
185
186 NTSTATUS
187 HDA_InitCodec(
188 IN PDEVICE_OBJECT DeviceObject,
189 IN ULONG codecAddress)
190 {
191 PHDA_CODEC_ENTRY Entry;
192 ULONG verbs[3];
193 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
194 CODEC_RESPONSE Response;
195 ULONG NodeId, GroupType;
196 NTSTATUS Status;
197 PHDA_CODEC_AUDIO_GROUP AudioGroup;
198 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
199
200 /* lets allocate the entry */
201 Entry = (PHDA_CODEC_ENTRY)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_ENTRY));
202 if (!Entry)
203 {
204 DPRINT1("hda: failed to allocate memory");
205 return STATUS_UNSUCCESSFUL;
206 }
207
208 /* init codec */
209 Entry->Addr = codecAddress;
210
211 /* get device extension */
212 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
213
214 /* store codec */
215 DeviceExtension->Codecs[codecAddress] = Entry;
216
217 verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
218 verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
219 verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUB_NODE_COUNT);
220
221 /* get basic info */
222 HDA_SendVerbs(DeviceObject, Entry, verbs, (PULONG)&Response, 3);
223
224 /* store codec details */
225 Entry->Major = Response.major;
226 Entry->Minor = Response.minor;
227 Entry->ProductId = Response.device;
228 Entry->Revision = Response.revision;
229 Entry->Stepping = Response.stepping;
230 Entry->VendorId = Response.vendor;
231
232 DPRINT1("hda Codec %ld Vendor: %04lx Product: %04lx, Revision: %lu.%lu.%lu.%lu NodeStart %u NodeCount %u \n", codecAddress, Response.vendor,
233 Response.device, Response.major, Response.minor, Response.revision, Response.stepping, Response.start, Response.count);
234
235 for (NodeId = Response.start; NodeId < Response.start + Response.count; NodeId++) {
236
237 /* get function type */
238 verbs[0] = MAKE_VERB(codecAddress, NodeId, VID_GET_PARAMETER, PID_FUNCTION_GROUP_TYPE);
239
240 HDA_SendVerbs(DeviceObject, Entry, verbs, &GroupType, 1);
241 DPRINT1("NodeId %u GroupType %x\n", NodeId, GroupType);
242
243 if ((GroupType & FUNCTION_GROUP_NODETYPE_MASK) == FUNCTION_GROUP_NODETYPE_AUDIO) {
244 if (Entry->AudioGroupCount >= HDA_MAX_AUDIO_GROUPS)
245 {
246 DPRINT1("Too many audio groups in node %u. Skipping.\n", NodeId);
247 break;
248 }
249
250 AudioGroup = (PHDA_CODEC_AUDIO_GROUP)AllocateItem(NonPagedPool, sizeof(HDA_CODEC_AUDIO_GROUP));
251 if (!AudioGroup)
252 {
253 DPRINT1("hda: insufficient memory\n");
254 return STATUS_INSUFFICIENT_RESOURCES;
255 }
256
257 /* init audio group */
258 AudioGroup->NodeId = NodeId;
259 AudioGroup->FunctionGroup = FUNCTION_GROUP_NODETYPE_AUDIO;
260
261 // Found an Audio Function Group!
262 DPRINT1("NodeId %x found an audio function group!\n", NodeId);
263
264 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(HDA_PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_SOUND, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &AudioGroup->ChildPDO);
265 if (!NT_SUCCESS(Status))
266 {
267 FreeItem(AudioGroup);
268 DPRINT1("hda failed to create device object %x\n", Status);
269 return Status;
270 }
271
272 /* init child pdo*/
273 ChildDeviceExtension = (PHDA_PDO_DEVICE_EXTENSION)AudioGroup->ChildPDO->DeviceExtension;
274 ChildDeviceExtension->IsFDO = FALSE;
275 ChildDeviceExtension->ReportedMissing = FALSE;
276 ChildDeviceExtension->Codec = Entry;
277 ChildDeviceExtension->AudioGroup = AudioGroup;
278 ChildDeviceExtension->FDO = DeviceObject;
279
280 /* setup flags */
281 AudioGroup->ChildPDO->Flags |= DO_POWER_PAGABLE;
282 AudioGroup->ChildPDO->Flags &= ~DO_DEVICE_INITIALIZING;
283
284 /* add audio group*/
285 Entry->AudioGroups[Entry->AudioGroupCount] = AudioGroup;
286 Entry->AudioGroupCount++;
287 }
288 }
289 return STATUS_SUCCESS;
290
291 }
292
293 NTSTATUS
294 NTAPI
295 HDA_InitCorbRirbPos(
296 IN PDEVICE_OBJECT DeviceObject)
297 {
298 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
299 UCHAR corbSize, value, rirbSize;
300 PHYSICAL_ADDRESS HighestPhysicalAddress, CorbPhysicalAddress;
301 ULONG Index;
302 USHORT corbReadPointer, rirbWritePointer, interruptValue, corbControl, rirbControl;
303
304 /* get device extension */
305 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
306
307 // Determine and set size of CORB
308 corbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE);
309 if ((corbSize & CORB_SIZE_CAP_256_ENTRIES) != 0) {
310 DeviceExtension->CorbLength = 256;
311
312 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE) & ~HDAC_CORB_SIZE_MASK;
313 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_SIZE, value | CORB_SIZE_256_ENTRIES);
314 }
315 else if (corbSize & CORB_SIZE_CAP_16_ENTRIES) {
316 DeviceExtension->CorbLength = 16;
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_16_ENTRIES);
320 }
321 else if (corbSize & CORB_SIZE_CAP_2_ENTRIES) {
322 DeviceExtension->CorbLength = 2;
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_2_ENTRIES);
326 }
327
328 // Determine and set size of RIRB
329 rirbSize = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE);
330 if (rirbSize & RIRB_SIZE_CAP_256_ENTRIES) {
331 DeviceExtension->RirbLength = 256;
332
333 value = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE) & ~HDAC_RIRB_SIZE_MASK;
334 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_SIZE, value | RIRB_SIZE_256_ENTRIES);
335 }
336 else if (rirbSize & RIRB_SIZE_CAP_16_ENTRIES) {
337 DeviceExtension->RirbLength = 16;
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_16_ENTRIES);
341 }
342 else if (rirbSize & RIRB_SIZE_CAP_2_ENTRIES) {
343 DeviceExtension->RirbLength = 2;
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_2_ENTRIES);
347 }
348
349 /* init corb */
350 HighestPhysicalAddress.QuadPart = 0x00000000FFFFFFFF;
351 DeviceExtension->CorbBase = (PULONG)MmAllocateContiguousMemory(PAGE_SIZE * 3, HighestPhysicalAddress);
352 ASSERT(DeviceExtension->CorbBase != NULL);
353
354 // FIXME align rirb 128bytes
355 ASSERT(DeviceExtension->CorbLength == 256);
356 ASSERT(DeviceExtension->RirbLength == 256);
357
358 CorbPhysicalAddress = MmGetPhysicalAddress(DeviceExtension->CorbBase);
359 ASSERT(CorbPhysicalAddress.QuadPart != 0LL);
360
361 // Program CORB/RIRB for these locations
362 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_LOWER), CorbPhysicalAddress.LowPart);
363 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_CORB_BASE_UPPER), CorbPhysicalAddress.HighPart);
364
365 DeviceExtension->RirbBase = (PRIRB_RESPONSE)((ULONG_PTR)DeviceExtension->CorbBase + PAGE_SIZE);
366 CorbPhysicalAddress.QuadPart += PAGE_SIZE;
367 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_LOWER), CorbPhysicalAddress.LowPart);
368 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_RIRB_BASE_UPPER), CorbPhysicalAddress.HighPart);
369
370 // Program DMA position update
371 DeviceExtension->StreamPositions = (PVOID)((ULONG_PTR)DeviceExtension->RirbBase + PAGE_SIZE);
372 CorbPhysicalAddress.QuadPart += PAGE_SIZE;
373 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), CorbPhysicalAddress.LowPart);
374 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), CorbPhysicalAddress.HighPart);
375
376 value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS)) & ~HDAC_CORB_WRITE_POS_MASK;
377 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_WRITE_POS), value);
378
379 // Reset CORB read pointer. Preserve bits marked as RsvdP.
380 // After setting the reset bit, we must wait for the hardware
381 // to acknowledge it, then manually unset it and wait for that
382 // to be acknowledged as well.
383 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
384
385 corbReadPointer |= CORB_READ_POS_RESET;
386 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
387
388 for (Index = 0; Index < 100; 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 not acknowledged\n");
396
397 // According to HDA spec v1.0a ch3.3.21, software must read the
398 // bit as 1 to verify that the reset completed. However, at least
399 // some nVidia HDA controllers do not update the bit after reset.
400 // Thus don't fail here on nVidia controllers.
401 //if (controller->pci_info.vendor_id != PCI_VENDOR_NVIDIA)
402 // return B_BUSY;
403 }
404
405 corbReadPointer &= ~CORB_READ_POS_RESET;
406 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS), corbReadPointer);
407 for (Index = 0; Index < 10; Index++) {
408 KeStallExecutionProcessor(10);
409 corbReadPointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_READ_POS));
410 if ((corbReadPointer & CORB_READ_POS_RESET) == 0)
411 break;
412 }
413 if ((corbReadPointer & CORB_READ_POS_RESET) != 0) {
414 DPRINT1("hda: CORB read pointer reset failed\n");
415 return STATUS_UNSUCCESSFUL;
416 }
417
418 // Reset RIRB write pointer
419 rirbWritePointer = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS)) & ~RIRB_WRITE_POS_RESET;
420 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_WRITE_POS), rirbWritePointer | RIRB_WRITE_POS_RESET);
421
422 // Generate interrupt for every response
423 interruptValue = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT)) & ~HDAC_RESPONSE_INTR_COUNT_MASK;
424 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RESPONSE_INTR_COUNT), interruptValue | 1);
425
426 // Setup cached read/write indices
427 DeviceExtension->RirbReadPos = 1;
428 DeviceExtension->CorbWritePos = 0;
429
430 // Gentlemen, start your engines...
431 corbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL)) & ~HDAC_CORB_CONTROL_MASK;
432 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_CORB_CONTROL), corbControl | CORB_CONTROL_RUN | CORB_CONTROL_MEMORY_ERROR_INTR);
433
434 rirbControl = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL)) & ~HDAC_RIRB_CONTROL_MASK;
435 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_RIRB_CONTROL), rirbControl | RIRB_CONTROL_DMA_ENABLE | RIRB_CONTROL_OVERRUN_INTR | RIRB_CONTROL_RESPONSE_INTR);
436
437 return STATUS_SUCCESS;
438 }
439
440 NTSTATUS
441 NTAPI
442 HDA_ResetController(
443 IN PDEVICE_OBJECT DeviceObject)
444 {
445 USHORT ValCapabilities;
446 ULONG Index;
447 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
448 ULONG InputStreams, OutputStreams, BiDirStreams, Control;
449 UCHAR corbControl, rirbControl;
450
451 /* get device extension */
452 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
453
454 /* read caps */
455 ValCapabilities = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_GLOBAL_CAP));
456
457 InputStreams = GLOBAL_CAP_INPUT_STREAMS(ValCapabilities);
458 OutputStreams = GLOBAL_CAP_OUTPUT_STREAMS(ValCapabilities);
459 BiDirStreams = GLOBAL_CAP_BIDIR_STREAMS(ValCapabilities);
460
461 DPRINT1("NumInputStreams %u\n", InputStreams);
462 DPRINT1("NumOutputStreams %u\n", OutputStreams);
463 DPRINT1("NumBiDirStreams %u\n", BiDirStreams);
464
465 /* stop all streams */
466 for (Index = 0; Index < InputStreams; Index++)
467 {
468 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
469 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_INPUT_STREAM_OFFSET(Index), 0);
470 }
471
472 for (Index = 0; Index < OutputStreams; Index++) {
473 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
474 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_OUTPUT_STREAM_OFFSET(InputStreams, Index), 0);
475 }
476
477 for (Index = 0; Index < BiDirStreams; Index++) {
478 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_CONTROL0 + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
479 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_STREAM_STATUS + HDAC_STREAM_BASE + HDAC_BIDIR_STREAM_OFFSET(InputStreams, OutputStreams, Index), 0);
480 }
481
482 // stop DMA
483 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL) & ~HDAC_CORB_CONTROL_MASK;
484 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL, Control);
485
486 Control = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL) & ~HDAC_RIRB_CONTROL_MASK;
487 WRITE_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL, Control);
488
489 for (int timeout = 0; timeout < 10; timeout++) {
490 KeStallExecutionProcessor(10);
491
492 corbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_CORB_CONTROL);
493 rirbControl = READ_REGISTER_UCHAR(DeviceExtension->RegBase + HDAC_RIRB_CONTROL);
494 if (corbControl == 0 && rirbControl == 0)
495 break;
496 }
497 if (corbControl != 0 || rirbControl != 0) {
498 DPRINT1("hda: unable to stop dma\n");
499 return STATUS_UNSUCCESSFUL;
500 }
501
502 // reset DMA position buffer
503 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_LOWER), 0);
504 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_DMA_POSITION_BASE_UPPER), 0);
505
506 // Set reset bit - it must be asserted for at least 100us
507 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
508 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control & ~GLOBAL_CONTROL_RESET);
509
510 for (int timeout = 0; timeout < 10; timeout++) {
511 KeStallExecutionProcessor(10);
512
513 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
514 if ((Control & GLOBAL_CONTROL_RESET) == 0)
515 break;
516 }
517 if ((Control & GLOBAL_CONTROL_RESET) != 0)
518 {
519 DPRINT1("hda: unable to reset controller\n");
520 return STATUS_UNSUCCESSFUL;
521 }
522
523 // Unset reset bit
524 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
525 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_RESET);
526
527 for (int timeout = 0; timeout < 10; timeout++) {
528 KeStallExecutionProcessor(10);
529
530 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
531 if ((Control & GLOBAL_CONTROL_RESET) != 0)
532 break;
533 }
534 if ((Control & GLOBAL_CONTROL_RESET) == 0) {
535 DPRINT1("hda: unable to exit reset\n");
536 return STATUS_UNSUCCESSFUL;
537 }
538
539 // Wait for codecs to finish their own reset (apparently needs more
540 // time than documented in the specs)
541 KeStallExecutionProcessor(100);
542
543 // Enable unsolicited responses
544 Control = READ_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL));
545 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_GLOBAL_CONTROL), Control | GLOBAL_CONTROL_UNSOLICITED);
546
547 return STATUS_SUCCESS;
548 }
549
550 NTSTATUS
551 NTAPI
552 HDA_FDOStartDevice(
553 IN PDEVICE_OBJECT DeviceObject,
554 IN PIRP Irp)
555 {
556 PIO_STACK_LOCATION IoStack;
557 NTSTATUS Status = STATUS_SUCCESS;
558 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
559 PCM_RESOURCE_LIST Resources;
560 ULONG Index;
561 USHORT Value;
562
563 /* get device extension */
564 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
565 ASSERT(DeviceExtension->IsFDO == TRUE);
566
567 /* forward irp to lower device */
568 if (!IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp))
569 {
570 ASSERT(FALSE);
571 return STATUS_INVALID_DEVICE_REQUEST;
572 }
573 Status = Irp->IoStatus.Status;
574 if (!NT_SUCCESS(Status))
575 {
576 // failed to start
577 DPRINT1("HDA_StartDevice Lower device failed to start %x\n", Status);
578 return Status;
579 }
580
581 /* get current irp stack location */
582 IoStack = IoGetCurrentIrpStackLocation(Irp);
583
584 Resources = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
585 for (Index = 0; Index < Resources->List[0].PartialResourceList.Count; Index++)
586 {
587 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &Resources->List[0].PartialResourceList.PartialDescriptors[Index];
588
589 if (Descriptor->Type == CmResourceTypeMemory)
590 {
591 DeviceExtension->RegLength = Descriptor->u.Memory.Length;
592 DeviceExtension->RegBase = (PUCHAR)MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached);
593 if (DeviceExtension->RegBase == NULL)
594 {
595 DPRINT1("[HDAB] Failed to map registers\n");
596 Status = STATUS_UNSUCCESSFUL;
597 break;
598 }
599 }
600 else if (Descriptor->Type == CmResourceTypeInterrupt)
601 {
602 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
603 HDA_InterruptService,
604 DeviceObject,
605 NULL,
606 Descriptor->u.Interrupt.Vector,
607 Descriptor->u.Interrupt.Level,
608 Descriptor->u.Interrupt.Level,
609 (KINTERRUPT_MODE)(Descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED),
610 (Descriptor->ShareDisposition != CmResourceShareDeviceExclusive),
611 Descriptor->u.Interrupt.Affinity,
612 FALSE);
613 if (!NT_SUCCESS(Status))
614 {
615 DPRINT1("[HDAB] Failed to connect interrupt. Status=%lx\n", Status);
616 break;
617 }
618
619 }
620 }
621
622 if (NT_SUCCESS(Status))
623 {
624 // Get controller into valid state
625 Status = HDA_ResetController(DeviceObject);
626 if (!NT_SUCCESS(Status)) return Status;
627
628 // Setup CORB/RIRB/DMA POS
629 Status = HDA_InitCorbRirbPos(DeviceObject);
630 if (!NT_SUCCESS(Status)) return Status;
631
632
633 // Don't enable codec state change interrupts. We don't handle
634 // them, as we want to use the STATE_STATUS register to identify
635 // available codecs. We'd have to clear that register in the interrupt
636 // handler to 'ack' the codec change.
637 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE)) & ~HDAC_WAKE_ENABLE_MASK;
638 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_WAKE_ENABLE), Value);
639
640 // Enable controller interrupts
641 WRITE_REGISTER_ULONG((PULONG)(DeviceExtension->RegBase + HDAC_INTR_CONTROL), INTR_CONTROL_GLOBAL_ENABLE | INTR_CONTROL_CONTROLLER_ENABLE);
642
643 KeStallExecutionProcessor(100);
644
645 Value = READ_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS));
646 if (!Value) {
647 DPRINT1("hda: bad codec status\n");
648 return STATUS_UNSUCCESSFUL;
649 }
650 WRITE_REGISTER_USHORT((PUSHORT)(DeviceExtension->RegBase + HDAC_STATE_STATUS), Value);
651
652 // Create codecs
653 DPRINT1("Codecs %lx\n", Value);
654 for (Index = 0; Index < HDA_MAX_CODECS; Index++) {
655 if ((Value & (1 << Index)) != 0) {
656 HDA_InitCodec(DeviceObject, Index);
657 }
658 }
659 }
660
661 return Status;
662 }
663
664 NTSTATUS
665 NTAPI
666 HDA_FDORemoveDevice(
667 _In_ PDEVICE_OBJECT DeviceObject,
668 _Inout_ PIRP Irp)
669 {
670 NTSTATUS Status;
671 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
672 ULONG CodecIndex, AFGIndex;
673 PHDA_CODEC_ENTRY CodecEntry;
674 PDEVICE_OBJECT ChildPDO;
675 PHDA_PDO_DEVICE_EXTENSION ChildDeviceExtension;
676
677 /* get device extension */
678 DeviceExtension = static_cast<PHDA_FDO_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
679 ASSERT(DeviceExtension->IsFDO == TRUE);
680
681 Irp->IoStatus.Status = STATUS_SUCCESS;
682 IoSkipCurrentIrpStackLocation(Irp);
683 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
684
685 IoDetachDevice(DeviceExtension->LowerDevice);
686
687 if (DeviceExtension->RegBase != NULL)
688 {
689 MmUnmapIoSpace(DeviceExtension->RegBase,
690 DeviceExtension->RegLength);
691 }
692 if (DeviceExtension->Interrupt != NULL)
693 {
694 IoDisconnectInterrupt(DeviceExtension->Interrupt);
695 }
696 if (DeviceExtension->CorbBase != NULL)
697 {
698 MmFreeContiguousMemory(DeviceExtension->CorbBase);
699 }
700
701 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
702 {
703 CodecEntry = DeviceExtension->Codecs[CodecIndex];
704 if (CodecEntry == NULL)
705 {
706 continue;
707 }
708
709 ASSERT(CodecEntry->AudioGroupCount <= HDA_MAX_AUDIO_GROUPS);
710 for (AFGIndex = 0; AFGIndex < CodecEntry->AudioGroupCount; AFGIndex++)
711 {
712 ChildPDO = CodecEntry->AudioGroups[AFGIndex]->ChildPDO;
713 if (ChildPDO != NULL)
714 {
715 ChildDeviceExtension = static_cast<PHDA_PDO_DEVICE_EXTENSION>(ChildPDO->DeviceExtension);
716 ChildDeviceExtension->Codec = NULL;
717 ChildDeviceExtension->AudioGroup = NULL;
718 ChildDeviceExtension->FDO = NULL;
719 ChildDeviceExtension->ReportedMissing = TRUE;
720 HDA_PDORemoveDevice(ChildPDO);
721 }
722 FreeItem(CodecEntry->AudioGroups[AFGIndex]);
723 }
724 FreeItem(CodecEntry);
725 }
726
727 IoDeleteDevice(DeviceObject);
728
729 return Status;
730 }
731
732 NTSTATUS
733 NTAPI
734 HDA_FDOQueryBusRelations(
735 IN PDEVICE_OBJECT DeviceObject,
736 IN PIRP Irp)
737 {
738 ULONG DeviceCount, CodecIndex, AFGIndex;
739 PHDA_FDO_DEVICE_EXTENSION DeviceExtension;
740 PHDA_CODEC_ENTRY Codec;
741 PDEVICE_RELATIONS DeviceRelations;
742
743 /* get device extension */
744 DeviceExtension = (PHDA_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
745 ASSERT(DeviceExtension->IsFDO == TRUE);
746
747 DeviceCount = 0;
748 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
749 {
750 if (DeviceExtension->Codecs[CodecIndex] == NULL)
751 continue;
752
753 Codec = DeviceExtension->Codecs[CodecIndex];
754 DeviceCount += Codec->AudioGroupCount;
755 }
756
757 if (DeviceCount == 0)
758 return STATUS_UNSUCCESSFUL;
759
760 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? sizeof(PDEVICE_OBJECT) * (DeviceCount - 1) : 0));
761 if (!DeviceRelations)
762 return STATUS_INSUFFICIENT_RESOURCES;
763
764 DeviceRelations->Count = 0;
765 for (CodecIndex = 0; CodecIndex < HDA_MAX_CODECS; CodecIndex++)
766 {
767 if (DeviceExtension->Codecs[CodecIndex] == NULL)
768 continue;
769
770 Codec = DeviceExtension->Codecs[CodecIndex];
771 ASSERT(Codec->AudioGroupCount <= HDA_MAX_AUDIO_GROUPS);
772 for (AFGIndex = 0; AFGIndex < Codec->AudioGroupCount; AFGIndex++)
773 {
774 DeviceRelations->Objects[DeviceRelations->Count] = Codec->AudioGroups[AFGIndex]->ChildPDO;
775 ObReferenceObject(Codec->AudioGroups[AFGIndex]->ChildPDO);
776 DeviceRelations->Count++;
777 }
778 }
779
780 /* FIXME handle existing device relations */
781 ASSERT(Irp->IoStatus.Information == 0);
782
783 /* store device relations */
784 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
785
786 /* done */
787 return STATUS_SUCCESS;
788 }
789
790