mirror of
https://github.com/reactos/reactos.git
synced 2024-08-26 21:28:48 +00:00
396 lines
11 KiB
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;
|
|
}
|