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