2 Copyright (c) 2006-2008 dogbert <dogber1@gmail.com>
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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.
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.
28 #define PUT_GUIDS_HERE
30 #include "adapter.hpp"
33 #pragma code_seg("PAGE")
36 NTSTATUS
InstallSubdevice(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PWCHAR Name
, REFGUID PortClassId
, REFGUID MiniportClassId
, PFNCREATEINSTANCE MiniportCreate
, PUNKNOWN UnknownAdapter
, PRESOURCELIST ResourceList
, REFGUID PortInterfaceId
, PUNKNOWN
* OutPortUnknown
)
39 DBGPRINT(("InstallSubdevice()"));
45 ntStatus
= PcNewPort(&Port
, PortClassId
);
46 if (NT_SUCCESS(ntStatus
)) {
48 ntStatus
= MiniportCreate((PUNKNOWN
*)&MiniPort
, MiniportClassId
, NULL
, NonPagedPool
);
50 ntStatus
= PcNewMiniport(&MiniPort
, MiniportClassId
);
54 if (!NT_SUCCESS(ntStatus
)) {
59 ntStatus
= Port
->Init(DeviceObject
, Irp
, MiniPort
, UnknownAdapter
, ResourceList
);
60 if (NT_SUCCESS(ntStatus
)) {
61 ntStatus
= PcRegisterSubdevice(DeviceObject
, Name
, Port
);
63 if (OutPortUnknown
&& NT_SUCCESS (ntStatus
)) {
64 ntStatus
= Port
->QueryInterface(IID_IUnknown
, (PVOID
*)OutPortUnknown
);
80 NTSTATUS
ProcessResources(PRESOURCELIST ResourceList
, PRESOURCELIST
* UartResourceList
)
84 ASSERT(UartResourceList
);
85 DBGPRINT(("ProcessResources()"));
86 DBGPRINT(("NumberOfPorts: %d, NumberOfInterrupts: %d, NumberOfDmas: %d", ResourceList
->NumberOfPorts(), ResourceList
->NumberOfInterrupts(), ResourceList
->NumberOfDmas()));
90 (*UartResourceList
) = NULL
;
93 if ((ResourceList
->NumberOfPorts() == 0) || (ResourceList
->NumberOfPorts() > 2) || (ResourceList
->NumberOfInterrupts() != 1) || (ResourceList
->NumberOfDmas() != 0)) {
94 DBGPRINT(("Unexpected configuration"));
95 return STATUS_DEVICE_CONFIGURATION_ERROR
;
99 ntStatus
= PcNewResourceSublist(UartResourceList
, NULL
, PagedPool
, ResourceList
, 2);
100 if (NT_SUCCESS(ntStatus
)) {
101 (*UartResourceList
)->AddPortFromParent(ResourceList
, 1);
102 (*UartResourceList
)->AddInterruptFromParent(ResourceList
, 0);
106 return STATUS_SUCCESS
;
110 NTSTATUS
StartDevice(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PRESOURCELIST ResourceList
)
113 ASSERT(DeviceObject
);
115 ASSERT(ResourceList
);
116 DBGPRINT(("StartDevice()"));
124 ntStatus
= PcNewPort(&pPort
,CLSID_PortWaveCyclic
);
125 if (NT_SUCCESS(ntStatus
)) {
126 // not supported in the first edition of win98
127 PPORTEVENTS pPortEvents
= 0;
128 ntStatus
= pPort
->QueryInterface(IID_IPortEvents
, (PVOID
*)&pPortEvents
);
129 if (!NT_SUCCESS(ntStatus
)) {
130 DBGPRINT(("ERROR: This driver doesn't work under Win98!"));
131 ntStatus
= STATUS_UNSUCCESSFUL
;
135 pPortEvents
->Release();
142 // resource validation
143 PRESOURCELIST UartResourceList
= NULL
;
144 ntStatus
= ProcessResources(ResourceList
, &UartResourceList
);
145 if (!NT_SUCCESS(ntStatus
)) {
146 DBGPRINT(("ProcessResources() failed"));
150 PCMIADAPTER pCMIAdapter
= NULL
;
151 PUNKNOWN pUnknownCommon
= NULL
;
153 // create the CMIAdapter object
154 ntStatus
= NewCMIAdapter(&pUnknownCommon
, IID_ICMIAdapter
, NULL
, NonPagedPool
);
155 if (!NT_SUCCESS(ntStatus
)) {
156 DBGPRINT(("NewCMIAdapter() failed"));
160 ntStatus
= pUnknownCommon
->QueryInterface(IID_ICMIAdapter
, (PVOID
*)&pCMIAdapter
);
161 if (!NT_SUCCESS(ntStatus
)) {
162 DBGPRINT(("QueryInterface() for ICMIAdapter failed"));
165 ntStatus
= pCMIAdapter
->init(ResourceList
, DeviceObject
);
166 if (!NT_SUCCESS(ntStatus
)) {
167 DBGPRINT(("CMIAdapter->init() failed"));
171 ntStatus
= PcRegisterAdapterPowerManagement((PUNKNOWN
)pCMIAdapter
, DeviceObject
);
173 pUnknownCommon
->Release();
175 PUNKNOWN unknownWave
= NULL
;
176 PUNKNOWN unknownTopology
= NULL
;
178 // install the topology miniport.
179 ntStatus
= InstallSubdevice(DeviceObject
, Irp
, L
"Topology", CLSID_PortTopology
, CLSID_PortTopology
, CreateMiniportTopologyCMI
, pCMIAdapter
, NULL
, GUID_NULL
, &unknownTopology
);
180 if (!NT_SUCCESS (ntStatus
)) {
181 DBGPRINT(("Topology miniport installation failed"));
186 // install the UART miniport - execution order important
187 ntStatus
= STATUS_UNSUCCESSFUL
;
189 for (int i
=0;i
<ResourceList
->NumberOfPorts();i
++) {
190 if (ResourceList
->FindTranslatedPort(i
)->u
.Port
.Length
== 2) {
191 MPUBase
= (UInt32
*)ResourceList
->FindTranslatedPort(i
)->u
.Port
.Start
.QuadPart
;
195 ntStatus
= pCMIAdapter
->activateMPU(MPUBase
);
196 if (NT_SUCCESS(ntStatus
)) {
197 ntStatus
= InstallSubdevice(DeviceObject
, Irp
, L
"Uart", CLSID_PortDMus
, CLSID_MiniportDriverDMusUART
, NULL
, pCMIAdapter
->getInterruptSync(), UartResourceList
, IID_IPortDMus
, NULL
);
200 if (!NT_SUCCESS(ntStatus
)) {
202 pCMIAdapter
->activateMPU(0);
203 DBGPRINT(("UART miniport installation failed"));
205 if (UartResourceList
) {
206 UartResourceList
->Release();
210 // install the wave miniport - the order matters here
212 ntStatus
= InstallSubdevice(DeviceObject
, Irp
, L
"Wave", CLSID_PortWaveRT
, CLSID_PortWaveRT
, CreateMiniportWaveCMI
, pCMIAdapter
, ResourceList
, IID_IPortWaveRT
, &unknownWave
);
214 ntStatus
= InstallSubdevice(DeviceObject
, Irp
, L
"Wave", CLSID_PortWaveCyclic
, CLSID_PortWaveCyclic
, CreateMiniportWaveCMI
, pCMIAdapter
, ResourceList
, IID_IPortWaveCyclic
, &unknownWave
);
216 if (!NT_SUCCESS(ntStatus
)) {
217 DBGPRINT(("Wave miniport installation failed"));
221 // connect wave and topology pins
222 ntStatus
= PcRegisterPhysicalConnection(DeviceObject
, unknownWave
, PIN_WAVE_RENDER_SOURCE
, unknownTopology
, PIN_WAVEOUT_SOURCE
);
223 if (!NT_SUCCESS(ntStatus
)) {
224 DBGPRINT(("Cannot connect topology and wave miniport (render)!"));
227 ntStatus
= PcRegisterPhysicalConnection(DeviceObject
, unknownTopology
, PIN_WAVEIN_DEST
, unknownWave
, PIN_WAVE_CAPTURE_SOURCE
);
228 if (!NT_SUCCESS(ntStatus
)) {
229 DBGPRINT(("Cannot connect topology and wave miniport (capture)!"));
232 if (!IoIsWdmVersionAvailable(6,0)) {
233 // this shit fixes the fucking XP mixer and breaks the vista mixer, so we have to check for vista here
234 ntStatus
= PcRegisterPhysicalConnection(DeviceObject
, unknownWave
, PIN_WAVE_AC3_RENDER_SOURCE
, unknownTopology
, PIN_SPDIF_AC3_SOURCE
);
235 if (!NT_SUCCESS(ntStatus
)) {
236 DBGPRINT(("Cannot connect topology and wave miniport (ac3)!"));
242 pCMIAdapter
->Release();
244 if (unknownTopology
) {
245 unknownTopology
->Release();
248 unknownWave
->Release();
254 extern "C" NTSTATUS NTAPI
AddDevice(PDRIVER_OBJECT DriverObject
, PDEVICE_OBJECT PhysicalDeviceObject
)
257 DBGPRINT(("AddDevice()"));
259 return PcAddAdapterDevice(DriverObject
, PhysicalDeviceObject
, (PCPFNSTARTDEVICE
)StartDevice
, MAX_MINIPORTS
, 0);
262 bool CopyResourceDescriptor(PIO_RESOURCE_DESCRIPTOR pInResDescriptor
, PIO_RESOURCE_DESCRIPTOR pOutResDescriptor
)
265 ASSERT(pInResDescriptor
);
266 ASSERT(pOutResDescriptor
);
267 DBGPRINT(("CopyResourceDescriptor()"));
270 RtlCopyMemory(pOutResDescriptor
, pInResDescriptor
, sizeof(IO_RESOURCE_DESCRIPTOR
));
272 pOutResDescriptor
->Type
= pInResDescriptor
->Type
;
273 pOutResDescriptor
->ShareDisposition
= pInResDescriptor
->ShareDisposition
;
274 pOutResDescriptor
->Flags
= pInResDescriptor
->Flags
;
275 pOutResDescriptor
->Option
= pInResDescriptor
->Option
;
277 switch (pInResDescriptor
->Type
) {
278 case CmResourceTypePort
:
279 case CmResourceTypePort
| CmResourceTypeNonArbitrated
: // huh?
281 if ((pInResDescriptor->u.Port.Length == 0) ||
282 ( (pInResDescriptor->u.Port.MinimumAddress.HighPart == pInResDescriptor->u.Port.MaximumAddress.HighPart) && (pInResDescriptor->u.Port.MinimumAddress.LowPart == pInResDescriptor->u.Port.MaximumAddress.LowPart) ) ) {
285 */ pOutResDescriptor
->u
.Port
.MinimumAddress
= pInResDescriptor
->u
.Port
.MinimumAddress
;
286 pOutResDescriptor
->u
.Port
.MaximumAddress
= pInResDescriptor
->u
.Port
.MaximumAddress
;
287 pOutResDescriptor
->u
.Port
.Length
= pInResDescriptor
->u
.Port
.Length
;
288 pOutResDescriptor
->u
.Port
.Alignment
= pInResDescriptor
->u
.Port
.Alignment
;
289 DBGPRINT((" Port: min %08x.%08x max %08x.%08x, Length: %x, Option: %x", pOutResDescriptor
->u
.Port
.MinimumAddress
.HighPart
, pOutResDescriptor
->u
.Port
.MinimumAddress
.LowPart
,
290 pOutResDescriptor
->u
.Port
.MaximumAddress
.HighPart
, pOutResDescriptor
->u
.Port
.MaximumAddress
.LowPart
,
291 pOutResDescriptor
->u
.Port
.Length
, pOutResDescriptor
->Option
));
293 case CmResourceTypeInterrupt
:
294 pOutResDescriptor
->u
.Interrupt
.MinimumVector
= pInResDescriptor
->u
.Interrupt
.MinimumVector
;
295 pOutResDescriptor
->u
.Interrupt
.MaximumVector
= pInResDescriptor
->u
.Interrupt
.MaximumVector
;
296 DBGPRINT((" IRQ: min %x max %x, Option: %d", pOutResDescriptor
->u
.Interrupt
.MinimumVector
, pOutResDescriptor
->u
.Interrupt
.MaximumVector
, pOutResDescriptor
->Option
));
305 extern "C" NTSTATUS
AdapterDispatchPnp(PDEVICE_OBJECT pDeviceObject
, PIRP pIrp
)
308 ASSERT(pDeviceObject
);
310 DBGPRINT(("AdapterDispatchPnp()"));
312 NTSTATUS ntStatus
= STATUS_SUCCESS
;
313 ULONG resourceListSize
;
314 PIO_RESOURCE_REQUIREMENTS_LIST resourceList
, list
;
315 PIO_RESOURCE_DESCRIPTOR descriptor
;
316 PIO_STACK_LOCATION pIrpStack
= IoGetCurrentIrpStackLocation(pIrp
);
318 if (pIrpStack
->MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
) {
319 DBGPRINT(("[AdapterDispatchPnp] - IRP_MN_FILTER_RESOURCE_REQUIREMENTS"));
321 list
= (PIO_RESOURCE_REQUIREMENTS_LIST
)pIrp
->IoStatus
.Information
;
323 // IO_RESOURCE_REQUIREMENTS_LIST has 1 IO_RESOURCE_LIST, IO_RESOURCE_LIST has 1 IO_RESOURCE_DESCRIPTOR and we want 2 more
324 resourceListSize
= sizeof(IO_RESOURCE_REQUIREMENTS_LIST
) + sizeof(IO_RESOURCE_DESCRIPTOR
)*(list
->List
[0].Count
+2) ;
325 resourceList
= (PIO_RESOURCE_REQUIREMENTS_LIST
)ExAllocatePoolWithTag(PagedPool
, resourceListSize
, 'LRDV');
328 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
333 RtlZeroMemory(resourceList
, resourceListSize
);
335 // initialize the list header
336 resourceList
->AlternativeLists
= 1; // number of IO_RESOURCE_LISTs
337 resourceList
->ListSize
= resourceListSize
;
339 resourceList
->List
[0].Version
= 1;
340 resourceList
->List
[0].Revision
= 1;
341 resourceList
->List
[0].Count
= 0;
343 // copy the resources which have already been assigned
344 for (unsigned int i
=0;i
<list
->List
[0].Count
;i
++) {
345 if (CopyResourceDescriptor(&list
->List
[0].Descriptors
[i
], &resourceList
->List
[0].Descriptors
[resourceList
->List
[0].Count
])) {
346 resourceList
->List
[0].Count
++;
351 // an additional port for mpu401
352 resourceList
->List
[0].Count
++;
353 descriptor
= &resourceList
->List
[0].Descriptors
[resourceList
->List
[0].Count
-1];
354 descriptor
->Option
= IO_RESOURCE_PREFERRED
;
355 descriptor
->Type
= CmResourceTypePort
;
356 descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
357 descriptor
->Flags
= CM_RESOURCE_PORT_IO
;
358 descriptor
->u
.Port
.MinimumAddress
.LowPart
= 0x300;
359 descriptor
->u
.Port
.MinimumAddress
.HighPart
= 0;
360 descriptor
->u
.Port
.MaximumAddress
.LowPart
= 0x330;
361 descriptor
->u
.Port
.MaximumAddress
.HighPart
= 0;
362 descriptor
->u
.Port
.Length
= 2;
363 descriptor
->u
.Port
.Alignment
= 0x10;
365 // mpu401 port should be optional. yes, this is severely braindamaged.
366 resourceList
->List
[0].Count
++;
367 descriptor
= &resourceList
->List
[0].Descriptors
[resourceList
->List
[0].Count
-1];
368 descriptor
->Option
= IO_RESOURCE_ALTERNATIVE
;
369 descriptor
->Type
= CmResourceTypePort
;
370 descriptor
->ShareDisposition
= CmResourceShareDeviceExclusive
;
371 descriptor
->Flags
= CM_RESOURCE_PORT_IO
;
372 descriptor
->u
.Port
.MinimumAddress
.LowPart
= 0x0;
373 descriptor
->u
.Port
.MinimumAddress
.HighPart
= 0;
374 descriptor
->u
.Port
.MaximumAddress
.LowPart
= 0xFFFF;
375 descriptor
->u
.Port
.MaximumAddress
.HighPart
= 0;
376 descriptor
->u
.Port
.Length
= 1;
377 descriptor
->u
.Port
.Alignment
= 0x10;
379 DBGPRINT(("number of resource list descriptors: %d", resourceList
->List
[0].Count
));
381 pIrp
->IoStatus
.Information
= (ULONG_PTR
)resourceList
;
383 // set the return status
384 pIrp
->IoStatus
.Status
= ntStatus
;
387 // Pass the IRPs on to PortCls
388 ntStatus
= PcDispatchIrp(pDeviceObject
, pIrp
);
393 extern "C" NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPathName
)
396 DBGPRINT(("DriverEntry()"));
400 //bind the adapter driver to the portclass driver
401 ntStatus
= PcInitializeAdapterDriver(DriverObject
, RegistryPathName
, AddDevice
);
403 if(NT_SUCCESS(ntStatus
)) {
404 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = AdapterDispatchPnp
;
408 if (!IoIsWdmVersionAvailable(6,0)) {
409 ntStatus
= STATUS_UNSUCCESSFUL
;
419 int __cdecl
_purecall (void)