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