/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel Streaming * FILE: drivers/wdm/audio/legacy/stream/pnp.c * PURPOSE: pnp handling * PROGRAMMER: Johannes Anderwald */ #include "stream.h" VOID CompleteIrp( IN PIRP Irp, IN NTSTATUS Status, IN ULONG_PTR Information) { Irp->IoStatus.Status = Status; Irp->IoStatus.Information = Information; IoCompleteRequest(Irp, IO_NO_INCREMENT); } VOID NTAPI StreamClassReleaseResources( IN PDEVICE_OBJECT DeviceObject) { PSTREAM_DEVICE_EXTENSION DeviceExtension; PLIST_ENTRY Entry; PMEMORY_RESOURCE_LIST Mem; /* Get device extension */ DeviceExtension = (PSTREAM_DEVICE_EXTENSION)DeviceObject->DeviceExtension; /* Disconnect interrupt */ if (DeviceExtension->Interrupt) { IoDisconnectInterrupt(DeviceExtension->Interrupt); DeviceExtension->Interrupt = NULL; } /* Release DmaAdapter */ if (DeviceExtension->DmaAdapter) { DeviceExtension->DmaAdapter->DmaOperations->PutDmaAdapter(DeviceExtension->DmaAdapter); DeviceExtension->DmaAdapter = NULL; } /* Release mem mapped I/O */ while(!IsListEmpty(&DeviceExtension->MemoryResourceList)) { Entry = RemoveHeadList(&DeviceExtension->MemoryResourceList); Mem = (PMEMORY_RESOURCE_LIST)CONTAINING_RECORD(Entry, MEMORY_RESOURCE_LIST, Entry); MmUnmapIoSpace(Mem->Start, Mem->Length); ExFreePool(Entry); } } BOOLEAN NTAPI StreamClassSynchronize( IN PKINTERRUPT Interrupt, IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, IN PVOID SynchronizeContext) { /* This function is used when the driver either implements synchronization on its own * or if there is no interrupt assigned */ return SynchronizeRoutine(SynchronizeContext); } VOID NTAPI StreamClassInterruptDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { //TODO //read/write data } BOOLEAN NTAPI StreamClassInterruptRoutine( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext) { BOOLEAN Ret = FALSE; PSTREAM_DEVICE_EXTENSION DeviceExtension = (PSTREAM_DEVICE_EXTENSION)ServiceContext; /* Does the driver implement HwInterrupt routine */ if (DeviceExtension->DriverExtension->Data.HwInterrupt) { /* Check if the interrupt was coming from this device */ Ret = DeviceExtension->DriverExtension->Data.HwInterrupt(DeviceExtension->DeviceExtension); if (Ret) { /* Interrupt has from this device, schedule a Dpc for us */ KeInsertQueueDpc(&DeviceExtension->InterruptDpc, NULL, NULL); } } /* Return result */ return Ret; } NTSTATUS NTAPI StreamClassStartDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PHW_STREAM_REQUEST_BLOCK_EXT RequestBlock; PPORT_CONFIGURATION_INFORMATION Config; PSTREAM_DEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IoStack; PCM_RESOURCE_LIST List; PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; PSTREAM_CLASS_DRIVER_EXTENSION DriverObjectExtension; PDMA_ADAPTER Adapter; DEVICE_DESCRIPTION DeviceDesc; NTSTATUS Status = STATUS_SUCCESS; ULONG ResultLength, Index; BOOLEAN bUseDMA, bUseInterrupt; ULONG MapRegisters; KAFFINITY Affinity = 0; PHW_STREAM_DESCRIPTOR StreamDescriptor; PACCESS_RANGE Range; PVOID MappedAddr; PMEMORY_RESOURCE_LIST Mem; /* Get current stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp); /* Get resource list */ List = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated; /* Calculate request length */ ResultLength = sizeof(HW_STREAM_REQUEST_BLOCK_EXT) + sizeof(PPORT_CONFIGURATION_INFORMATION) + List->List[0].PartialResourceList.Count * sizeof(ACCESS_RANGE); /* Allocate Request Block */ RequestBlock = ExAllocatePool(NonPagedPool, ResultLength); if (!RequestBlock) { /* Not enough memory */ CompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, 0); return STATUS_INSUFFICIENT_RESOURCES; } /* Get device extension */ DeviceExtension = (PSTREAM_DEVICE_EXTENSION)DeviceObject->DeviceExtension; /* Get driver object extension */ DriverObjectExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, (PVOID)StreamClassAddDevice); /* sanity checks */ ASSERT(DeviceExtension); ASSERT(DriverObjectExtension); /* Zero request block */ RtlZeroMemory(RequestBlock, ResultLength); /* Locate Config struct */ Config = (PPORT_CONFIGURATION_INFORMATION) (RequestBlock + 1); Range = (PACCESS_RANGE) (Config + 1); /* Initialize Request */ RequestBlock->Block.SizeOfThisPacket = sizeof(HW_STREAM_REQUEST_BLOCK); RequestBlock->Block.Command = SRB_INITIALIZE_DEVICE; RequestBlock->Block.CommandData.ConfigInfo = Config; KeInitializeEvent(&RequestBlock->Event, SynchronizationEvent, FALSE); Config->SizeOfThisPacket = sizeof(PPORT_CONFIGURATION_INFORMATION); Config->HwDeviceExtension = (PVOID) (DeviceExtension + 1); Config->ClassDeviceObject = DeviceObject; Config->PhysicalDeviceObject = DeviceExtension->LowerDeviceObject; Config->RealPhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject; Config->AccessRanges = Range; IoGetDeviceProperty(DeviceObject, DevicePropertyBusNumber, sizeof(ULONG), (PVOID)&Config->SystemIoBusNumber, &ResultLength); IoGetDeviceProperty(DeviceObject, DevicePropertyLegacyBusType, sizeof(INTERFACE_TYPE), (PVOID)&Config->AdapterInterfaceType, &ResultLength); /* Get resource list */ List = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated; /* Scan the translated resources */ bUseDMA = FALSE; bUseInterrupt = FALSE; Range = (PACCESS_RANGE) (Config + 1); for(Index = 0; Index < List->List[0].PartialResourceList.Count; Index++) { /* Locate partial descriptor */ Descriptor = &List->List[0].PartialResourceList.PartialDescriptors[Index]; switch(Descriptor->Type) { case CmResourceTypePort: { /* Store resource information in AccessRange struct */ Range[Config->NumberOfAccessRanges].RangeLength = Descriptor->u.Port.Length; Range[Config->NumberOfAccessRanges].RangeStart.QuadPart = Descriptor->u.Port.Start.QuadPart; Range[Config->NumberOfAccessRanges].RangeInMemory = FALSE; Config->NumberOfAccessRanges++; break; } case CmResourceTypeInterrupt: { /* Store resource information */ Config->BusInterruptLevel = Descriptor->u.Interrupt.Level; Config->BusInterruptVector = Descriptor->u.Interrupt.Vector; Config->InterruptMode = Descriptor->Flags; Affinity = Descriptor->u.Interrupt.Affinity; bUseInterrupt = TRUE; break; } case CmResourceTypeMemory: { Mem = ExAllocatePool(NonPagedPool, sizeof(MEMORY_RESOURCE_LIST)); MappedAddr = MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached); if (!MappedAddr || !Mem) { if (Mem) { /* Release Memory resource descriptor */ ExFreePool(Mem); } if (MappedAddr) { /* Release mem mapped I/O */ MmUnmapIoSpace(MappedAddr, Descriptor->u.Memory.Length); } /* Release resources */ StreamClassReleaseResources(DeviceObject); /* Complete irp */ CompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, 0); ExFreePool(RequestBlock); return STATUS_INSUFFICIENT_RESOURCES; } /* Store range for driver */ Range[Config->NumberOfAccessRanges].RangeLength = Descriptor->u.Memory.Length; Range[Config->NumberOfAccessRanges].RangeStart.QuadPart = Descriptor->u.Memory.Start.QuadPart; Range[Config->NumberOfAccessRanges].RangeInMemory = TRUE; Config->NumberOfAccessRanges++; /* Initialize Memory resource descriptor */ Mem->Length = Descriptor->u.Memory.Length; Mem->Start = MappedAddr; InsertTailList(&DeviceExtension->MemoryResourceList, &Mem->Entry); break; } case CmResourceTypeDma: { bUseDMA = TRUE; Config->DmaChannel = Descriptor->u.Dma.Channel; break; } } } if (!bUseInterrupt || DriverObjectExtension->Data.HwInterrupt == NULL || Config->BusInterruptLevel == 0 || Config->BusInterruptVector == 0) { /* requirements not satisfied */ DeviceExtension->SynchronizeFunction = StreamClassSynchronize; } else { /* use real sync routine */ DeviceExtension->SynchronizeFunction = KeSynchronizeExecution; /* connect interrupt */ Status = IoConnectInterrupt(&DeviceExtension->Interrupt, StreamClassInterruptRoutine, (PVOID)DeviceExtension, NULL, Config->BusInterruptVector, Config->BusInterruptLevel, Config->BusInterruptLevel, Config->InterruptMode, TRUE, Affinity, FALSE); if (!NT_SUCCESS(Status)) { /* Release resources */ StreamClassReleaseResources(DeviceObject); /* Failed to connect interrupt */ CompleteIrp(Irp, Status, 0); /* Release request block */ ExFreePool(RequestBlock); return Status; } /* store interrupt object */ Config->InterruptObject = DeviceExtension->Interrupt; } /* does the device use DMA */ if (bUseDMA && DriverObjectExtension->Data.BusMasterDMA) { /* Zero device description */ RtlZeroMemory(&DeviceDesc, sizeof(DEVICE_DESCRIPTION)); DeviceDesc.Version = DEVICE_DESCRIPTION_VERSION; DeviceDesc.Master = TRUE; DeviceDesc.ScatterGather = TRUE; DeviceDesc.AutoInitialize = FALSE; DeviceDesc.DmaChannel = Config->DmaChannel; DeviceDesc.InterfaceType = Config->AdapterInterfaceType; DeviceDesc.DmaWidth = Width32Bits; DeviceDesc.DmaSpeed = Compatible; DeviceDesc.MaximumLength = MAXULONG; DeviceDesc.Dma32BitAddresses = DriverObjectExtension->Data.Dma24BitAddresses; Adapter = IoGetDmaAdapter(DeviceExtension->PhysicalDeviceObject, &DeviceDesc, &MapRegisters); if (!Adapter) { /* Failed to claim DMA Adapter */ CompleteIrp(Irp, Status, 0); /* Release resources */ StreamClassReleaseResources(DeviceObject); /* Release request block */ ExFreePool(RequestBlock); return Status; } if (DeviceExtension->DriverExtension->Data.DmaBufferSize) { DeviceExtension->DmaCommonBuffer = Adapter->DmaOperations->AllocateCommonBuffer(Adapter, DeviceExtension->DriverExtension->Data.DmaBufferSize, &DeviceExtension->DmaPhysicalAddress, FALSE); if (!DeviceExtension->DmaCommonBuffer) { /* Failed to allocate a common buffer */ CompleteIrp(Irp, Status, 0); /* Release resources */ StreamClassReleaseResources(DeviceObject); /* Release request block */ ExFreePool(RequestBlock); return Status; } } DeviceExtension->MapRegisters = MapRegisters; DeviceExtension->DmaAdapter = Adapter; Config->DmaAdapterObject = (PADAPTER_OBJECT)Adapter; } /* First forward the request to lower attached device object */ Status = ForwardIrpSynchronous(DeviceObject, Irp); if (!NT_SUCCESS(Status)) { /* Failed to start lower devices */ CompleteIrp(Irp, Status, 0); /* Release resources */ StreamClassReleaseResources(DeviceObject); /* Release request block */ ExFreePool(RequestBlock); return Status; } Config->Irp = Irp; /* FIXME SYNCHRONIZATION */ /* Send the request */ DriverObjectExtension->Data.HwReceivePacket((PHW_STREAM_REQUEST_BLOCK)RequestBlock); if (RequestBlock->Block.Status == STATUS_PENDING) { /* Request is pending, wait for result */ KeWaitForSingleObject(&RequestBlock->Event, Executive, KernelMode, FALSE, NULL); /* Get final status code */ Status = RequestBlock->Block.Status; } /* Copy stream descriptor size */ DeviceExtension->StreamDescriptorSize = Config->StreamDescriptorSize; /* check if the request has succeeded or if stream size is valid*/ if (!NT_SUCCESS(Status)|| !Config->StreamDescriptorSize) { /* Failed to start device */ CompleteIrp(Irp, Status, 0); /* Release resources */ StreamClassReleaseResources(DeviceObject); /* Release request block */ ExFreePool(RequestBlock); return Status; } /* Allocate a stream Descriptor */ StreamDescriptor = ExAllocatePool(NonPagedPool, DeviceExtension->StreamDescriptorSize); if (!StreamDescriptor) { /* Not enough memory */ CompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, 0); /* Release resources */ StreamClassReleaseResources(DeviceObject); /* Release request block */ ExFreePool(RequestBlock); return STATUS_INSUFFICIENT_RESOURCES; } /* Zero stream descriptor */ RtlZeroMemory(StreamDescriptor, DeviceExtension->StreamDescriptorSize); /* Setup get stream info struct */ RequestBlock->Block.Command = SRB_GET_STREAM_INFO; RequestBlock->Block.CommandData.StreamBuffer = StreamDescriptor; KeClearEvent(&RequestBlock->Event); /* send the request */ DriverObjectExtension->Data.HwReceivePacket((PHW_STREAM_REQUEST_BLOCK)RequestBlock); if (RequestBlock->Block.Status == STATUS_PENDING) { /* Request is pending, wait for result */ KeWaitForSingleObject(&RequestBlock->Event, Executive, KernelMode, FALSE, NULL); /* Get final status code */ Status = RequestBlock->Block.Status; } if (NT_SUCCESS(Status)) { /* store stream descriptor */ DeviceExtension->StreamDescriptor = StreamDescriptor; } else { /* cleanup resources */ ExFreePool(StreamDescriptor); } ExFreePool(RequestBlock); /* Complete Irp */ CompleteIrp(Irp, Status, 0); /* Return result */ return Status; } NTSTATUS NTAPI StreamClassPnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IoStack; /* Get current irp stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp); switch (IoStack->MinorFunction) { case IRP_MN_START_DEVICE: { return StreamClassStartDevice(DeviceObject, Irp); } } IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_SUPPORTED; }