[CMIPCI]
[reactos.git] / reactos / drivers / wdm / audio / drivers / CMIDriver / adapter.cpp
1 /*
2 Copyright (c) 2006-2008 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
30 #include "adapter.hpp"
31
32 #ifdef _MSC_VER
33 #pragma code_seg("PAGE")
34 #endif
35
36 static
37 NTSTATUS
38 InstallSubdevice(PDEVICE_OBJECT DeviceObject, PIRP Irp, PWCHAR Name, REFGUID PortClassId, REFGUID MiniportClassId, PFNCREATEINSTANCE MiniportCreate, PUNKNOWN UnknownAdapter, PRESOURCELIST ResourceList, REFGUID PortInterfaceId, PUNKNOWN* OutPortUnknown)
39 {
40 PAGED_CODE();
41 DBGPRINT(("InstallSubdevice()"));
42
43 NTSTATUS ntStatus;
44 PPORT Port;
45 PMINIPORT MiniPort;
46
47 ntStatus = PcNewPort(&Port, PortClassId);
48 if (NT_SUCCESS(ntStatus)) {
49 if (MiniportCreate) {
50 ntStatus = MiniportCreate((PUNKNOWN*)&MiniPort, MiniportClassId, NULL, NonPagedPool);
51 } else {
52 ntStatus = PcNewMiniport(&MiniPort, MiniportClassId);
53 }
54 }
55
56 if (!NT_SUCCESS(ntStatus)) {
57 Port->Release();
58 return ntStatus;
59 }
60
61 ntStatus = Port->Init(DeviceObject, Irp, MiniPort, UnknownAdapter, ResourceList);
62 if (NT_SUCCESS(ntStatus)) {
63 ntStatus = PcRegisterSubdevice(DeviceObject, Name, Port);
64
65 if (OutPortUnknown && NT_SUCCESS (ntStatus)) {
66 ntStatus = Port->QueryInterface(IID_IUnknown, (PVOID *)OutPortUnknown);
67 }
68 }
69
70 if (MiniPort) {
71 MiniPort->Release();
72 }
73
74 if (Port) {
75 Port->Release();
76 }
77
78 return ntStatus;
79 }
80
81 static
82 NTSTATUS
83 ProcessResources(PRESOURCELIST ResourceList, PRESOURCELIST* UartResourceList)
84 {
85 PAGED_CODE();
86 ASSERT(ResourceList);
87 ASSERT(UartResourceList);
88 DBGPRINT(("ProcessResources()"));
89 DBGPRINT(("NumberOfPorts: %d, NumberOfInterrupts: %d, NumberOfDmas: %d", ResourceList->NumberOfPorts(), ResourceList->NumberOfInterrupts(), ResourceList->NumberOfDmas()));
90 #ifdef UART
91 NTSTATUS ntStatus;
92
93 (*UartResourceList) = NULL;
94 #endif
95
96 if ((ResourceList->NumberOfPorts() == 0) || (ResourceList->NumberOfPorts() > 2) || (ResourceList->NumberOfInterrupts() != 1) || (ResourceList->NumberOfDmas() != 0)) {
97 DBGPRINT(("Unexpected configuration"));
98 return STATUS_DEVICE_CONFIGURATION_ERROR;
99 }
100
101 #ifdef UART
102 ntStatus = PcNewResourceSublist(UartResourceList, NULL, PagedPool, ResourceList, 2);
103 if (NT_SUCCESS(ntStatus)) {
104 (*UartResourceList)->AddPortFromParent(ResourceList, 1);
105 (*UartResourceList)->AddInterruptFromParent(ResourceList, 0);
106 }
107 #endif
108
109 return STATUS_SUCCESS;
110 }
111
112
113 NTSTATUS
114 NTAPI
115 StartDevice(PDEVICE_OBJECT DeviceObject, PIRP Irp, PRESOURCELIST ResourceList)
116 {
117 PAGED_CODE();
118 ASSERT(DeviceObject);
119 ASSERT(Irp);
120 ASSERT(ResourceList);
121 DBGPRINT(("StartDevice()"));
122
123 NTSTATUS ntStatus;
124 PPORT pPort = 0;
125 #ifdef UART
126 ULONG* MPUBase;
127 #endif
128
129 ntStatus = PcNewPort(&pPort,CLSID_PortWaveCyclic);
130 if (NT_SUCCESS(ntStatus)) {
131 // not supported in the first edition of win98
132 PPORTEVENTS pPortEvents = 0;
133 ntStatus = pPort->QueryInterface(IID_IPortEvents, (PVOID *)&pPortEvents);
134 if (!NT_SUCCESS(ntStatus)) {
135 DBGPRINT(("ERROR: This driver doesn't work under Win98!"));
136 ntStatus = STATUS_UNSUCCESSFUL;
137 }
138 else
139 {
140 pPortEvents->Release();
141 }
142 pPort->Release ();
143 } else {
144 return ntStatus;
145 }
146
147 // resource validation
148 PRESOURCELIST UartResourceList = NULL;
149 ntStatus = ProcessResources(ResourceList, &UartResourceList);
150 if (!NT_SUCCESS(ntStatus)) {
151 DBGPRINT(("ProcessResources() failed"));
152 return ntStatus;
153 }
154
155 PCMIADAPTER pCMIAdapter = NULL;
156 PUNKNOWN pUnknownCommon = NULL;
157
158 // create the CMIAdapter object
159 ntStatus = NewCMIAdapter(&pUnknownCommon, IID_ICMIAdapter, NULL, NonPagedPool);
160 if (!NT_SUCCESS(ntStatus)) {
161 DBGPRINT(("NewCMIAdapter() failed"));
162 return ntStatus;
163 }
164
165 ntStatus = pUnknownCommon->QueryInterface(IID_ICMIAdapter, (PVOID *)&pCMIAdapter);
166 if (!NT_SUCCESS(ntStatus)) {
167 DBGPRINT(("QueryInterface() for ICMIAdapter failed"));
168 return ntStatus;
169 }
170 ntStatus = pCMIAdapter->init(ResourceList, DeviceObject);
171 if (!NT_SUCCESS(ntStatus)) {
172 DBGPRINT(("CMIAdapter->init() failed"));
173 return ntStatus;
174 }
175
176 ntStatus = PcRegisterAdapterPowerManagement((PUNKNOWN)pCMIAdapter, DeviceObject);
177
178 pUnknownCommon->Release();
179
180 PUNKNOWN unknownWave = NULL;
181 PUNKNOWN unknownTopology = NULL;
182
183 // install the topology miniport.
184 ntStatus = InstallSubdevice(DeviceObject, Irp, L"Topology", CLSID_PortTopology, CLSID_PortTopology, CreateMiniportTopologyCMI, pCMIAdapter, NULL, GUID_NULL, &unknownTopology);
185 if (!NT_SUCCESS (ntStatus)) {
186 DBGPRINT(("Topology miniport installation failed"));
187 return ntStatus;
188 }
189
190 #ifdef UART
191 // install the UART miniport - execution order important
192 ntStatus = STATUS_UNSUCCESSFUL;
193 MPUBase = 0;
194 for (int i=0;i<ResourceList->NumberOfPorts();i++) {
195 if (ResourceList->FindTranslatedPort(i)->u.Port.Length == 2) {
196 MPUBase = (UInt32*)ResourceList->FindTranslatedPort(i)->u.Port.Start.QuadPart;
197 }
198 }
199 if (MPUBase != 0) {
200 ntStatus = pCMIAdapter->activateMPU(MPUBase);
201 if (NT_SUCCESS(ntStatus)) {
202 ntStatus = InstallSubdevice(DeviceObject, Irp, L"Uart", CLSID_PortDMus, CLSID_MiniportDriverDMusUART, NULL, pCMIAdapter->getInterruptSync(), UartResourceList, IID_IPortDMus, NULL);
203 }
204 }
205 if (!NT_SUCCESS(ntStatus)) {
206 MPUBase = 0;
207 pCMIAdapter->activateMPU(0);
208 DBGPRINT(("UART miniport installation failed"));
209 }
210 if (UartResourceList) {
211 UartResourceList->Release();
212 }
213 #endif
214
215 // install the wave miniport - the order matters here
216 #ifdef WAVERT
217 ntStatus = InstallSubdevice(DeviceObject, Irp, L"Wave", CLSID_PortWaveRT, CLSID_PortWaveRT, CreateMiniportWaveCMI, pCMIAdapter, ResourceList, IID_IPortWaveRT, &unknownWave);
218 #else
219 ntStatus = InstallSubdevice(DeviceObject, Irp, L"Wave", CLSID_PortWaveCyclic, CLSID_PortWaveCyclic, CreateMiniportWaveCMI, pCMIAdapter, ResourceList, IID_IPortWaveCyclic, &unknownWave);
220 #endif
221 if (!NT_SUCCESS(ntStatus)) {
222 DBGPRINT(("Wave miniport installation failed"));
223 return ntStatus;
224 }
225
226 // connect wave and topology pins
227 ntStatus = PcRegisterPhysicalConnection(DeviceObject, unknownWave, PIN_WAVE_RENDER_SOURCE, unknownTopology, PIN_WAVEOUT_SOURCE);
228 if (!NT_SUCCESS(ntStatus)) {
229 DBGPRINT(("Cannot connect topology and wave miniport (render)!"));
230 return ntStatus;
231 }
232 ntStatus = PcRegisterPhysicalConnection(DeviceObject, unknownTopology, PIN_WAVEIN_DEST, unknownWave, PIN_WAVE_CAPTURE_SOURCE);
233 if (!NT_SUCCESS(ntStatus)) {
234 DBGPRINT(("Cannot connect topology and wave miniport (capture)!"));
235 return ntStatus;
236 }
237 if (!IoIsWdmVersionAvailable(6,0)) {
238 // this shit fixes the fucking XP mixer and breaks the vista mixer, so we have to check for vista here
239 ntStatus = PcRegisterPhysicalConnection(DeviceObject, unknownWave, PIN_WAVE_AC3_RENDER_SOURCE, unknownTopology, PIN_SPDIF_AC3_SOURCE);
240 if (!NT_SUCCESS(ntStatus)) {
241 DBGPRINT(("Cannot connect topology and wave miniport (ac3)!"));
242 }
243 }
244
245 // clean up
246 if (pCMIAdapter) {
247 pCMIAdapter->Release();
248 }
249 if (unknownTopology) {
250 unknownTopology->Release();
251 }
252 if (unknownWave) {
253 unknownWave->Release();
254 }
255
256 return ntStatus;
257 }
258
259 extern "C" NTSTATUS NTAPI AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject)
260 {
261 PAGED_CODE();
262 DBGPRINT(("AddDevice()"));
263
264 return PcAddAdapterDevice(DriverObject, PhysicalDeviceObject, StartDevice, MAX_MINIPORTS, 0);
265 }
266
267 static
268 bool
269 CopyResourceDescriptor(PIO_RESOURCE_DESCRIPTOR pInResDescriptor, PIO_RESOURCE_DESCRIPTOR pOutResDescriptor)
270 {
271 PAGED_CODE();
272 ASSERT(pInResDescriptor);
273 ASSERT(pOutResDescriptor);
274 DBGPRINT(("CopyResourceDescriptor()"));
275
276 #if 0
277 RtlCopyMemory(pOutResDescriptor, pInResDescriptor, sizeof(IO_RESOURCE_DESCRIPTOR));
278 #else
279 pOutResDescriptor->Type = pInResDescriptor->Type;
280 pOutResDescriptor->ShareDisposition = pInResDescriptor->ShareDisposition;
281 pOutResDescriptor->Flags = pInResDescriptor->Flags;
282 pOutResDescriptor->Option = pInResDescriptor->Option;
283
284 switch (pInResDescriptor->Type) {
285 case CmResourceTypePort:
286 case CmResourceTypePort | CmResourceTypeNonArbitrated: // huh?
287 /* // filter crap
288 if ((pInResDescriptor->u.Port.Length == 0) ||
289 ( (pInResDescriptor->u.Port.MinimumAddress.HighPart == pInResDescriptor->u.Port.MaximumAddress.HighPart) && (pInResDescriptor->u.Port.MinimumAddress.LowPart == pInResDescriptor->u.Port.MaximumAddress.LowPart) ) ) {
290 return FALSE;
291 }
292 */ pOutResDescriptor->u.Port.MinimumAddress = pInResDescriptor->u.Port.MinimumAddress;
293 pOutResDescriptor->u.Port.MaximumAddress = pInResDescriptor->u.Port.MaximumAddress;
294 pOutResDescriptor->u.Port.Length = pInResDescriptor->u.Port.Length;
295 pOutResDescriptor->u.Port.Alignment = pInResDescriptor->u.Port.Alignment;
296 DBGPRINT((" Port: min %08x.%08x max %08x.%08x, Length: %x, Option: %x", pOutResDescriptor->u.Port.MinimumAddress.HighPart, pOutResDescriptor->u.Port.MinimumAddress.LowPart,
297 pOutResDescriptor->u.Port.MaximumAddress.HighPart, pOutResDescriptor->u.Port.MaximumAddress.LowPart,
298 pOutResDescriptor->u.Port.Length, pOutResDescriptor->Option));
299 break;
300 case CmResourceTypeInterrupt:
301 pOutResDescriptor->u.Interrupt.MinimumVector = pInResDescriptor->u.Interrupt.MinimumVector;
302 pOutResDescriptor->u.Interrupt.MaximumVector = pInResDescriptor->u.Interrupt.MaximumVector;
303 DBGPRINT((" IRQ: min %x max %x, Option: %d", pOutResDescriptor->u.Interrupt.MinimumVector, pOutResDescriptor->u.Interrupt.MaximumVector, pOutResDescriptor->Option));
304 break;
305 default:
306 return FALSE;
307 }
308 return TRUE;
309 #endif
310 }
311
312 extern "C" NTSTATUS NTAPI AdapterDispatchPnp(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
313 {
314 PAGED_CODE();
315 ASSERT(pDeviceObject);
316 ASSERT(pIrp);
317 DBGPRINT(("AdapterDispatchPnp()"));
318
319 NTSTATUS ntStatus = STATUS_SUCCESS;
320 ULONG resourceListSize;
321 PIO_RESOURCE_REQUIREMENTS_LIST resourceList, list;
322 PIO_RESOURCE_DESCRIPTOR descriptor;
323 PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
324
325 if (pIrpStack->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS) {
326 DBGPRINT(("[AdapterDispatchPnp] - IRP_MN_FILTER_RESOURCE_REQUIREMENTS"));
327
328 list = (PIO_RESOURCE_REQUIREMENTS_LIST)pIrp->IoStatus.Information;
329
330 // IO_RESOURCE_REQUIREMENTS_LIST has 1 IO_RESOURCE_LIST, IO_RESOURCE_LIST has 1 IO_RESOURCE_DESCRIPTOR and we want 2 more
331 resourceListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + sizeof(IO_RESOURCE_DESCRIPTOR)*(list->List[0].Count+2) ;
332 resourceList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePoolWithTag(PagedPool, resourceListSize, 'LRDV');
333
334 if (!resourceList) {
335 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
336 return ntStatus;
337 }
338
339
340 RtlZeroMemory(resourceList, resourceListSize);
341
342 // initialize the list header
343 resourceList->AlternativeLists = 1; // number of IO_RESOURCE_LISTs
344 resourceList->ListSize = resourceListSize;
345
346 resourceList->List[0].Version = 1;
347 resourceList->List[0].Revision = 1;
348 resourceList->List[0].Count = 0;
349
350 // copy the resources which have already been assigned
351 for (unsigned int i=0;i<list->List[0].Count;i++) {
352 if (CopyResourceDescriptor(&list->List[0].Descriptors[i], &resourceList->List[0].Descriptors[resourceList->List[0].Count])) {
353 resourceList->List[0].Count++;
354 }
355 }
356 ExFreePool(list);
357
358 // an additional port for mpu401
359 resourceList->List[0].Count++;
360 descriptor = &resourceList->List[0].Descriptors[resourceList->List[0].Count-1];
361 descriptor->Option = IO_RESOURCE_PREFERRED;
362 descriptor->Type = CmResourceTypePort;
363 descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
364 descriptor->Flags = CM_RESOURCE_PORT_IO;
365 descriptor->u.Port.MinimumAddress.LowPart = 0x300;
366 descriptor->u.Port.MinimumAddress.HighPart = 0;
367 descriptor->u.Port.MaximumAddress.LowPart = 0x330;
368 descriptor->u.Port.MaximumAddress.HighPart = 0;
369 descriptor->u.Port.Length = 2;
370 descriptor->u.Port.Alignment = 0x10;
371
372 // mpu401 port should be optional. yes, this is severely braindamaged.
373 resourceList->List[0].Count++;
374 descriptor = &resourceList->List[0].Descriptors[resourceList->List[0].Count-1];
375 descriptor->Option = IO_RESOURCE_ALTERNATIVE;
376 descriptor->Type = CmResourceTypePort;
377 descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
378 descriptor->Flags = CM_RESOURCE_PORT_IO;
379 descriptor->u.Port.MinimumAddress.LowPart = 0x0;
380 descriptor->u.Port.MinimumAddress.HighPart = 0;
381 descriptor->u.Port.MaximumAddress.LowPart = 0xFFFF;
382 descriptor->u.Port.MaximumAddress.HighPart = 0;
383 descriptor->u.Port.Length = 1;
384 descriptor->u.Port.Alignment = 0x10;
385
386 DBGPRINT(("number of resource list descriptors: %d", resourceList->List[0].Count));
387
388 pIrp->IoStatus.Information = (ULONG_PTR)resourceList;
389
390 // set the return status
391 pIrp->IoStatus.Status = ntStatus;
392 }
393
394 // Pass the IRPs on to PortCls
395 ntStatus = PcDispatchIrp(pDeviceObject, pIrp);
396
397 return ntStatus;
398 }
399
400 extern "C"
401 NTSTATUS
402 NTAPI
403 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPathName)
404 {
405 PAGED_CODE();
406 DBGPRINT(("DriverEntry()"));
407
408 NTSTATUS ntStatus;
409
410 //bind the adapter driver to the portclass driver
411 ntStatus = PcInitializeAdapterDriver(DriverObject, RegistryPathName, AddDevice);
412 #ifdef UART
413 if(NT_SUCCESS(ntStatus)) {
414 DriverObject->MajorFunction[IRP_MJ_PNP] = AdapterDispatchPnp;
415 }
416 #endif
417 #ifdef WAVERT
418 if (!IoIsWdmVersionAvailable(6,0)) {
419 ntStatus = STATUS_UNSUCCESSFUL;
420 }
421 #endif
422
423 return ntStatus;
424 }
425
426 #ifdef _MSC_VER
427 #pragma code_seg()
428 #endif
429 int __cdecl _purecall (void)
430 {
431 return 0;
432 }