Merge from amd64-branch:
[reactos.git] / reactos / drivers / wdm / audio / drivers / CMIDriver / adapter.cpp
1 /*
2 Copyright (c) 2006-2007 dogbert <dogber1@gmail.com>
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #define PUT_GUIDS_HERE
29 #include <initguid.h>
30 #include "adapter.hpp"
31
32 //#pragma code_seg("PAGE")
33
34
35 NTSTATUS InstallSubdevice(
36 PDEVICE_OBJECT DeviceObject,
37 PIRP Irp,
38 PWCHAR Name,
39 REFGUID PortClassId,
40 REFGUID MiniportClassId,
41 PFNCREATEINSTANCE MiniportCreate,
42 PUNKNOWN UnknownAdapter,
43 PRESOURCELIST ResourceList,
44 REFGUID PortInterfaceId,
45 PUNKNOWN* OutPortUnknown)
46 {
47 NTSTATUS ntStatus;
48 PPORT Port;
49 PMINIPORT MiniPort;
50
51 ////PAGED_CODE();
52 DBGPRINT(("InstallSubdevice()"));
53
54 ntStatus = PcNewPort(&Port, PortClassId);
55 if (NT_SUCCESS(ntStatus)) {
56 if (MiniportCreate) {
57 ntStatus = MiniportCreate((PUNKNOWN*)&MiniPort, MiniportClassId, NULL, NonPagedPool);
58 } else {
59 ntStatus = PcNewMiniport(&MiniPort, MiniportClassId);
60 }
61 }
62
63 if (!NT_SUCCESS(ntStatus)) {
64 Port->Release();
65 return ntStatus;
66 }
67
68 ntStatus = Port->Init(DeviceObject, Irp, MiniPort, UnknownAdapter, ResourceList);
69 if (NT_SUCCESS(ntStatus)) {
70 ntStatus = PcRegisterSubdevice(DeviceObject, Name, Port);
71
72 if (OutPortUnknown && NT_SUCCESS (ntStatus)) {
73 ntStatus = Port->QueryInterface(IID_IUnknown, (PVOID *)OutPortUnknown);
74 }
75 }
76
77 if (MiniPort) {
78 MiniPort->Release();
79 }
80
81 if (Port) {
82 Port->Release();
83 }
84
85 return ntStatus;
86 }
87
88
89 NTSTATUS
90 ProcessResources(
91 PRESOURCELIST ResourceList,
92 PRESOURCELIST* UartResourceList)
93 {
94 NTSTATUS ntStatus;
95
96 ////PAGED_CODE();
97 ////ASSERT(ResourceList);
98 ////ASSERT(UartResourceList);
99 //DBGPRINT(("ProcessResources()"));
100 //DBGPRINT(("NumberOfPorts: %d, NumberOfInterrupts: %d, NumberOfDmas: %d", ResourceList->NumberOfPorts(), ResourceList->NumberOfInterrupts(), ResourceList->NumberOfDmas()));
101
102 #ifdef UART
103 (*UartResourceList) = NULL;
104 #endif
105
106
107 if ((ResourceList->NumberOfPorts() == 0) || (ResourceList->NumberOfPorts() > 2) || (ResourceList->NumberOfInterrupts() != 1) || (ResourceList->NumberOfDmas() != 0)) {
108 DBGPRINT(("Unexpected configuration"));
109 return STATUS_DEVICE_CONFIGURATION_ERROR;
110 }
111
112 #ifdef UART
113 ntStatus = PcNewResourceSublist(UartResourceList, NULL, PagedPool, ResourceList, 2);
114 if (NT_SUCCESS(ntStatus)) {
115 (*UartResourceList)->AddPortFromParent(ResourceList, 1);
116 (*UartResourceList)->AddInterruptFromParent(ResourceList, 0);
117 }
118 #endif
119
120 return STATUS_SUCCESS;
121 }
122
123
124 NTSTATUS StartDevice(PDEVICE_OBJECT DeviceObject, PIRP Irp, PRESOURCELIST ResourceList)
125 {
126 NTSTATUS ntStatus;
127 PPORT pPort = 0;
128 ULONG* MPUBase;
129 #if 0
130 //PAGED_CODE();
131 //ASSERT(DeviceObject);
132 //ASSERT(Irp);
133 //ASSERT(ResourceList);
134 DBGPRINT(("StartDevice()"));
135 #endif
136
137 ntStatus = PcNewPort(&pPort,CLSID_PortWaveCyclic);
138 if (NT_SUCCESS(ntStatus)) {
139 // not supported in the first edition of win98
140 PPORTEVENTS pPortEvents = 0;
141 ntStatus = pPort->QueryInterface(IID_IPortEvents, (PVOID *)&pPortEvents);
142 if (!NT_SUCCESS(ntStatus)) {
143 DBGPRINT(("ERROR: This driver doesn't work under Win98!"));
144 ntStatus = STATUS_UNSUCCESSFUL;
145 }
146 else
147 {
148 pPortEvents->Release();
149 }
150 pPort->Release ();
151 } else {
152 return ntStatus;
153 }
154
155 // resource validation
156 PRESOURCELIST UartResourceList = NULL;
157 ntStatus = ProcessResources(ResourceList, &UartResourceList);
158 if (!NT_SUCCESS(ntStatus)) {
159 DBGPRINT(("ProcessResources() failed"));
160 return ntStatus;
161 }
162
163 PCMIADAPTER pCMIAdapter = NULL;
164 PUNKNOWN pUnknownCommon = NULL;
165
166 // create the CMIAdapter object
167 ntStatus = NewCMIAdapter(&pUnknownCommon, IID_ICMIAdapter, NULL, NonPagedPool);
168 if (!NT_SUCCESS(ntStatus)) {
169 DBGPRINT(("NewCMIAdapter() failed"));
170 return ntStatus;
171 }
172
173 ntStatus = pUnknownCommon->QueryInterface(IID_ICMIAdapter, (PVOID *)&pCMIAdapter);
174 if (!NT_SUCCESS(ntStatus)) {
175 DBGPRINT(("QueryInterface() for ICMIAdapter failed"));
176 return ntStatus;
177 }
178 ntStatus = pCMIAdapter->init(ResourceList, DeviceObject);
179 if (!NT_SUCCESS(ntStatus)) {
180 DBGPRINT(("CMIAdapter->init() failed"));
181 return ntStatus;
182 }
183
184 ntStatus = PcRegisterAdapterPowerManagement((PUNKNOWN)pCMIAdapter, DeviceObject);
185
186 pUnknownCommon->Release();
187
188 PUNKNOWN unknownWave = NULL;
189 PUNKNOWN unknownTopology = NULL;
190
191 // install the topology miniport.
192 ntStatus = InstallSubdevice(DeviceObject, Irp, L"Topology", CLSID_PortTopology, CLSID_PortTopology, CreateMiniportTopologyCMI, pCMIAdapter, NULL, GUID_NULL, &unknownTopology);
193 if (!NT_SUCCESS (ntStatus)) {
194 DBGPRINT(("Topology miniport installation failed"));
195 return ntStatus;
196 }
197
198 #ifdef UART
199 // install the UART miniport - execution order important
200 ntStatus = STATUS_UNSUCCESSFUL;
201 MPUBase = 0;
202 for (int i=0;i<ResourceList->NumberOfPorts();i++) {
203 if (ResourceList->FindTranslatedPort(i)->u.Port.Length == 2) {
204 MPUBase = (UInt32*)ResourceList->FindTranslatedPort(i)->u.Port.Start.QuadPart;
205 }
206 }
207 if (MPUBase != 0) {
208 ntStatus = pCMIAdapter->activateMPU(MPUBase);
209 if (NT_SUCCESS(ntStatus)) {
210 ntStatus = InstallSubdevice(DeviceObject, Irp, L"Uart", CLSID_PortDMus, CLSID_MiniportDriverDMusUART, NULL, pCMIAdapter->getInterruptSync(), UartResourceList, IID_IPortDMus, NULL);
211 }
212 }
213 if (!NT_SUCCESS(ntStatus)) {
214 MPUBase = 0;
215 pCMIAdapter->activateMPU(0);
216 DBGPRINT(("UART miniport installation failed"));
217 }
218 if (UartResourceList) {
219 UartResourceList->Release();
220 }
221 #endif
222
223 // install the wave miniport - the order matters here
224 #ifdef WAVERT
225 ntStatus = InstallSubdevice(DeviceObject, Irp, L"Wave", CLSID_PortWaveRT, CLSID_PortWaveRT, CreateMiniportWaveCMI, pCMIAdapter, ResourceList, IID_IPortWaveRT, &unknownWave);
226 #else
227 ntStatus = InstallSubdevice(DeviceObject, Irp, L"Wave", CLSID_PortWaveCyclic, CLSID_PortWaveCyclic, CreateMiniportWaveCMI, pCMIAdapter, ResourceList, IID_IPortWaveCyclic, &unknownWave);
228 #endif
229 if (!NT_SUCCESS(ntStatus)) {
230 DBGPRINT(("Wave miniport installation failed"));
231 return ntStatus;
232 }
233
234 // connect wave and topology pins
235 ntStatus = PcRegisterPhysicalConnection(DeviceObject, unknownWave, PIN_WAVE_RENDER_SOURCE, unknownTopology, PIN_WAVEOUT_SOURCE);
236 if (!NT_SUCCESS(ntStatus)) {
237 DBGPRINT(("Cannot connect topology and wave miniport (render)!"));
238 return ntStatus;
239 }
240 ntStatus = PcRegisterPhysicalConnection(DeviceObject, unknownTopology, PIN_WAVEIN_DEST, unknownWave, PIN_WAVE_CAPTURE_SOURCE);
241 if (!NT_SUCCESS(ntStatus)) {
242 DBGPRINT(("Cannot connect topology and wave miniport (capture)!"));
243 return ntStatus;
244 }
245 if (!IoIsWdmVersionAvailable(6,0)) {
246 // this shit fixes the fucking XP mixer and breaks the vista mixer, so we have to check for vista here
247 ntStatus = PcRegisterPhysicalConnection(DeviceObject, unknownWave, PIN_WAVE_AC3_RENDER_SOURCE, unknownTopology, PIN_SPDIF_AC3_SOURCE);
248 if (!NT_SUCCESS(ntStatus)) {
249 DBGPRINT(("Cannot connect topology and wave miniport (ac3)!"));
250 }
251 }
252
253 // clean up
254 if (pCMIAdapter) {
255 pCMIAdapter->Release();
256 }
257 if (unknownTopology) {
258 unknownTopology->Release();
259 }
260 if (unknownWave) {
261 unknownWave->Release();
262 }
263
264 return ntStatus;
265 }
266
267 extern
268 "C"
269 NTSTATUS
270 NTAPI
271 AddDevice(
272 PDRIVER_OBJECT DriverObject,
273 PDEVICE_OBJECT PhysicalDeviceObject)
274 {
275 #if 0
276 //PAGED_CODE();
277 DBGPRINT(("AddDevice()"));
278 #endif
279
280 return PcAddAdapterDevice(DriverObject, PhysicalDeviceObject, (PCPFNSTARTDEVICE)StartDevice, MAX_MINIPORTS, 0);
281 }
282
283 bool CopyResourceDescriptor(PIO_RESOURCE_DESCRIPTOR pInResDescriptor, PIO_RESOURCE_DESCRIPTOR pOutResDescriptor)
284 {
285 #if 0
286 //PAGED_CODE();
287 //ASSERT(pInResDescriptor);
288 //ASSERT(pOutResDescriptor);
289 DBGPRINT(("CopyResourceDescriptor()"));
290 RtlCopyMemory(pOutResDescriptor, pInResDescriptor, sizeof(IO_RESOURCE_DESCRIPTOR));
291 #else
292 pOutResDescriptor->Type = pInResDescriptor->Type;
293 pOutResDescriptor->ShareDisposition = pInResDescriptor->ShareDisposition;
294 pOutResDescriptor->Flags = pInResDescriptor->Flags;
295 pOutResDescriptor->Option = pInResDescriptor->Option;
296
297 switch (pInResDescriptor->Type) {
298 case CmResourceTypePort:
299 case CmResourceTypePort | CmResourceTypeNonArbitrated: // huh?
300 /* // filter crap
301 if ((pInResDescriptor->u.Port.Length == 0) ||
302 ( (pInResDescriptor->u.Port.MinimumAddress.HighPart == pInResDescriptor->u.Port.MaximumAddress.HighPart) && (pInResDescriptor->u.Port.MinimumAddress.LowPart == pInResDescriptor->u.Port.MaximumAddress.LowPart) ) ) {
303 return FALSE;
304 }
305 */ pOutResDescriptor->u.Port.MinimumAddress = pInResDescriptor->u.Port.MinimumAddress;
306 pOutResDescriptor->u.Port.MaximumAddress = pInResDescriptor->u.Port.MaximumAddress;
307 pOutResDescriptor->u.Port.Length = pInResDescriptor->u.Port.Length;
308 pOutResDescriptor->u.Port.Alignment = pInResDescriptor->u.Port.Alignment;
309 #if 0
310 DBGPRINT((" Port: min %08x.%08x max %08x.%08x, Length: %x, Option: %x", pOutResDescriptor->u.Port.MinimumAddress.HighPart, pOutResDescriptor->u.Port.MinimumAddress.LowPart,
311 pOutResDescriptor->u.Port.MaximumAddress.HighPart, pOutResDescriptor->u.Port.MaximumAddress.LowPart,
312 pOutResDescriptor->u.Port.Length, pOutResDescriptor->Option));
313 #endif
314 break;
315 case CmResourceTypeInterrupt:
316 pOutResDescriptor->u.Interrupt.MinimumVector = pInResDescriptor->u.Interrupt.MinimumVector;
317 pOutResDescriptor->u.Interrupt.MaximumVector = pInResDescriptor->u.Interrupt.MaximumVector;
318 #if 0
319 DBGPRINT((" IRQ: min %x max %x, Option: %d", pOutResDescriptor->u.Interrupt.MinimumVector, pOutResDescriptor->u.Interrupt.MaximumVector, pOutResDescriptor->Option));
320 #endif
321 break;
322 default:
323 return FALSE;
324 }
325 return TRUE;
326 #endif
327 }
328
329 extern
330 "C"
331 NTSTATUS
332 NTAPI
333 AdapterDispatchPnp(
334 PDEVICE_OBJECT pDeviceObject,
335 PIRP pIrp)
336 {
337 NTSTATUS ntStatus = STATUS_SUCCESS;
338 ULONG resourceListSize;
339 PIO_RESOURCE_REQUIREMENTS_LIST resourceList, list;
340 PIO_RESOURCE_DESCRIPTOR descriptor;
341 PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
342
343 ////PAGED_CODE();
344 ////ASSERT(pDeviceObject);
345 ////ASSERT(pIrp);
346 DBGPRINT(("AdapterDispatchPnp()"));
347
348 if (pIrpStack->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS) {
349 DBGPRINT(("[AdapterDispatchPnp] - IRP_MN_FILTER_RESOURCE_REQUIREMENTS"));
350
351 list = (PIO_RESOURCE_REQUIREMENTS_LIST)pIrp->IoStatus.Information;
352
353 // IO_RESOURCE_REQUIREMENTS_LIST has 1 IO_RESOURCE_LIST, IO_RESOURCE_LIST has 1 IO_RESOURCE_DESCRIPTOR and we want 2 more
354 resourceListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + sizeof(IO_RESOURCE_DESCRIPTOR)*(list->List[0].Count+2) ;
355 resourceList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePoolWithTag(PagedPool, resourceListSize, 'LRDV');
356
357 if (!resourceList) {
358 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
359 return ntStatus;
360 }
361
362
363 RtlZeroMemory(resourceList, resourceListSize);
364
365 // initialize the list header
366 resourceList->AlternativeLists = 1; // number of IO_RESOURCE_LISTs
367 resourceList->ListSize = resourceListSize;
368
369 resourceList->List[0].Version = 1;
370 resourceList->List[0].Revision = 1;
371 resourceList->List[0].Count = 0;
372
373 // copy the resources which have already been assigned
374 for (int i=0;i<list->List[0].Count;i++) {
375 if (CopyResourceDescriptor(&list->List[0].Descriptors[i], &resourceList->List[0].Descriptors[resourceList->List[0].Count])) {
376 resourceList->List[0].Count++;
377 }
378 }
379 ExFreePool(list);
380
381 // an additional port for mpu401
382 resourceList->List[0].Count++;
383 descriptor = &resourceList->List[0].Descriptors[resourceList->List[0].Count-1];
384 descriptor->Option = IO_RESOURCE_PREFERRED;
385 descriptor->Type = CmResourceTypePort;
386 descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
387 descriptor->Flags = CM_RESOURCE_PORT_IO;
388 descriptor->u.Port.MinimumAddress.LowPart = 0x300;
389 descriptor->u.Port.MinimumAddress.HighPart = 0;
390 descriptor->u.Port.MaximumAddress.LowPart = 0x330;
391 descriptor->u.Port.MaximumAddress.HighPart = 0;
392 descriptor->u.Port.Length = 2;
393 descriptor->u.Port.Alignment = 0x10;
394
395 // mpu401 port should be optional. yes, this is severely braindamaged.
396 resourceList->List[0].Count++;
397 descriptor = &resourceList->List[0].Descriptors[resourceList->List[0].Count-1];
398 descriptor->Option = IO_RESOURCE_ALTERNATIVE;
399 descriptor->Type = CmResourceTypePort;
400 descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
401 descriptor->Flags = CM_RESOURCE_PORT_IO;
402 descriptor->u.Port.MinimumAddress.LowPart = 0x0;
403 descriptor->u.Port.MinimumAddress.HighPart = 0;
404 descriptor->u.Port.MaximumAddress.LowPart = 0xFFFF;
405 descriptor->u.Port.MaximumAddress.HighPart = 0;
406 descriptor->u.Port.Length = 1;
407 descriptor->u.Port.Alignment = 0x10;
408
409 // DBGPRINT(("number of resource list descriptors: %d", resourceList->List[0].Count));
410
411 pIrp->IoStatus.Information = (ULONG_PTR)resourceList;
412
413 // set the return status
414 pIrp->IoStatus.Status = ntStatus;
415 }
416
417 // Pass the IRPs on to PortCls
418 ntStatus = PcDispatchIrp(pDeviceObject, pIrp);
419
420 return ntStatus;
421 }
422
423 extern
424 "C"
425 NTSTATUS
426 NTAPI
427 DriverEntry(
428 PDRIVER_OBJECT DriverObject,
429 PUNICODE_STRING RegistryPathName)
430 {
431 NTSTATUS ntStatus;
432
433 DBGPRINT(("DriverEntry()"));
434
435
436 //bind the adapter driver to the portclass driver
437 ntStatus = PcInitializeAdapterDriver(DriverObject, RegistryPathName, AddDevice);
438
439
440 #ifdef UART
441 if(NT_SUCCESS(ntStatus)) {
442 DriverObject->MajorFunction[IRP_MJ_PNP] = AdapterDispatchPnp;
443 }
444 #endif
445 #ifdef WAVERT
446 if (!IoIsWdmVersionAvailable(6,0)) {
447 ntStatus = STATUS_UNSUCCESSFUL;
448 }
449 #endif
450
451 return ntStatus;
452 }
453
454 #pragma code_seg()
455 int __cdecl _purecall (void)
456 {
457 return 0;
458 }