www.pudn.com > CMIDriver-1.1.1-src.zip > adapter.cpp
/* Copyright (c) 2006-2007 dogbertAll rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define PUT_GUIDS_HERE #include "adapter.hpp" #pragma code_seg("PAGE") NTSTATUS InstallSubdevice(PDEVICE_OBJECT DeviceObject, PIRP Irp, PWCHAR Name, REFGUID PortClassId, REFGUID MiniportClassId, PFNCREATEINSTANCE MiniportCreate, PUNKNOWN UnknownAdapter, PRESOURCELIST ResourceList, REFGUID PortInterfaceId, PUNKNOWN* OutPortUnknown) { PAGED_CODE(); DBGPRINT(("InstallSubdevice()")); NTSTATUS ntStatus; PPORT Port; PMINIPORT MiniPort; ntStatus = PcNewPort(&Port, PortClassId); if (NT_SUCCESS(ntStatus)) { if (MiniportCreate) { ntStatus = MiniportCreate((PUNKNOWN*)&MiniPort, MiniportClassId, NULL, NonPagedPool); } else { ntStatus = PcNewMiniport(&MiniPort, MiniportClassId); } } if (!NT_SUCCESS(ntStatus)) { Port->Release(); return ntStatus; } ntStatus = Port->Init(DeviceObject, Irp, MiniPort, UnknownAdapter, ResourceList); if (NT_SUCCESS(ntStatus)) { ntStatus = PcRegisterSubdevice(DeviceObject, Name, Port); if (OutPortUnknown && NT_SUCCESS (ntStatus)) { ntStatus = Port->QueryInterface(IID_IUnknown, (PVOID *)OutPortUnknown); } } if (MiniPort) { MiniPort->Release(); } if (Port) { Port->Release(); } return ntStatus; } NTSTATUS ProcessResources(PRESOURCELIST ResourceList, PRESOURCELIST* UartResourceList) { PAGED_CODE(); ASSERT(ResourceList); ASSERT(UartResourceList); DBGPRINT(("ProcessResources()")); DBGPRINT(("NumberOfPorts: %d, NumberOfInterrupts: %d, NumberOfDmas: %d", ResourceList->NumberOfPorts(), ResourceList->NumberOfInterrupts(), ResourceList->NumberOfDmas())); #ifdef UART (*UartResourceList) = NULL; #endif NTSTATUS ntStatus; if ((ResourceList->NumberOfPorts() == 0) || (ResourceList->NumberOfPorts() > 2) || (ResourceList->NumberOfInterrupts() != 1) || (ResourceList->NumberOfDmas() != 0)) { DBGPRINT(("Unexpected configuration")); return STATUS_DEVICE_CONFIGURATION_ERROR; } #ifdef UART ntStatus = PcNewResourceSublist(UartResourceList, NULL, PagedPool, ResourceList, 2); if (NT_SUCCESS(ntStatus)) { (*UartResourceList)->AddPortFromParent(ResourceList, 1); (*UartResourceList)->AddInterruptFromParent(ResourceList, 0); } #endif return STATUS_SUCCESS; } NTSTATUS StartDevice(PDEVICE_OBJECT DeviceObject, PIRP Irp, PRESOURCELIST ResourceList) { PAGED_CODE(); ASSERT(DeviceObject); ASSERT(Irp); ASSERT(ResourceList); DBGPRINT(("StartDevice()")); NTSTATUS ntStatus; PPORT pPort = 0; ULONG* MPUBase; ntStatus = PcNewPort(&pPort,CLSID_PortWaveCyclic); if (NT_SUCCESS(ntStatus)) { // not supported in the first edition of win98 PPORTEVENTS pPortEvents = 0; ntStatus = pPort->QueryInterface(IID_IPortEvents, (PVOID *)&pPortEvents); if (!NT_SUCCESS(ntStatus)) { DBGPRINT(("ERROR: This driver doesn't work under Win98!")); ntStatus = STATUS_UNSUCCESSFUL; } else { pPortEvents->Release(); } pPort->Release (); } else { return ntStatus; } // resource validation PRESOURCELIST UartResourceList = NULL; ntStatus = ProcessResources(ResourceList, &UartResourceList); if (!NT_SUCCESS(ntStatus)) { DBGPRINT(("ProcessResources() failed")); return ntStatus; } PCMIADAPTER pCMIAdapter = NULL; PUNKNOWN pUnknownCommon = NULL; // create the CMIAdapter object ntStatus = NewCMIAdapter(&pUnknownCommon, IID_ICMIAdapter, NULL, NonPagedPool); if (!NT_SUCCESS(ntStatus)) { DBGPRINT(("NewCMIAdapter() failed")); return ntStatus; } ntStatus = pUnknownCommon->QueryInterface(IID_ICMIAdapter, (PVOID *)&pCMIAdapter); if (!NT_SUCCESS(ntStatus)) { DBGPRINT(("QueryInterface() for ICMIAdapter failed")); return ntStatus; } ntStatus = pCMIAdapter->init(ResourceList, DeviceObject); if (!NT_SUCCESS(ntStatus)) { DBGPRINT(("CMIAdapter->init() failed")); return ntStatus; } #ifdef POWERMANAGEMENT ntStatus = PcRegisterAdapterPowerManagement((PUNKNOWN)pCMIAdapter, DeviceObject); #endif pUnknownCommon->Release(); PUNKNOWN unknownWave = NULL; PUNKNOWN unknownTopology = NULL; // install the topology miniport. ntStatus = InstallSubdevice(DeviceObject, Irp, L"Topology", CLSID_PortTopology, CLSID_PortTopology, CreateMiniportTopologyCMI, pCMIAdapter, NULL, GUID_NULL, &unknownTopology); if (!NT_SUCCESS (ntStatus)) { DBGPRINT(("Topology miniport installation failed")); return ntStatus; } #ifdef UART // install the UART miniport - execution order important ntStatus = STATUS_UNSUCCESSFUL; MPUBase = 0; for (int i=0;i NumberOfPorts();i++) { if (ResourceList->FindTranslatedPort(i)->u.Port.Length == 2) { MPUBase = (UInt32*)ResourceList->FindTranslatedPort(i)->u.Port.Start.QuadPart; } } if (MPUBase != 0) { ntStatus = pCMIAdapter->activateMPU(MPUBase); if (NT_SUCCESS(ntStatus)) { ntStatus = InstallSubdevice(DeviceObject, Irp, L"Uart", CLSID_PortDMus, CLSID_MiniportDriverDMusUART, NULL, pCMIAdapter->getInterruptSync(), UartResourceList, IID_IPortDMus, NULL); } } if (!NT_SUCCESS(ntStatus)) { MPUBase = 0; pCMIAdapter->activateMPU(0); DBGPRINT(("UART miniport installation failed")); } if (UartResourceList) { UartResourceList->Release(); } #endif // install the wave miniport - the order matters here #ifdef WAVERT ntStatus = InstallSubdevice(DeviceObject, Irp, L"Wave", CLSID_PortWaveRT, CLSID_PortWaveRT, CreateMiniportWaveCMI, pCMIAdapter, ResourceList, IID_IPortWaveRT, &unknownWave); #else ntStatus = InstallSubdevice(DeviceObject, Irp, L"Wave", CLSID_PortWaveCyclic, CLSID_PortWaveCyclic, CreateMiniportWaveCMI, pCMIAdapter, ResourceList, IID_IPortWaveCyclic, &unknownWave); #endif if (!NT_SUCCESS(ntStatus)) { DBGPRINT(("Wave miniport installation failed")); return ntStatus; } // connect wave and topology pins ntStatus = PcRegisterPhysicalConnection(DeviceObject, unknownWave, PIN_WAVE_RENDER_SOURCE, unknownTopology, PIN_WAVEOUT_SOURCE); if (!NT_SUCCESS(ntStatus)) { DBGPRINT(("Cannot connect topology and wave miniport (render)!")); return ntStatus; } ntStatus = PcRegisterPhysicalConnection(DeviceObject, unknownTopology, PIN_WAVEIN_DEST, unknownWave, PIN_WAVE_CAPTURE_SOURCE); if (!NT_SUCCESS(ntStatus)) { DBGPRINT(("Cannot connect topology and wave miniport (capture)!")); return ntStatus; } if (!IoIsWdmVersionAvailable(6,0)) { // this shit fixes the fucking XP mixer and breaks the vista mixer, so we have to check for vista here ntStatus = PcRegisterPhysicalConnection(DeviceObject, unknownWave, PIN_WAVE_AC3_RENDER_SOURCE, unknownTopology, PIN_SPDIF_AC3_SOURCE); if (!NT_SUCCESS(ntStatus)) { DBGPRINT(("Cannot connect topology and wave miniport (ac3)!")); } } // clean up if (pCMIAdapter) { pCMIAdapter->Release(); } if (unknownTopology) { unknownTopology->Release(); } if (unknownWave) { unknownWave->Release(); } return ntStatus; } extern "C" NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject) { PAGED_CODE(); DBGPRINT(("AddDevice()")); return PcAddAdapterDevice(DriverObject, PhysicalDeviceObject, (PCPFNSTARTDEVICE)StartDevice, MAX_MINIPORTS, 0); } bool CopyResourceDescriptor(PIO_RESOURCE_DESCRIPTOR pInResDescriptor, PIO_RESOURCE_DESCRIPTOR pOutResDescriptor) { PAGED_CODE(); ASSERT(pInResDescriptor); ASSERT(pOutResDescriptor); DBGPRINT(("CopyResourceDescriptor()")); #if 0 RtlCopyMemory(pOutResDescriptor, pInResDescriptor, sizeof(IO_RESOURCE_DESCRIPTOR)); #else pOutResDescriptor->Type = pInResDescriptor->Type; pOutResDescriptor->ShareDisposition = pInResDescriptor->ShareDisposition; pOutResDescriptor->Flags = pInResDescriptor->Flags; pOutResDescriptor->Option = pInResDescriptor->Option; switch (pInResDescriptor->Type) { case CmResourceTypePort: case CmResourceTypePort | CmResourceTypeNonArbitrated: // huh? /* // filter crap if ((pInResDescriptor->u.Port.Length == 0) || ( (pInResDescriptor->u.Port.MinimumAddress.HighPart == pInResDescriptor->u.Port.MaximumAddress.HighPart) && (pInResDescriptor->u.Port.MinimumAddress.LowPart == pInResDescriptor->u.Port.MaximumAddress.LowPart) ) ) { return FALSE; } */ pOutResDescriptor->u.Port.MinimumAddress = pInResDescriptor->u.Port.MinimumAddress; pOutResDescriptor->u.Port.MaximumAddress = pInResDescriptor->u.Port.MaximumAddress; pOutResDescriptor->u.Port.Length = pInResDescriptor->u.Port.Length; pOutResDescriptor->u.Port.Alignment = pInResDescriptor->u.Port.Alignment; DBGPRINT((" Port: min %08x.%08x max %08x.%08x, Length: %x, Option: %x", pOutResDescriptor->u.Port.MinimumAddress.HighPart, pOutResDescriptor->u.Port.MinimumAddress.LowPart, pOutResDescriptor->u.Port.MaximumAddress.HighPart, pOutResDescriptor->u.Port.MaximumAddress.LowPart, pOutResDescriptor->u.Port.Length, pOutResDescriptor->Option)); break; case CmResourceTypeInterrupt: pOutResDescriptor->u.Interrupt.MinimumVector = pInResDescriptor->u.Interrupt.MinimumVector; pOutResDescriptor->u.Interrupt.MaximumVector = pInResDescriptor->u.Interrupt.MaximumVector; DBGPRINT((" IRQ: min %x max %x, Option: %d", pOutResDescriptor->u.Interrupt.MinimumVector, pOutResDescriptor->u.Interrupt.MaximumVector, pOutResDescriptor->Option)); break; default: return FALSE; } return TRUE; #endif } extern "C" NTSTATUS AdapterDispatchPnp(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { PAGED_CODE(); ASSERT(pDeviceObject); ASSERT(pIrp); DBGPRINT(("AdapterDispatchPnp()")); NTSTATUS ntStatus = STATUS_SUCCESS; ULONG resourceListSize; PIO_RESOURCE_REQUIREMENTS_LIST resourceList, list; PIO_RESOURCE_DESCRIPTOR descriptor; PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp); if (pIrpStack->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS) { DBGPRINT(("[AdapterDispatchPnp] - IRP_MN_FILTER_RESOURCE_REQUIREMENTS")); list = (PIO_RESOURCE_REQUIREMENTS_LIST)pIrp->IoStatus.Information; // IO_RESOURCE_REQUIREMENTS_LIST has 1 IO_RESOURCE_LIST, IO_RESOURCE_LIST has 1 IO_RESOURCE_DESCRIPTOR and we want 2 more resourceListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + sizeof(IO_RESOURCE_DESCRIPTOR)*(list->List[0].Count+2) ; resourceList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePoolWithTag(PagedPool, resourceListSize, 'LRDV'); if (!resourceList) { ntStatus = STATUS_INSUFFICIENT_RESOURCES; return ntStatus; } RtlZeroMemory(resourceList, resourceListSize); // initialize the list header resourceList->AlternativeLists = 1; // number of IO_RESOURCE_LISTs resourceList->ListSize = resourceListSize; resourceList->List[0].Version = 1; resourceList->List[0].Revision = 1; resourceList->List[0].Count = 0; // copy the resources which have already been assigned for (int i=0;i List[0].Count;i++) { if (CopyResourceDescriptor(&list->List[0].Descriptors[i], &resourceList->List[0].Descriptors[resourceList->List[0].Count])) { resourceList->List[0].Count++; } } ExFreePool(list); // an additional port for mpu401 resourceList->List[0].Count++; descriptor = &resourceList->List[0].Descriptors[resourceList->List[0].Count-1]; descriptor->Option = IO_RESOURCE_PREFERRED; descriptor->Type = CmResourceTypePort; descriptor->ShareDisposition = CmResourceShareDeviceExclusive; descriptor->Flags = CM_RESOURCE_PORT_IO; descriptor->u.Port.MinimumAddress.LowPart = 0x300; descriptor->u.Port.MinimumAddress.HighPart = 0; descriptor->u.Port.MaximumAddress.LowPart = 0x330; descriptor->u.Port.MaximumAddress.HighPart = 0; descriptor->u.Port.Length = 2; descriptor->u.Port.Alignment = 0x10; // mpu401 port should be optional. yes, this is severely braindamaged. resourceList->List[0].Count++; descriptor = &resourceList->List[0].Descriptors[resourceList->List[0].Count-1]; descriptor->Option = IO_RESOURCE_ALTERNATIVE; descriptor->Type = CmResourceTypePort; descriptor->ShareDisposition = CmResourceShareDeviceExclusive; descriptor->Flags = CM_RESOURCE_PORT_IO; descriptor->u.Port.MinimumAddress.LowPart = 0x0; descriptor->u.Port.MinimumAddress.HighPart = 0; descriptor->u.Port.MaximumAddress.LowPart = 0xFFFF; descriptor->u.Port.MaximumAddress.HighPart = 0; descriptor->u.Port.Length = 1; descriptor->u.Port.Alignment = 0x10; DBGPRINT(("number of resource list descriptors: %d", resourceList->List[0].Count)); pIrp->IoStatus.Information = (ULONG_PTR)resourceList; // set the return status pIrp->IoStatus.Status = ntStatus; } // Pass the IRPs on to PortCls ntStatus = PcDispatchIrp(pDeviceObject, pIrp); return ntStatus; } extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPathName) { PAGED_CODE(); DBGPRINT(("DriverEntry()")); NTSTATUS ntStatus; //bind the adapter driver to the portclass driver ntStatus = PcInitializeAdapterDriver(DriverObject, RegistryPathName, AddDevice); #ifdef UART if(NT_SUCCESS(ntStatus)) { DriverObject->MajorFunction[IRP_MJ_PNP] = AdapterDispatchPnp; } #endif #ifdef WAVERT if (!IoIsWdmVersionAvailable(6,0)) { ntStatus = STATUS_UNSUCCESSFUL; } #endif return ntStatus; } #pragma code_seg() int __cdecl _purecall (void) { return 0; }