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 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 DPRINT1("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 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 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 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 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 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 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 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 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