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