1 /******************************************************************************** 2 ** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved. 3 ** 4 ** Portions Copyright (c) 1998-1999 Intel Corporation 5 ** 6 ********************************************************************************/ 7 8 /* The file adapter.cpp was reviewed by LCA in June 2011 and is acceptable for use by Microsoft. */ 9 10 // 11 // The name that is printed in debug output messages 12 // 13 #define STR_MODULENAME "AC97 Adapter: " 14 15 // 16 // All the GUIDs from portcls and your own defined GUIDs end up in this object. 17 // 18 #define PUT_GUIDS_HERE 19 20 // 21 // We want the global debug variables here. 22 // 23 #define DEFINE_DEBUG_VARS 24 25 #include "adapter.h" 26 27 28 /***************************************************************************** 29 * Referenced forward 30 */ 31 DRIVER_ADD_DEVICE AddDevice; 32 33 #ifdef _MSC_VER 34 #pragma code_seg("PAGE") 35 #endif 36 /***************************************************************************** 37 * InstallSubdevice 38 ***************************************************************************** 39 * This function creates and registers a subdevice consisting of a port 40 * driver, a minport driver and a set of resources bound together. It will 41 * also optionally place a pointer to an interface on the port driver in a 42 * specified location before initializing the port driver. This is done so 43 * that a common ISR can have access to the port driver during initialization, 44 * when the ISR might fire. 45 * This function is internally used and validates no parameters. 46 */ 47 NTSTATUS InstallSubdevice 48 ( 49 _In_ PDEVICE_OBJECT DeviceObject, 50 _In_ PIRP Irp, 51 _In_ PWSTR Name, 52 _In_ REFGUID PortClassId, 53 _In_ REFGUID MiniportClassId, 54 _In_opt_ PFNCREATEMINIPORT MiniportCreate, 55 _In_opt_ PUNKNOWN UnknownAdapter, 56 _In_opt_ PRESOURCELIST ResourceList, 57 _In_opt_ REFGUID PortInterfaceId, 58 _Out_opt_ PMINIPORT * OutMiniport, 59 _Out_opt_ PUNKNOWN * OutPortUnknown 60 ) 61 { 62 PAGED_CODE (); 63 64 NTSTATUS ntStatus; 65 PPORT port; 66 PMINIPORT miniport; 67 68 DOUT (DBG_PRINT, ("[InstallSubdevice]")); 69 70 #ifndef __REACTOS__ 71 UNREFERENCED_PARAMETER(PortInterfaceId); 72 #endif 73 74 // 75 // Create the port driver object 76 // 77 ntStatus = PcNewPort (&port,PortClassId); 78 79 // 80 // return immediately in case of an error 81 // 82 if (!NT_SUCCESS (ntStatus)) 83 return ntStatus; 84 85 // 86 // Create the miniport object 87 // 88 if (MiniportCreate) 89 { 90 ntStatus = MiniportCreate ((PUNKNOWN*)&miniport, MiniportClassId, 91 NULL, NonPagedPool); 92 } 93 else 94 { 95 ntStatus = PcNewMiniport (&miniport,MiniportClassId); 96 } 97 98 // 99 // return immediately in case of an error 100 // 101 if (!NT_SUCCESS (ntStatus)) 102 { 103 port->Release (); 104 return ntStatus; 105 } 106 107 // 108 // Init the port driver and miniport in one go. 109 // 110 #ifdef _MSC_VER 111 #pragma warning(push) 112 #endif 113 // IPort::Init's annotation on ResourceList requires it to be non-NULL. However, 114 // for dynamic devices, we may no longer have the resource list and this should 115 // still succeed. 116 // 117 #ifdef _MSC_VER 118 #pragma warning(disable:6387) 119 #endif 120 ntStatus = port->Init (DeviceObject, Irp, miniport, UnknownAdapter, 121 ResourceList); 122 #ifdef _MSC_VER 123 #pragma warning(pop) 124 #endif 125 126 if (NT_SUCCESS (ntStatus)) 127 { 128 // 129 // Register the subdevice (port/miniport combination). 130 // 131 ntStatus = PcRegisterSubdevice (DeviceObject, Name, port); 132 133 // 134 // Deposit the port as an unknown if it's needed. 135 // 136 if (OutPortUnknown && NT_SUCCESS (ntStatus)) 137 { 138 ntStatus = port->QueryInterface (IID_IUnknown, 139 (PVOID *)OutPortUnknown); 140 } 141 142 // 143 // Deposit the miniport as an IMiniport if it's needed. 144 // 145 if ( OutMiniport && NT_SUCCESS (ntStatus) ) 146 { 147 ntStatus = miniport->QueryInterface (IID_IMiniport, 148 (PVOID *)OutMiniport); 149 } 150 } 151 152 // 153 // Release the reference for the port and miniport. This is the right 154 // thing to do, regardless of the outcome. 155 // 156 miniport->Release (); 157 port->Release (); 158 159 160 return ntStatus; 161 } 162 163 164 /***************************************************************************** 165 * ValidateResources 166 ***************************************************************************** 167 * This function validates the list of resources for the various functions on 168 * the card. This code is specific to the adapter. 169 * This function doesn't check the ResourceList parameter and returns 170 * STATUS_SUCCESS when the resources are valid. 171 */ 172 NTSTATUS ValidateResources 173 ( 174 IN PRESOURCELIST ResourceList // All resources. 175 ) 176 { 177 PAGED_CODE (); 178 179 DOUT (DBG_PRINT, ("[ValidateResources]")); 180 181 // 182 // Get counts for the types of resources. 183 // 184 ULONG countIO = ResourceList->NumberOfPorts (); 185 ULONG countIRQ = ResourceList->NumberOfInterrupts (); 186 ULONG countDMA = ResourceList->NumberOfDmas (); 187 188 // validate resources 189 if ((countIO != 2) || (countIRQ != 1) || (countDMA != 0)) 190 { 191 DOUT (DBG_ERROR, ("Unknown configuration:\n" 192 " IO count: %d\n" 193 " IRQ count: %d\n" 194 " DMA count: %d", 195 countIO, countIRQ, countDMA)); 196 return STATUS_DEVICE_CONFIGURATION_ERROR; 197 } 198 199 return STATUS_SUCCESS; 200 } 201 202 /***************************************************************************** 203 * StartDevice 204 ***************************************************************************** 205 * This function is called by the operating system when the device is started. 206 * It is responsible for starting the miniports. This code is specific to 207 * the adapter because it calls out miniports for functions that are specific 208 * to the adapter. 209 */ 210 NTSTATUS GZCALL StartDevice 211 ( 212 IN PDEVICE_OBJECT DeviceObject, // Device object. 213 IN PIRP Irp, // IO request packet. 214 IN PRESOURCELIST ResourceList // List of hardware resources. 215 ) 216 { 217 PAGED_CODE (); 218 219 ASSERT (DeviceObject); 220 ASSERT (Irp); 221 ASSERT (ResourceList); 222 223 NTSTATUS ntStatus; 224 225 DOUT (DBG_PRINT, ("[StartDevice]")); 226 227 // 228 // Determine which version of the OS we are running under. We don't want 229 // to run under Win98G. 230 // 231 232 // create a wave cyclic port 233 PPORT pPort = 0; 234 ntStatus = PcNewPort (&pPort,CLSID_PortWaveCyclic); 235 236 // check error code 237 if (NT_SUCCESS (ntStatus)) 238 { 239 // query for the event interface which is not supported in Win98 gold. 240 PPORTEVENTS pPortEvents = 0; 241 ntStatus = pPort->QueryInterface (IID_IPortEvents, 242 (PVOID *)&pPortEvents); 243 if (!NT_SUCCESS (ntStatus)) 244 { 245 DOUT (DBG_ERROR, ("This driver is not for Win98 Gold!")); 246 ntStatus = STATUS_UNSUCCESSFUL; // change error code. 247 } 248 else 249 { 250 pPortEvents->Release (); 251 } 252 pPort->Release (); 253 } 254 255 // now return in case it was Win98 Gold. 256 if (!NT_SUCCESS (ntStatus)) 257 return ntStatus; 258 259 // 260 // Validate the resources. 261 // We don't have to split the resources into several resource lists cause 262 // the topology miniport doesn't need a resource list, the wave pci miniport 263 // needs all resources like the adapter common object. 264 // 265 ntStatus = ValidateResources (ResourceList); 266 267 // 268 // return immediately in case of an error 269 // 270 if (!NT_SUCCESS (ntStatus)) 271 return ntStatus; 272 273 // 274 // If the adapter has the right resources... 275 // 276 PADAPTERCOMMON pAdapterCommon = NULL; 277 PUNKNOWN pUnknownCommon; 278 279 // create a new adapter common object 280 ntStatus = NewAdapterCommon (&pUnknownCommon, IID_IAC97AdapterCommon, 281 NULL, NonPagedPool); 282 283 if (NT_SUCCESS (ntStatus)) 284 { 285 // query for the IAC97AdapterCommon interface 286 ntStatus = pUnknownCommon->QueryInterface (IID_IAC97AdapterCommon, 287 (PVOID *)&pAdapterCommon); 288 if (NT_SUCCESS (ntStatus)) 289 { 290 // Initialize the object 291 ntStatus = pAdapterCommon->Init (ResourceList, DeviceObject); 292 293 if (NT_SUCCESS (ntStatus)) 294 { 295 // register with PortCls for power-management services 296 ntStatus = PcRegisterAdapterPowerManagement ((PUNKNOWN)pAdapterCommon, 297 DeviceObject); 298 } 299 } 300 301 // release the IID_IAC97AdapterCommon on adapter common 302 pUnknownCommon->Release (); 303 } 304 305 // print error message. 306 if (!NT_SUCCESS (ntStatus)) 307 { 308 DOUT (DBG_ERROR, ("Could not create or query AdapterCommon.")); 309 } 310 311 // 312 // These are the port driver pointers we are keeping around for registering 313 // physical connections. 314 // 315 PMINIPORT miniTopology = NULL; 316 PUNKNOWN unknownWave = NULL; 317 PUNKNOWN unknownTopology = NULL; 318 PAC97MINIPORTTOPOLOGY pMiniportTopology = NULL; 319 320 // 321 // Start the topology miniport. 322 // 323 if (NT_SUCCESS (ntStatus)) 324 { 325 ntStatus = InstallSubdevice (DeviceObject, 326 Irp, 327 L"Topology", 328 CLSID_PortTopology, 329 CLSID_PortTopology, // not used 330 CreateAC97MiniportTopology, 331 pAdapterCommon, 332 NULL, 333 GUID_NULL, 334 &miniTopology, 335 &unknownTopology); 336 337 if (NT_SUCCESS (ntStatus)) 338 { 339 // query for the IAC97MiniportTopology interface 340 ntStatus = miniTopology->QueryInterface (IID_IAC97MiniportTopology, 341 (PVOID *)&pMiniportTopology); 342 miniTopology->Release (); 343 miniTopology = NULL; 344 } 345 346 // print error message. 347 if (!NT_SUCCESS (ntStatus)) 348 { 349 DOUT (DBG_ERROR, ("Could not create or query TopologyICH")); 350 } 351 } 352 353 // 354 // Start the wave miniport. 355 // 356 if (NT_SUCCESS (ntStatus)) 357 { 358 #if (NTDDI_VERSION >= NTDDI_VISTA) 359 ntStatus = InstallSubdevice (DeviceObject, 360 Irp, 361 L"Wave", 362 CLSID_PortWaveRT, 363 CLSID_PortWaveRT, // not used 364 CreateAC97MiniportWaveRT, 365 pAdapterCommon, 366 ResourceList, 367 IID_IPortWaveRT, 368 NULL, 369 &unknownWave); 370 371 if (!NT_SUCCESS (ntStatus)) 372 { 373 #endif 374 // 375 // If creation of the RT port failed we can fall back to the WavePCI 376 // or WaveCyc port of portcls. In this case, we try the WavePCI port. 377 // 378 #if 1 379 ntStatus = InstallSubdevice (DeviceObject, 380 Irp, 381 L"Wave", 382 CLSID_PortWaveCyclic, 383 CLSID_PortWaveCyclic, // not used 384 CreateAC97MiniportWaveCyclic, 385 pAdapterCommon, 386 ResourceList, 387 IID_IPortWaveCyclic, 388 NULL, 389 &unknownWave); 390 #else 391 ntStatus = InstallSubdevice (DeviceObject, 392 Irp, 393 L"Wave", 394 CLSID_PortWavePci, 395 CLSID_PortWavePci, // not used 396 CreateAC97MiniportWavePCI, 397 pAdapterCommon, 398 ResourceList, 399 IID_IPortWavePci, 400 NULL, 401 &unknownWave); 402 #endif 403 404 405 #if (NTDDI_VERSION >= NTDDI_VISTA) 406 } 407 #endif 408 // print error message. 409 if (!NT_SUCCESS (ntStatus)) 410 { 411 DOUT (DBG_ERROR, ("WaveRT and WavePCI miniport installation failed!")); 412 } 413 } 414 415 // 416 // Establish physical connections between filters as shown. 417 // 418 // +------+ +------+ 419 // | Wave | | Topo | 420 // Capture <---|2 3|<===|x |<--- CD 421 // | | | | 422 // Render --->|0 1|===>|y |<--- Line In 423 // | | | | 424 // Mic <---|4 5|<===|z |<--- Mic 425 // +------+ | | 426 // | |---> Line Out 427 // +------+ 428 // 429 // Note that the pin numbers for the nodes to be connected 430 // vary depending on the hardware/codec configuration. 431 // Also, the mic input may or may not be present. 432 // 433 // So, 434 // Do a QI on unknownTopology to get an interface to call 435 // a method on to get the topology miniport pin IDs. 436 437 if (NT_SUCCESS (ntStatus)) 438 { 439 ULONG ulWaveOut, ulWaveIn, ulMicIn; 440 441 // get the pin numbers. 442 DOUT (DBG_PRINT, ("Connecting topo and wave.")); 443 ntStatus = pMiniportTopology->GetPhysicalConnectionPins (&ulWaveOut, 444 &ulWaveIn, &ulMicIn); 445 446 // register wave render connection 447 if (NT_SUCCESS (ntStatus)) 448 { 449 ntStatus = PcRegisterPhysicalConnection (DeviceObject, 450 unknownWave, 451 PIN_WAVEOUT_BRIDGE, 452 unknownTopology, 453 ulWaveOut); 454 // print error message. 455 if (!NT_SUCCESS (ntStatus)) 456 { 457 DOUT (DBG_ERROR, ("Cannot connect topology and wave miniport" 458 " (render)!")); 459 } 460 } 461 462 463 if (NT_SUCCESS (ntStatus)) 464 { 465 // register wave capture connection 466 ntStatus = PcRegisterPhysicalConnection (DeviceObject, 467 unknownTopology, 468 ulWaveIn, 469 unknownWave, 470 PIN_WAVEIN_BRIDGE); 471 // print error message. 472 if (!NT_SUCCESS (ntStatus)) 473 { 474 DOUT (DBG_ERROR, ("Cannot connect topology and wave miniport" 475 " (capture)!")); 476 } 477 } 478 479 if (NT_SUCCESS (ntStatus)) 480 { 481 // register mic capture connection 482 if (pAdapterCommon->GetPinConfig (PINC_MICIN_PRESENT)) 483 { 484 ntStatus = PcRegisterPhysicalConnection (DeviceObject, 485 unknownTopology, 486 ulMicIn, 487 unknownWave, 488 PIN_MICIN_BRIDGE); 489 // print error message. 490 if (!NT_SUCCESS (ntStatus)) 491 { 492 DOUT (DBG_ERROR, ("Cannot connect topology and wave miniport" 493 " (MIC)!")); 494 } 495 } 496 } 497 } 498 499 // 500 // Release the adapter common object. It either has other references, 501 // or we need to delete it anyway. 502 // 503 if (pAdapterCommon) 504 pAdapterCommon->Release (); 505 506 // 507 // Release the unknowns. 508 // 509 if (unknownTopology) 510 unknownTopology->Release (); 511 if (unknownWave) 512 unknownWave->Release (); 513 514 // and the AC97 miniport. 515 if (pMiniportTopology) 516 pMiniportTopology->Release (); 517 518 519 return ntStatus; // whatever this is ... 520 } 521 522 /***************************************************************************** 523 * AddDevice 524 ***************************************************************************** 525 * This function is called by the operating system when the device is added. 526 * All adapter drivers can use this code without change. 527 */ 528 // disable prefast warning 28152 because 529 // DO_DEVICE_INITIALIZING is cleared in PcAddAdapterDevice 530 #ifdef _MSC_VER 531 #pragma warning(disable:28152) 532 #endif 533 NTSTATUS GZCALL AddDevice 534 ( 535 IN PDRIVER_OBJECT DriverObject, 536 IN PDEVICE_OBJECT PhysicalDeviceObject 537 ) 538 { 539 PAGED_CODE (); 540 541 DOUT (DBG_PRINT, ("[AddDevice]")); 542 543 544 // 545 // Tell portcls (the class driver) to add the device. 546 // 547 return PcAddAdapterDevice (DriverObject, 548 PhysicalDeviceObject, 549 (PCPFNSTARTDEVICE)StartDevice, 550 MAX_MINIPORTS, 551 0); 552 } 553 554 /***************************************************************************** 555 * DriverEntry 556 ***************************************************************************** 557 * This function is called by the operating system when the driver is loaded. 558 * All adapter drivers can use this code without change. 559 */ 560 extern "C" DRIVER_INITIALIZE DriverEntry; 561 extern "C" NTSTATUS GZCALL DriverEntry 562 ( 563 IN PDRIVER_OBJECT DriverObject, 564 IN PUNICODE_STRING RegistryPathName 565 ) 566 { 567 PAGED_CODE (); 568 569 DOUT (DBG_PRINT, ("[DriverEntry]")); 570 571 // 572 // Tell the class driver to initialize the driver. 573 // 574 NTSTATUS RetValue = PcInitializeAdapterDriver (DriverObject, 575 RegistryPathName, 576 (PDRIVER_ADD_DEVICE)AddDevice); 577 578 579 return RetValue; 580 } 581 582 583 584