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 */
InstallSubdevice(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp,_In_ PWSTR Name,_In_ REFGUID PortClassId,_In_ REFGUID MiniportClassId,_In_opt_ PFNCREATEMINIPORT MiniportCreate,_In_opt_ PUNKNOWN UnknownAdapter,_In_opt_ PRESOURCELIST ResourceList,_In_opt_ REFGUID PortInterfaceId,_Out_opt_ PMINIPORT * OutMiniport,_Out_opt_ PUNKNOWN * OutPortUnknown)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 */
ValidateResources(IN PRESOURCELIST ResourceList)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 */
StartDevice(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PRESOURCELIST ResourceList)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
AddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject)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;
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPathName)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