mirror of
https://github.com/reactos/reactos.git
synced 2024-09-11 05:12:43 +00:00
313 lines
9.6 KiB
C++
313 lines
9.6 KiB
C++
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel Streaming
|
|
* FILE: drivers/wdm/audio/backpln/portcls/api.cpp
|
|
* PURPOSE: Port Class driver / DriverEntry and IRP handlers
|
|
* PROGRAMMER: Andrew Greenwood
|
|
* Johannes Anderwald
|
|
* HISTORY:
|
|
* 27 Jan 07 Created
|
|
*/
|
|
|
|
#include "private.hpp"
|
|
|
|
#ifndef YDEBUG
|
|
#define NDEBUG
|
|
#endif
|
|
|
|
#include <debug.h>
|
|
|
|
//
|
|
// This is called from DriverEntry so that PortCls can take care of some
|
|
// IRPs and map some others to the main KS driver. In most cases this will
|
|
// be the first function called by an audio driver.
|
|
//
|
|
// First 2 parameters are from DriverEntry.
|
|
//
|
|
// The AddDevice parameter is a driver-supplied pointer to a function which
|
|
// typically then calls PcAddAdapterDevice (see below.)
|
|
//
|
|
NTSTATUS
|
|
NTAPI
|
|
PcInitializeAdapterDriver(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPathName,
|
|
IN PDRIVER_ADD_DEVICE AddDevice)
|
|
{
|
|
DPRINT("PcInitializeAdapterDriver\n");
|
|
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
|
|
|
|
// Our IRP handlers
|
|
DPRINT("Setting IRP handlers\n");
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = PcDispatchIrp;
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = PcDispatchIrp;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = PcDispatchIrp;
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PcDispatchIrp;
|
|
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = PcDispatchIrp;
|
|
|
|
// The driver-supplied AddDevice
|
|
DriverObject->DriverExtension->AddDevice = AddDevice;
|
|
|
|
// KS handles these
|
|
DPRINT("Setting KS function handlers\n");
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE);
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL);
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_FLUSH_BUFFERS);
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_QUERY_SECURITY);
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_READ);
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_SET_SECURITY);
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_WRITE);
|
|
|
|
DPRINT("PortCls has finished initializing the adapter driver\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Typically called by a driver's AddDevice function, which is set when
|
|
// calling PcInitializeAdapterDriver. This performs some common driver
|
|
// operations, such as creating a device extension.
|
|
//
|
|
// The StartDevice parameter is a driver-supplied function which gets
|
|
// called in response to IRP_MJ_PNP / IRP_MN_START_DEVICE.
|
|
//
|
|
NTSTATUS
|
|
NTAPI
|
|
PcAddAdapterDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
IN PCPFNSTARTDEVICE StartDevice,
|
|
IN ULONG MaxObjects,
|
|
IN ULONG DeviceExtensionSize)
|
|
{
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
PDEVICE_OBJECT fdo;
|
|
PDEVICE_OBJECT PrevDeviceObject;
|
|
PPCLASS_DEVICE_EXTENSION portcls_ext = NULL;
|
|
|
|
DPRINT("PcAddAdapterDevice called\n");
|
|
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
|
|
|
|
if (!DriverObject || !PhysicalDeviceObject || !StartDevice)
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// check if the DeviceExtensionSize is provided
|
|
if ( DeviceExtensionSize < PORT_CLASS_DEVICE_EXTENSION_SIZE )
|
|
{
|
|
// driver does not need a device extension
|
|
if ( DeviceExtensionSize != 0 )
|
|
{
|
|
// DeviceExtensionSize must be zero
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
// set size to our extension size
|
|
DeviceExtensionSize = PORT_CLASS_DEVICE_EXTENSION_SIZE;
|
|
}
|
|
|
|
// create the device
|
|
status = IoCreateDevice(DriverObject,
|
|
DeviceExtensionSize,
|
|
NULL,
|
|
FILE_DEVICE_KS,
|
|
FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
|
|
FALSE,
|
|
&fdo);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", status);
|
|
return status;
|
|
}
|
|
|
|
// Obtain the new device extension
|
|
portcls_ext = (PPCLASS_DEVICE_EXTENSION) fdo->DeviceExtension;
|
|
// initialize the device extension
|
|
RtlZeroMemory(portcls_ext, DeviceExtensionSize);
|
|
// allocate create item
|
|
portcls_ext->CreateItems = (PKSOBJECT_CREATE_ITEM)AllocateItem(NonPagedPool, MaxObjects * sizeof(KSOBJECT_CREATE_ITEM), TAG_PORTCLASS);
|
|
|
|
if (!portcls_ext->CreateItems)
|
|
{
|
|
// not enough resources
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
// store max subdevice count
|
|
portcls_ext->MaxSubDevices = MaxObjects;
|
|
// store the physical device object
|
|
portcls_ext->PhysicalDeviceObject = PhysicalDeviceObject;
|
|
// set up the start device function
|
|
portcls_ext->StartDevice = StartDevice;
|
|
// initialize timer lock
|
|
KeInitializeSpinLock(&portcls_ext->TimerListLock);
|
|
// initialize timer list
|
|
InitializeListHead(&portcls_ext->TimerList);
|
|
// initialize io timer
|
|
IoInitializeTimer(fdo, PcIoTimerRoutine, NULL);
|
|
// start the io timer
|
|
IoStartTimer(fdo);
|
|
|
|
// set io flags
|
|
fdo->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
|
|
// clear initializing flag
|
|
fdo->Flags &= ~ DO_DEVICE_INITIALIZING;
|
|
|
|
// allocate the device header
|
|
status = KsAllocateDeviceHeader(&portcls_ext->KsDeviceHeader, MaxObjects, portcls_ext->CreateItems);
|
|
// did we succeed
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
// attach device to device stack
|
|
PrevDeviceObject = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
|
|
// did we succeed
|
|
if (PrevDeviceObject)
|
|
{
|
|
// store the device object in the device header
|
|
//KsSetDevicePnpBaseObject(portcls_ext->KsDeviceHeader, fdo, PrevDeviceObject);
|
|
portcls_ext->PrevDeviceObject = PrevDeviceObject;
|
|
}
|
|
else
|
|
{
|
|
// return error code
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto cleanup;
|
|
}
|
|
|
|
// register shutdown notification
|
|
IoRegisterShutdownNotification(PhysicalDeviceObject);
|
|
|
|
return status;
|
|
|
|
cleanup:
|
|
|
|
if (portcls_ext->KsDeviceHeader)
|
|
{
|
|
// free the device header
|
|
KsFreeDeviceHeader(portcls_ext->KsDeviceHeader);
|
|
}
|
|
|
|
if (portcls_ext->CreateItems)
|
|
{
|
|
// free previously allocated create items
|
|
FreeItem(portcls_ext->CreateItems, TAG_PORTCLASS);
|
|
}
|
|
|
|
// delete created fdo
|
|
IoDeleteDevice(fdo);
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
PcRegisterSubdevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PWCHAR Name,
|
|
IN PUNKNOWN Unknown)
|
|
{
|
|
PPCLASS_DEVICE_EXTENSION DeviceExt;
|
|
NTSTATUS Status;
|
|
ISubdevice *SubDevice;
|
|
UNICODE_STRING SymbolicLinkName;
|
|
PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor;
|
|
ULONG Index;
|
|
UNICODE_STRING RefName;
|
|
PSYMBOLICLINK_ENTRY SymEntry;
|
|
|
|
DPRINT("PcRegisterSubdevice DeviceObject %p Name %S Unknown %p\n", DeviceObject, Name, Unknown);
|
|
|
|
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
|
|
|
|
// check if all parameters are valid
|
|
if (!DeviceObject || !Name || !Unknown)
|
|
{
|
|
DPRINT("PcRegisterSubdevice invalid parameter\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// get device extension
|
|
DeviceExt = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
if (!DeviceExt)
|
|
{
|
|
// should not happen
|
|
DbgBreakPoint();
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
// look up our undocumented interface
|
|
Status = Unknown->QueryInterface(IID_ISubdevice, (LPVOID*)&SubDevice);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("No ISubdevice interface\n");
|
|
// the provided port driver doesnt support ISubdevice
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// get the subdevice descriptor
|
|
Status = SubDevice->GetDescriptor(&SubDeviceDescriptor);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("Failed to get subdevice descriptor %x\n", Status);
|
|
SubDevice->Release();
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
// add an create item to the device header
|
|
Status = KsAddObjectCreateItemToDeviceHeader(DeviceExt->KsDeviceHeader, PcCreateItemDispatch, (PVOID)SubDevice, Name, NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
// failed to attach
|
|
SubDevice->Release();
|
|
DPRINT("KsAddObjectCreateItemToDeviceHeader failed with %x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
// initialize reference string
|
|
RtlInitUnicodeString(&RefName, Name);
|
|
RtlInitUnicodeString(&SubDeviceDescriptor->RefString, Name);
|
|
|
|
for(Index = 0; Index < SubDeviceDescriptor->InterfaceCount; Index++)
|
|
{
|
|
// FIXME
|
|
// check if reference string with that name already exists
|
|
|
|
Status = IoRegisterDeviceInterface(DeviceExt->PhysicalDeviceObject,
|
|
&SubDeviceDescriptor->Interfaces[Index],
|
|
&RefName,
|
|
&SymbolicLinkName);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
// activate device interface
|
|
IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
|
|
// allocate symbolic link entry
|
|
SymEntry = (PSYMBOLICLINK_ENTRY)AllocateItem(NonPagedPool, sizeof(SYMBOLICLINK_ENTRY), TAG_PORTCLASS);
|
|
if (SymEntry)
|
|
{
|
|
// initialize symbolic link item
|
|
RtlInitUnicodeString(&SymEntry->SymbolicLink, SymbolicLinkName.Buffer);
|
|
// store item
|
|
InsertTailList(&SubDeviceDescriptor->SymbolicLinkList, &SymEntry->Entry);
|
|
}
|
|
else
|
|
{
|
|
// allocating failed
|
|
RtlFreeUnicodeString(&SymbolicLinkName);
|
|
}
|
|
}
|
|
}
|
|
|
|
// release SubDevice reference
|
|
SubDevice->Release();
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|