reactos/drivers/wdm/audio/legacy/stream/driver.c

396 lines
11 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel Streaming
* FILE: drivers/wdm/audio/legacy/stream/driver.c
* PURPOSE: WDM Codec Class Driver
* PROGRAMMER: Johannes Anderwald
*/
#include "stream.h"
NTSTATUS
NTAPI
StreamClassAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
PSTREAM_CLASS_DRIVER_EXTENSION DriverObjectExtension;
PDEVICE_OBJECT DeviceObject, LowerDeviceObject;
PSTREAM_DEVICE_EXTENSION DeviceExtension;
PKSOBJECT_CREATE_ITEM ItemList;
NTSTATUS Status;
/* Fetch driver object extension */
DriverObjectExtension = IoGetDriverObjectExtension(DriverObject, (PVOID)StreamClassAddDevice);
if (!DriverObjectExtension)
{
/* Failed to get driver extension */
return STATUS_DEVICE_DOES_NOT_EXIST;
}
/* Allocate Create Item */
ItemList = ExAllocatePool(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM));
if (!ItemList)
{
/* Failed to allocated Create Item */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Create the FDO */
Status = IoCreateDevice(DriverObject, DriverObjectExtension->Data.DeviceExtensionSize + sizeof(STREAM_DEVICE_EXTENSION), NULL, FILE_DEVICE_KS, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, 0, &DeviceObject);
if (!NT_SUCCESS(Status))
{
/* Failed to create the FDO */
ExFreePool(ItemList);
return Status;
}
/* Attach to device stack */
LowerDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
if (!LowerDeviceObject)
{
/* Failed to attach */
IoDeleteDevice(DeviceObject);
ExFreePool(ItemList);
return STATUS_UNSUCCESSFUL;
}
/* Zero Create item */
RtlZeroMemory(ItemList, sizeof(KSOBJECT_CREATE_ITEM));
/* Setup object class */
RtlInitUnicodeString(&ItemList->ObjectClass, L"GLOBAL");
/* Setup CreateDispatch routine */
ItemList->Create = StreamClassCreateFilter;
/* Get device extension */
DeviceExtension = (PSTREAM_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* Zero device extension */
RtlZeroMemory(DeviceExtension, sizeof(STREAM_DEVICE_EXTENSION));
/* Initialize Ks streaming */
Status = KsAllocateDeviceHeader(&DeviceExtension->Header, 1, ItemList);
if (!NT_SUCCESS(Status))
{
/* Cleanup resources */
IoDetachDevice(LowerDeviceObject);
IoDeleteDevice(DeviceObject);
ExFreePool(ItemList);
return Status;
}
/* Store lower device object */
DeviceExtension->LowerDeviceObject = LowerDeviceObject;
/* Store physical device object */
DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
/* Store driver object extension */
DeviceExtension->DriverExtension = DriverObjectExtension;
/* Initialize memory list */
InitializeListHead(&DeviceExtension->MemoryResourceList);
/* Setup device extension */
DeviceExtension->DeviceExtension = (PVOID) (DeviceExtension + 1);
/* Init interrupt dpc */
KeInitializeDpc(&DeviceExtension->InterruptDpc, StreamClassInterruptDpc, (PVOID)DeviceExtension);
/* Set device transfer method */
DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
/* Clear init flag */
DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
return Status;
}
/*
*@implemented
*/
NTSTATUS
STREAMAPI
StreamClassRegisterAdapter(
IN PVOID Argument1,
IN PVOID Argument2,
IN PHW_INITIALIZATION_DATA HwInitializationData)
{
NTSTATUS Status;
PSTREAM_CLASS_DRIVER_EXTENSION DriverObjectExtension;
PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
/* Allocate driver extension */
Status = IoAllocateDriverObjectExtension(DriverObject, (PVOID)StreamClassAddDevice, sizeof(STREAM_CLASS_DRIVER_EXTENSION), (PVOID*)&DriverObjectExtension);
if (!NT_SUCCESS(Status))
{
/* Failed to allocate */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Zero driver object extension */
RtlZeroMemory(DriverObjectExtension, sizeof(STREAM_CLASS_DRIVER_EXTENSION));
/* copy HwInitializationData */
RtlCopyMemory(&DriverObjectExtension->Data, HwInitializationData, sizeof(HW_INITIALIZATION_DATA));
/* Setup device init methods */
DriverObject->DriverExtension->AddDevice = StreamClassAddDevice;
DriverObject->DriverUnload = KsNullDriverUnload;
/* Setup irp handlers */
DriverObject->MajorFunction[IRP_MJ_PNP] = StreamClassPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = StreamClassPower;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = StreamClassSystemControl;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = StreamClassCleanup;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = StreamClassFlushBuffers;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = StreamClassDeviceControl;
/* Let Ks handle these */
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CREATE);
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE);
return STATUS_SUCCESS;
}
/*
*@implemented
*/
VOID
NTAPI
StreamClassReenumerateStreams(
IN PVOID HwDeviceExtension,
IN ULONG StreamDescriptorSize)
{
HW_STREAM_REQUEST_BLOCK_EXT RequestBlock;
PSTREAM_DEVICE_EXTENSION DeviceExtension;
PHW_STREAM_DESCRIPTOR StreamDescriptor;
if (!HwDeviceExtension || !StreamDescriptorSize)
return;
StreamDescriptor = ExAllocatePool(NonPagedPool, StreamDescriptorSize);
if (!StreamDescriptor)
return;
/* Zero stream descriptor */
RtlZeroMemory(StreamDescriptor, StreamDescriptorSize);
/* Get our DeviceExtension */
DeviceExtension = (PSTREAM_DEVICE_EXTENSION) ((ULONG_PTR)HwDeviceExtension - sizeof(STREAM_DEVICE_EXTENSION));
ASSERT(DeviceExtension->DeviceExtension == HwDeviceExtension);
/* Zero RequestBlock */
RtlZeroMemory(&RequestBlock, sizeof(HW_STREAM_REQUEST_BLOCK_EXT));
/* Setup get stream info struct */
RequestBlock.Block.SizeOfThisPacket = sizeof(HW_STREAM_REQUEST_BLOCK);
RequestBlock.Block.Command = SRB_GET_STREAM_INFO;
RequestBlock.Block.CommandData.StreamBuffer = StreamDescriptor;
KeInitializeEvent(&RequestBlock.Event, SynchronizationEvent, FALSE);
/* FIXME SYNCHRONIZATION */
/* Send the request */
DeviceExtension->DriverExtension->Data.HwReceivePacket ((PHW_STREAM_REQUEST_BLOCK)&RequestBlock);
/* Is the device already completed? */
if (RequestBlock.Block.Status == STATUS_PENDING)
{
/* Request is pending, wait for result */
KeWaitForSingleObject(&RequestBlock.Event, Executive, KernelMode, FALSE, NULL);
}
if (!NT_SUCCESS(RequestBlock.Block.Status))
{
/* Release Stream descriptor */
ExFreePool(StreamDescriptor);
}
else
{
if (DeviceExtension->StreamDescriptor)
{
/* Release old stream descriptor */
ExFreePool(DeviceExtension->StreamDescriptor);
}
/* Store stream descriptor */
DeviceExtension->StreamDescriptor = StreamDescriptor;
DeviceExtension->StreamDescriptorSize = StreamDescriptorSize;
}
}
/*
*@implemented
*/
VOID
NTAPI
StreamClassDebugAssert(
IN PCHAR File,
IN ULONG Line,
IN PCHAR AssertText,
IN ULONG AssertValue)
{
#if DBG
DbgBreakPoint();
#endif
}
/*
*@implemented
*/
VOID
__cdecl
StreamClassDebugPrint(
IN STREAM_DEBUG_LEVEL DebugPrintLevel,
IN PCCHAR DebugMessage,
...)
{
#if DBG
va_list ap;
if (DebugPrintLevel <=STREAMDEBUG_LEVEL)
{
va_start(ap, DebugMessage);
DbgPrint(DebugMessage, ap);
va_end(ap);
}
#endif
}
/*
*@unimplemented
*/
VOID
__cdecl
StreamClassDeviceNotification(
IN STREAM_MINIDRIVER_DEVICE_NOTIFICATION_TYPE NotificationType,
IN PVOID HwDeviceExtension,
IN PHW_STREAM_REQUEST_BLOCK pSrb,
IN PKSEVENT_ENTRY EventEntry,
IN GUID *EventSet,
IN ULONG EventId)
{
PHW_STREAM_REQUEST_BLOCK_EXT RequestBlock;
if (NotificationType == DeviceRequestComplete)
{
RequestBlock = (PHW_STREAM_REQUEST_BLOCK_EXT)pSrb;
KeSetEvent(&RequestBlock->Event, 0, FALSE);
return;
}
UNIMPLEMENTED;
}
/*
*@implemented
*/
PVOID
STREAMAPI
StreamClassGetDmaBuffer(
IN PVOID HwDeviceExtension)
{
PSTREAM_DEVICE_EXTENSION DeviceExtension;
/* Get our DeviceExtension */
DeviceExtension = (PSTREAM_DEVICE_EXTENSION) ((ULONG_PTR)HwDeviceExtension - sizeof(STREAM_DEVICE_EXTENSION));
ASSERT(DeviceExtension->DeviceExtension == HwDeviceExtension);
return DeviceExtension->DmaCommonBuffer;
}
NTSTATUS
NTAPI
StreamClassRWCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PIO_STATUS_BLOCK IoStatusBlock = (PIO_STATUS_BLOCK)Context;
IoStatusBlock->Information = Irp->IoStatus.Information;
IoStatusBlock->Status = Irp->IoStatus.Status;
return STATUS_SUCCESS;
}
/*
*@implemented
*/
BOOLEAN
STREAMAPI
StreamClassReadWriteConfig(
IN PVOID HwDeviceExtension,
IN BOOLEAN Read,
IN PVOID Buffer,
IN ULONG OffSet,
IN ULONG Length)
{
PIRP Irp;
ULONG MajorFunction;
KEVENT Event;
PSTREAM_DEVICE_EXTENSION DeviceExtension;
LARGE_INTEGER Offset;
IO_STATUS_BLOCK StatusBlock;
NTSTATUS Status;
/* Get our DeviceExtension */
DeviceExtension = (PSTREAM_DEVICE_EXTENSION) ((ULONG_PTR)HwDeviceExtension - sizeof(STREAM_DEVICE_EXTENSION));
ASSERT(DeviceExtension->DeviceExtension == HwDeviceExtension);
if (Read)
{
/* Zero input buffer */
RtlZeroMemory(Buffer, Length);
}
/* Set request type */
MajorFunction = (Read ? IRP_MJ_READ : IRP_MJ_WRITE);
/* Initialize event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Set offset */
Offset.QuadPart = OffSet;
/* Pre-init status block */
StatusBlock.Status = STATUS_NOT_SUPPORTED;
/* Create Irp */
Irp = IoBuildSynchronousFsdRequest(MajorFunction,
DeviceExtension->LowerDeviceObject, /* Verify */
Buffer,
Length,
&Offset,
&Event,
&StatusBlock);
if (!Irp)
{
/* Failed to allocate memory */
return FALSE;
}
/* Setup a completion routine */
IoSetCompletionRoutine(Irp, StreamClassRWCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
/* Call driver */
Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* Request is pending, wait for result */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
/* Fetch result */
Status = StatusBlock.Status;
}
if (!NT_SUCCESS(Status))
{
return FALSE;
}
/* FIXME Handle Length != InputLength */
return TRUE;
}