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