mirror of
https://github.com/reactos/reactos.git
synced 2025-02-25 01:39:30 +00:00
- Remove dead code
- Silence a few debug prints - Implement Dispatch_FastRead, Dispatch_fnFastDeviceIoControl - Change _InterlockedXXX to InterlockedXXX - Store IPortPinWaveCyclic pins in an array and close pin on a new create request (fixes a memory leak) - Complete the close irp when the stream has really been closed svn path=/trunk/; revision=40250
This commit is contained in:
parent
72160071f9
commit
93c61940bb
10 changed files with 187 additions and 167 deletions
|
@ -50,15 +50,6 @@ PcInitializeAdapterDriver(
|
||||||
|
|
||||||
DPRINT1("PcInitializeAdapterDriver\n");
|
DPRINT1("PcInitializeAdapterDriver\n");
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Set default stub - is this a good idea? */
|
|
||||||
DPRINT1("Setting IRP stub\n");
|
|
||||||
for ( i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i ++ )
|
|
||||||
{
|
|
||||||
DriverObject->MajorFunction[i] = IrpStub;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Our IRP handlers */
|
/* Our IRP handlers */
|
||||||
DPRINT1("Setting IRP handlers\n");
|
DPRINT1("Setting IRP handlers\n");
|
||||||
DriverObject->MajorFunction[IRP_MJ_CREATE] = PcDispatchIrp;
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = PcDispatchIrp;
|
||||||
|
@ -195,8 +186,6 @@ PcAddAdapterDevice(
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +230,17 @@ PcRegisterSubdevice(
|
||||||
/* the provided port driver doesnt support ISubdevice */
|
/* the provided port driver doesnt support ISubdevice */
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get the subdevice descriptor */
|
||||||
|
Status = SubDevice->lpVtbl->GetDescriptor(SubDevice, &SubDeviceDescriptor);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to get subdevice descriptor %x\n", Status);
|
||||||
|
SubDevice->lpVtbl->Release(SubDevice);
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add an create item to the device header */
|
||||||
Status = KsAddObjectCreateItemToDeviceHeader(DeviceExt->KsDeviceHeader, PcCreateItemDispatch, (PVOID)SubDevice, Name, NULL);
|
Status = KsAddObjectCreateItemToDeviceHeader(DeviceExt->KsDeviceHeader, PcCreateItemDispatch, (PVOID)SubDevice, Name, NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
|
@ -249,17 +249,16 @@ PcRegisterSubdevice(
|
||||||
DPRINT1("KsAddObjectCreateItemToDeviceHeader failed with %x\n", Status);
|
DPRINT1("KsAddObjectCreateItemToDeviceHeader failed with %x\n", Status);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
SubDevice->lpVtbl->AddRef(SubDevice);
|
|
||||||
|
|
||||||
Status = SubDevice->lpVtbl->GetDescriptor(SubDevice, &SubDeviceDescriptor);
|
/* increment reference count */
|
||||||
if (!NT_SUCCESS(Status))
|
SubDevice->lpVtbl->AddRef(SubDevice);
|
||||||
{
|
|
||||||
DPRINT1("Failed to get subdevice descriptor %x\n", Status);
|
|
||||||
SubDevice->lpVtbl->Release(SubDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(Index = 0; Index < SubDeviceDescriptor->InterfaceCount; Index++)
|
for(Index = 0; Index < SubDeviceDescriptor->InterfaceCount; Index++)
|
||||||
{
|
{
|
||||||
|
//FIXME
|
||||||
|
// Use a reference string such as Wave0001 / Topology0001
|
||||||
|
//
|
||||||
|
|
||||||
Status = IoRegisterDeviceInterface(DeviceExt->PhysicalDeviceObject,
|
Status = IoRegisterDeviceInterface(DeviceExt->PhysicalDeviceObject,
|
||||||
&SubDeviceDescriptor->Interfaces[Index],
|
&SubDeviceDescriptor->Interfaces[Index],
|
||||||
NULL,
|
NULL,
|
||||||
|
|
|
@ -49,7 +49,7 @@ PcRegisterIoTimeout(
|
||||||
Status = IoInitializeTimer(pDeviceObject, pTimerRoutine, pContext);
|
Status = IoInitializeTimer(pDeviceObject, pTimerRoutine, pContext);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT("IoInitializeTimer failed with %x\n", Status);
|
DPRINT1("IoInitializeTimer failed with %x\n", Status);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,8 +94,6 @@ cleanup:
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,20 +6,14 @@ Dispatch_fnDeviceIoControl(
|
||||||
PDEVICE_OBJECT DeviceObject,
|
PDEVICE_OBJECT DeviceObject,
|
||||||
PIRP Irp)
|
PIRP Irp)
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION IoStack;
|
|
||||||
IIrpTarget * IrpTarget;
|
IIrpTarget * IrpTarget;
|
||||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||||
|
|
||||||
//DPRINT1("Dispatch_fnDeviceIoControl called DeviceObject %p Irp %p\n", DeviceObject);
|
|
||||||
|
|
||||||
/* access the create item */
|
/* access the create item */
|
||||||
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
||||||
|
/* get the IrpTarget */
|
||||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
||||||
ASSERT(IoStack->FileObject);
|
|
||||||
|
|
||||||
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
||||||
|
/* let IrpTarget handle request */
|
||||||
return IrpTarget->lpVtbl->DeviceIoControl(IrpTarget, DeviceObject, Irp);
|
return IrpTarget->lpVtbl->DeviceIoControl(IrpTarget, DeviceObject, Irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,20 +23,14 @@ Dispatch_fnRead(
|
||||||
PDEVICE_OBJECT DeviceObject,
|
PDEVICE_OBJECT DeviceObject,
|
||||||
PIRP Irp)
|
PIRP Irp)
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION IoStack;
|
|
||||||
IIrpTarget * IrpTarget;
|
IIrpTarget * IrpTarget;
|
||||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||||
|
|
||||||
DPRINT1("Dispatch_fnRead called DeviceObject %p Irp %p\n", DeviceObject);
|
|
||||||
|
|
||||||
/* access the create item */
|
/* access the create item */
|
||||||
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
||||||
|
/* get the IrpTarget */
|
||||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
||||||
ASSERT(IoStack->FileObject);
|
|
||||||
|
|
||||||
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
||||||
|
/* let IrpTarget handle request */
|
||||||
return IrpTarget->lpVtbl->Read(IrpTarget, DeviceObject, Irp);
|
return IrpTarget->lpVtbl->Read(IrpTarget, DeviceObject, Irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,20 +40,14 @@ Dispatch_fnWrite(
|
||||||
PDEVICE_OBJECT DeviceObject,
|
PDEVICE_OBJECT DeviceObject,
|
||||||
PIRP Irp)
|
PIRP Irp)
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION IoStack;
|
|
||||||
IIrpTarget * IrpTarget;
|
IIrpTarget * IrpTarget;
|
||||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||||
|
|
||||||
DPRINT1("Dispatch_fnWrite called DeviceObject %p Irp %p\n", DeviceObject);
|
|
||||||
|
|
||||||
/* access the create item */
|
/* access the create item */
|
||||||
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
||||||
|
/* get the IrpTarget */
|
||||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
||||||
ASSERT(IoStack->FileObject);
|
|
||||||
|
|
||||||
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
||||||
|
/* let IrpTarget handle request */
|
||||||
return IrpTarget->lpVtbl->Write(IrpTarget, DeviceObject, Irp);
|
return IrpTarget->lpVtbl->Write(IrpTarget, DeviceObject, Irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,20 +57,14 @@ Dispatch_fnFlush(
|
||||||
PDEVICE_OBJECT DeviceObject,
|
PDEVICE_OBJECT DeviceObject,
|
||||||
PIRP Irp)
|
PIRP Irp)
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION IoStack;
|
|
||||||
IIrpTarget * IrpTarget;
|
IIrpTarget * IrpTarget;
|
||||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||||
|
|
||||||
DPRINT1("Dispatch_fnFlush called DeviceObject %p Irp %p\n", DeviceObject);
|
|
||||||
|
|
||||||
/* access the create item */
|
/* access the create item */
|
||||||
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
||||||
|
/* get the IrpTarget */
|
||||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
||||||
ASSERT(IoStack->FileObject);
|
|
||||||
|
|
||||||
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
||||||
|
/* let IrpTarget handle request */
|
||||||
return IrpTarget->lpVtbl->Flush(IrpTarget, DeviceObject, Irp);
|
return IrpTarget->lpVtbl->Flush(IrpTarget, DeviceObject, Irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,24 +74,14 @@ Dispatch_fnClose(
|
||||||
PDEVICE_OBJECT DeviceObject,
|
PDEVICE_OBJECT DeviceObject,
|
||||||
PIRP Irp)
|
PIRP Irp)
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION IoStack;
|
|
||||||
IIrpTarget * IrpTarget;
|
IIrpTarget * IrpTarget;
|
||||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||||
|
|
||||||
DPRINT1("Dispatch_fnClose called DeviceObject %p Irp %p\n", DeviceObject);
|
|
||||||
|
|
||||||
/* access the create item */
|
/* access the create item */
|
||||||
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
||||||
ASSERT(CreateItem != NULL);
|
/* get the IrpTarget */
|
||||||
|
|
||||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
||||||
ASSERT(IoStack != NULL);
|
|
||||||
ASSERT(IoStack->FileObject != NULL);
|
|
||||||
|
|
||||||
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
||||||
|
/* let IrpTarget handle request */
|
||||||
//DPRINT1("IrpTarget %p\n", IrpTarget);
|
|
||||||
|
|
||||||
return IrpTarget->lpVtbl->Close(IrpTarget, DeviceObject, Irp);
|
return IrpTarget->lpVtbl->Close(IrpTarget, DeviceObject, Irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,20 +91,14 @@ Dispatch_fnQuerySecurity(
|
||||||
PDEVICE_OBJECT DeviceObject,
|
PDEVICE_OBJECT DeviceObject,
|
||||||
PIRP Irp)
|
PIRP Irp)
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION IoStack;
|
|
||||||
IIrpTarget * IrpTarget;
|
IIrpTarget * IrpTarget;
|
||||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||||
|
|
||||||
DPRINT1("Dispatch_fnQuerySecurity called DeviceObject %p Irp %p\n", DeviceObject);
|
|
||||||
|
|
||||||
/* access the create item */
|
/* access the create item */
|
||||||
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
||||||
|
/* get the IrpTarget */
|
||||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
||||||
ASSERT(IoStack->FileObject);
|
|
||||||
|
|
||||||
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
||||||
|
/* let IrpTarget handle request */
|
||||||
return IrpTarget->lpVtbl->QuerySecurity(IrpTarget, DeviceObject, Irp);
|
return IrpTarget->lpVtbl->QuerySecurity(IrpTarget, DeviceObject, Irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,20 +108,14 @@ Dispatch_fnSetSecurity(
|
||||||
PDEVICE_OBJECT DeviceObject,
|
PDEVICE_OBJECT DeviceObject,
|
||||||
PIRP Irp)
|
PIRP Irp)
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION IoStack;
|
|
||||||
IIrpTarget * IrpTarget;
|
IIrpTarget * IrpTarget;
|
||||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||||
|
|
||||||
DPRINT1("Dispatch_fnSetSecurity called DeviceObject %p Irp %p\n", DeviceObject);
|
|
||||||
|
|
||||||
/* access the create item */
|
/* access the create item */
|
||||||
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
||||||
|
/* get the IrpTarget */
|
||||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
||||||
ASSERT(IoStack->FileObject);
|
|
||||||
|
|
||||||
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
IrpTarget = (IIrpTarget*)CreateItem->Context;
|
||||||
|
/* let IrpTarget handle request */
|
||||||
return IrpTarget->lpVtbl->SetSecurity(IrpTarget, DeviceObject, Irp);
|
return IrpTarget->lpVtbl->SetSecurity(IrpTarget, DeviceObject, Irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,10 +132,13 @@ Dispatch_fnFastDeviceIoControl(
|
||||||
PIO_STATUS_BLOCK IoStatus,
|
PIO_STATUS_BLOCK IoStatus,
|
||||||
PDEVICE_OBJECT DeviceObject)
|
PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
DPRINT1("Dispatch_fnFastDeviceIoControl called DeviceObject %p Irp %p\n", DeviceObject);
|
IIrpTarget * IrpTarget;
|
||||||
|
|
||||||
|
/* access IrpTarget */
|
||||||
|
IrpTarget = (IIrpTarget *)FileObject->FsContext2;
|
||||||
|
|
||||||
return FALSE;
|
/* let IrpTarget handle request */
|
||||||
|
return IrpTarget->lpVtbl->FastDeviceIoControl(IrpTarget, FileObject, Wait, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, IoControlCode, IoStatus, DeviceObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,10 +154,13 @@ Dispatch_fnFastRead(
|
||||||
PIO_STATUS_BLOCK IoStatus,
|
PIO_STATUS_BLOCK IoStatus,
|
||||||
PDEVICE_OBJECT DeviceObject)
|
PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
DPRINT1("Dispatch_fnFastRead called DeviceObject %p Irp %p\n", DeviceObject);
|
IIrpTarget * IrpTarget;
|
||||||
|
|
||||||
return FALSE;
|
/* access IrpTarget */
|
||||||
|
IrpTarget = (IIrpTarget *)FileObject->FsContext2;
|
||||||
|
|
||||||
|
/* let IrpTarget handle request */
|
||||||
|
return IrpTarget->lpVtbl->FastRead(IrpTarget, FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
|
@ -216,10 +176,10 @@ Dispatch_fnFastWrite(
|
||||||
PDEVICE_OBJECT DeviceObject)
|
PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
IIrpTarget * IrpTarget;
|
IIrpTarget * IrpTarget;
|
||||||
//DPRINT1("Dispatch_fnFastWrite called DeviceObject %p Irp %p\n", DeviceObject);
|
|
||||||
|
|
||||||
|
/* access IrpTarget */
|
||||||
IrpTarget = (IIrpTarget *)FileObject->FsContext2;
|
IrpTarget = (IIrpTarget *)FileObject->FsContext2;
|
||||||
|
/* let IrpTarget handle request */
|
||||||
return IrpTarget->lpVtbl->FastWrite(IrpTarget, FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
|
return IrpTarget->lpVtbl->FastWrite(IrpTarget, FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,9 +113,6 @@ IDmaChannelSlave_fnAllocateBuffer(
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME
|
|
||||||
// retry with different size on failure
|
|
||||||
|
|
||||||
This->Buffer = This->pAdapter->DmaOperations->AllocateCommonBuffer(This->pAdapter, BufferSize, &This->Address, FALSE);
|
This->Buffer = This->pAdapter->DmaOperations->AllocateCommonBuffer(This->pAdapter, BufferSize, &This->Address, FALSE);
|
||||||
if (!This->Buffer)
|
if (!This->Buffer)
|
||||||
{
|
{
|
||||||
|
@ -400,7 +397,7 @@ IDmaChannelSlave_fnStop(
|
||||||
|
|
||||||
This->DmaStarted = FALSE;
|
This->DmaStarted = FALSE;
|
||||||
|
|
||||||
return 0;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
|
@ -493,7 +490,7 @@ PcNewDmaChannel(
|
||||||
|
|
||||||
IDmaChannelSlaveImpl * This;
|
IDmaChannelSlaveImpl * This;
|
||||||
|
|
||||||
DPRINT1("OutDmaChannel %p OuterUnknown %p PoolType %p DeviceDescription %p DeviceObject %p\n",
|
DPRINT("OutDmaChannel %p OuterUnknown %p PoolType %p DeviceDescription %p DeviceObject %p\n",
|
||||||
OutDmaChannel, OuterUnknown, PoolType, DeviceDescription, DeviceObject);
|
OutDmaChannel, OuterUnknown, PoolType, DeviceDescription, DeviceObject);
|
||||||
|
|
||||||
This = AllocateItem(PoolType, sizeof(IDmaChannelSlaveImpl), TAG_PORTCLASS);
|
This = AllocateItem(PoolType, sizeof(IDmaChannelSlaveImpl), TAG_PORTCLASS);
|
||||||
|
@ -510,8 +507,6 @@ PcNewDmaChannel(
|
||||||
DeviceDescription->InterfaceType = BusType;
|
DeviceDescription->InterfaceType = BusType;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT1("Calling IoGetDmaAdapter\n");
|
|
||||||
|
|
||||||
Adapter = IoGetDmaAdapter(DeviceExt->PhysicalDeviceObject, DeviceDescription, &MapRegisters);
|
Adapter = IoGetDmaAdapter(DeviceExt->PhysicalDeviceObject, DeviceDescription, &MapRegisters);
|
||||||
if (!Adapter)
|
if (!Adapter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,7 +15,7 @@ IDrmPort2_fnAddRef(
|
||||||
|
|
||||||
DPRINT("IDrmPort2_AddRef: This %p\n", This);
|
DPRINT("IDrmPort2_AddRef: This %p\n", This);
|
||||||
|
|
||||||
return _InterlockedIncrement(&This->ref);
|
return InterlockedIncrement(&This->ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG
|
ULONG
|
||||||
|
@ -25,7 +25,7 @@ IDrmPort2_fnRelease(
|
||||||
{
|
{
|
||||||
IDrmPort2Impl * This = (IDrmPort2Impl*)iface;
|
IDrmPort2Impl * This = (IDrmPort2Impl*)iface;
|
||||||
|
|
||||||
_InterlockedDecrement(&This->ref);
|
InterlockedDecrement(&This->ref);
|
||||||
|
|
||||||
if (This->ref == 0)
|
if (This->ref == 0)
|
||||||
{
|
{
|
||||||
|
@ -51,13 +51,12 @@ IDrmPort2_fnQueryInterface(
|
||||||
IsEqualGUIDAligned(refiid, &IID_IUnknown))
|
IsEqualGUIDAligned(refiid, &IID_IUnknown))
|
||||||
{
|
{
|
||||||
*Output = (PVOID)&This->lpVtbl;
|
*Output = (PVOID)&This->lpVtbl;
|
||||||
_InterlockedIncrement(&This->ref);
|
InterlockedIncrement(&This->ref);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringFromCLSID(refiid, Buffer);
|
StringFromCLSID(refiid, Buffer);
|
||||||
DPRINT1("IDrmPort2_QueryInterface no interface!!! iface %S\n", Buffer);
|
DPRINT1("IDrmPort2_QueryInterface no interface!!! iface %S\n", Buffer);
|
||||||
KeBugCheckEx(0, 0, 0, 0, 0);
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ typedef struct
|
||||||
LONG ref;
|
LONG ref;
|
||||||
|
|
||||||
IPortWaveCyclic* Port;
|
IPortWaveCyclic* Port;
|
||||||
IPortPinWaveCyclic * Pin;
|
IPortPinWaveCyclic ** Pins;
|
||||||
|
SUBDEVICE_DESCRIPTOR * Descriptor;
|
||||||
|
|
||||||
}IPortFilterWaveCyclicImpl;
|
}IPortFilterWaveCyclicImpl;
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ IPortFilterWaveCyclic_fnRelease(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
@ -83,55 +84,58 @@ IPortFilterWaveCyclic_fnNewIrpTarget(
|
||||||
IN PIRP Irp,
|
IN PIRP Irp,
|
||||||
IN KSOBJECT_CREATE *CreateObject)
|
IN KSOBJECT_CREATE *CreateObject)
|
||||||
{
|
{
|
||||||
ISubdevice * ISubDevice;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
IPortPinWaveCyclic * Pin;
|
IPortPinWaveCyclic * Pin;
|
||||||
SUBDEVICE_DESCRIPTOR * Descriptor;
|
|
||||||
PKSPIN_CONNECT ConnectDetails;
|
PKSPIN_CONNECT ConnectDetails;
|
||||||
IPortFilterWaveCyclicImpl * This = (IPortFilterWaveCyclicImpl *)iface;
|
IPortFilterWaveCyclicImpl * This = (IPortFilterWaveCyclicImpl *)iface;
|
||||||
|
|
||||||
ASSERT(This->Port);
|
ASSERT(This->Port);
|
||||||
|
ASSERT(This->Descriptor);
|
||||||
|
ASSERT(This->Pins);
|
||||||
|
|
||||||
DPRINT("IPortFilterWaveCyclic_fnNewIrpTarget entered\n");
|
DPRINT("IPortFilterWaveCyclic_fnNewIrpTarget entered\n");
|
||||||
|
|
||||||
Status = This->Port->lpVtbl->QueryInterface(This->Port, &IID_ISubdevice, (PVOID*)&ISubDevice);
|
/* let's verify the connection request */
|
||||||
if (!NT_SUCCESS(Status))
|
Status = PcValidateConnectRequest(Irp, &This->Descriptor->Factory, &ConnectDetails);
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
|
|
||||||
Status = ISubDevice->lpVtbl->GetDescriptor(ISubDevice, &Descriptor);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
|
|
||||||
Status = PcValidateConnectRequest(Irp, &Descriptor->Factory, &ConnectDetails);
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ISubDevice->lpVtbl->Release(ISubDevice);
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ISubDevice->lpVtbl->Release(ISubDevice);
|
if (This->Pins[ConnectDetails->PinId] && This->Descriptor->Factory.Instances[ConnectDetails->PinId].CurrentPinInstanceCount)
|
||||||
|
{
|
||||||
|
/* release existing instance */
|
||||||
|
This->Pins[ConnectDetails->PinId]->lpVtbl->Close(This->Pins[ConnectDetails->PinId], DeviceObject, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now create the pin */
|
||||||
Status = NewPortPinWaveCyclic(&Pin);
|
Status = NewPortPinWaveCyclic(&Pin);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = Pin->lpVtbl->Init(Pin, This->Port, iface, ConnectDetails, &Descriptor->Factory.KsPinDescriptor[ConnectDetails->PinId]);
|
/* initialize the pin */
|
||||||
|
Status = Pin->lpVtbl->Init(Pin, This->Port, iface, ConnectDetails, &This->Descriptor->Factory.KsPinDescriptor[ConnectDetails->PinId]);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
Pin->lpVtbl->Release(Pin);
|
Pin->lpVtbl->Release(Pin);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store pin handle */
|
/* release existing pin */
|
||||||
This->Pin = Pin;
|
if (This->Pins[ConnectDetails->PinId])
|
||||||
|
{
|
||||||
|
This->Pins[ConnectDetails->PinId]->lpVtbl->Release(This->Pins[ConnectDetails->PinId]);
|
||||||
|
}
|
||||||
|
/* store pin */
|
||||||
|
This->Pins[ConnectDetails->PinId] = Pin;
|
||||||
|
|
||||||
/* store result */
|
/* store result */
|
||||||
*OutTarget = (IIrpTarget*)Pin;
|
*OutTarget = (IIrpTarget*)Pin;
|
||||||
|
|
||||||
/* increment current instance count */
|
/* increment current instance count */
|
||||||
Descriptor->Factory.Instances[ConnectDetails->PinId].CurrentPinInstanceCount++;
|
This->Descriptor->Factory.Instances[ConnectDetails->PinId].CurrentPinInstanceCount++;
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -207,7 +211,7 @@ IPortFilterWaveCyclic_fnFlush(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
@ -216,10 +220,18 @@ IPortFilterWaveCyclic_fnClose(
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
IN PIRP Irp)
|
IN PIRP Irp)
|
||||||
{
|
{
|
||||||
DPRINT1("IPortFilterWaveCyclic_fnClose entered\n");
|
ULONG Index;
|
||||||
|
IPortFilterWaveCyclicImpl * This = (IPortFilterWaveCyclicImpl *)iface;
|
||||||
|
|
||||||
|
for(Index = 0; Index < This->Descriptor->Factory.PinDescriptorCount; Index++)
|
||||||
|
{
|
||||||
|
if (This->Pins[Index])
|
||||||
|
{
|
||||||
|
This->Pins[Index]->lpVtbl->Close(This->Pins[Index], DeviceObject, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//FIXME
|
|
||||||
//close all pin instances
|
|
||||||
|
|
||||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = 0;
|
||||||
|
@ -271,7 +283,7 @@ IPortFilterWaveCyclic_fnFastDeviceIoControl(
|
||||||
OUT PIO_STATUS_BLOCK StatusBlock,
|
OUT PIO_STATUS_BLOCK StatusBlock,
|
||||||
IN PDEVICE_OBJECT DeviceObject)
|
IN PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,6 +303,7 @@ IPortFilterWaveCyclic_fnFastRead(
|
||||||
OUT PIO_STATUS_BLOCK StatusBlock,
|
OUT PIO_STATUS_BLOCK StatusBlock,
|
||||||
IN PDEVICE_OBJECT DeviceObject)
|
IN PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +323,7 @@ IPortFilterWaveCyclic_fnFastWrite(
|
||||||
OUT PIO_STATUS_BLOCK StatusBlock,
|
OUT PIO_STATUS_BLOCK StatusBlock,
|
||||||
IN PDEVICE_OBJECT DeviceObject)
|
IN PDEVICE_OBJECT DeviceObject)
|
||||||
{
|
{
|
||||||
|
UNIMPLEMENTED
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,12 +337,38 @@ IPortFilterWaveCyclic_fnInit(
|
||||||
IN IPortFilterWaveCyclic* iface,
|
IN IPortFilterWaveCyclic* iface,
|
||||||
IN IPortWaveCyclic* Port)
|
IN IPortWaveCyclic* Port)
|
||||||
{
|
{
|
||||||
|
ISubdevice * ISubDevice;
|
||||||
|
SUBDEVICE_DESCRIPTOR * Descriptor;
|
||||||
|
NTSTATUS Status;
|
||||||
IPortFilterWaveCyclicImpl * This = (IPortFilterWaveCyclicImpl*)iface;
|
IPortFilterWaveCyclicImpl * This = (IPortFilterWaveCyclicImpl*)iface;
|
||||||
|
|
||||||
This->Port = Port;
|
This->Port = Port;
|
||||||
|
|
||||||
|
/* get our private interface */
|
||||||
|
Status = This->Port->lpVtbl->QueryInterface(This->Port, &IID_ISubdevice, (PVOID*)&ISubDevice);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
|
/* get the subdevice descriptor */
|
||||||
|
Status = ISubDevice->lpVtbl->GetDescriptor(ISubDevice, &Descriptor);
|
||||||
|
|
||||||
|
/* release subdevice interface */
|
||||||
|
ISubDevice->lpVtbl->Release(ISubDevice);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
|
/* save descriptor */
|
||||||
|
This->Descriptor = Descriptor;
|
||||||
|
|
||||||
|
/* allocate pin array */
|
||||||
|
This->Pins = AllocateItem(NonPagedPool, Descriptor->Factory.PinDescriptorCount * sizeof(IPortPinWaveCyclic*), TAG_PORTCLASS);
|
||||||
|
|
||||||
|
if (!This->Pins)
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
/* increment reference count */
|
/* increment reference count */
|
||||||
iface->lpVtbl->AddRef(iface);
|
Port->lpVtbl->AddRef(Port);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,8 +179,6 @@ IIrpQueue_fnAddMapping(
|
||||||
|
|
||||||
(void)InterlockedIncrement((volatile long*)&This->NumMappings);
|
(void)InterlockedIncrement((volatile long*)&This->NumMappings);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (Irp)
|
if (Irp)
|
||||||
{
|
{
|
||||||
Irp->IoStatus.Status = STATUS_PENDING;
|
Irp->IoStatus.Status = STATUS_PENDING;
|
||||||
|
|
|
@ -30,6 +30,7 @@ typedef struct
|
||||||
ULONG DelayedRequestInProgress;
|
ULONG DelayedRequestInProgress;
|
||||||
ULONG FrameSize;
|
ULONG FrameSize;
|
||||||
BOOL Capture;
|
BOOL Capture;
|
||||||
|
PIRP CloseIrp;
|
||||||
|
|
||||||
}IPortPinWaveCyclicImpl;
|
}IPortPinWaveCyclicImpl;
|
||||||
|
|
||||||
|
@ -242,7 +243,7 @@ IServiceSink_fnRequestService(
|
||||||
|
|
||||||
|
|
||||||
Status = This->Stream->lpVtbl->GetPosition(This->Stream, &Position);
|
Status = This->Stream->lpVtbl->GetPosition(This->Stream, &Position);
|
||||||
DPRINT1("Position %u Buffer %p BufferSize %u ActiveIrpOffset %u\n", Position, Buffer, This->CommonBufferSize, BufferSize);
|
DPRINT("Position %u Buffer %p BufferSize %u ActiveIrpOffset %u\n", Position, Buffer, This->CommonBufferSize, BufferSize);
|
||||||
|
|
||||||
if (Position < This->CommonBufferOffset)
|
if (Position < This->CommonBufferOffset)
|
||||||
{
|
{
|
||||||
|
@ -616,10 +617,62 @@ CloseStreamRoutine(
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
IN PVOID Context)
|
IN PVOID Context)
|
||||||
{
|
{
|
||||||
PMINIPORTWAVECYCLICSTREAM Stream = (PMINIPORTWAVECYCLICSTREAM)Context;
|
PMINIPORTWAVECYCLICSTREAM Stream;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ISubdevice *ISubDevice;
|
||||||
|
PSUBDEVICE_DESCRIPTOR Descriptor;
|
||||||
|
|
||||||
DPRINT("CloseStreamRoutine %p\n", Stream);
|
IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)Context;
|
||||||
Stream->lpVtbl->Release(Stream);
|
|
||||||
|
if (This->Stream)
|
||||||
|
{
|
||||||
|
if (This->State != KSSTATE_STOP)
|
||||||
|
{
|
||||||
|
This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP);
|
||||||
|
KeStallExecutionProcessor(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
This->ServiceGroup->lpVtbl->RemoveMember(This->ServiceGroup, (PSERVICESINK)&This->lpVtblServiceSink);
|
||||||
|
This->ServiceGroup->lpVtbl->Release(This->ServiceGroup);
|
||||||
|
This->DmaChannel->lpVtbl->Release(This->DmaChannel);
|
||||||
|
|
||||||
|
Status = This->Port->lpVtbl->QueryInterface(This->Port, &IID_ISubdevice, (PVOID*)&ISubDevice);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Status = ISubDevice->lpVtbl->GetDescriptor(ISubDevice, &Descriptor);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ISubDevice->lpVtbl->Release(ISubDevice);
|
||||||
|
Descriptor->Factory.Instances[This->ConnectDetails->PinId].CurrentPinInstanceCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (This->Format)
|
||||||
|
{
|
||||||
|
ExFreePool(This->Format);
|
||||||
|
This->Format = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (This->IrpQueue)
|
||||||
|
{
|
||||||
|
This->IrpQueue->lpVtbl->Release(This->IrpQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (This->Stream)
|
||||||
|
{
|
||||||
|
Stream = This->Stream;
|
||||||
|
This->Stream = NULL;
|
||||||
|
|
||||||
|
if (This->CloseIrp)
|
||||||
|
{
|
||||||
|
This->CloseIrp->IoStatus.Information = 0;
|
||||||
|
This->CloseIrp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
|
IoCompleteRequest(This->CloseIrp, IO_NO_INCREMENT);
|
||||||
|
}
|
||||||
|
Stream->lpVtbl->Release(Stream);
|
||||||
|
/* this line is never reached */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -632,55 +685,33 @@ IPortPinWaveCyclic_fnClose(
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
IN PDEVICE_OBJECT DeviceObject,
|
||||||
IN PIRP Irp)
|
IN PIRP Irp)
|
||||||
{
|
{
|
||||||
ISubdevice *ISubDevice;
|
|
||||||
NTSTATUS Status;
|
|
||||||
SUBDEVICE_DESCRIPTOR * Descriptor;
|
|
||||||
PIO_WORKITEM WorkItem;
|
PIO_WORKITEM WorkItem;
|
||||||
|
|
||||||
IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface;
|
IPortPinWaveCyclicImpl * This = (IPortPinWaveCyclicImpl*)iface;
|
||||||
DPRINT1("IPortPinWaveCyclic_fnClose\n");
|
|
||||||
|
|
||||||
Status = This->Port->lpVtbl->QueryInterface(This->Port, &IID_ISubdevice, (PVOID*)&ISubDevice);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
Status = ISubDevice->lpVtbl->GetDescriptor(ISubDevice, &Descriptor);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
ISubDevice->lpVtbl->Release(ISubDevice);
|
|
||||||
Descriptor->Factory.Instances[This->ConnectDetails->PinId].CurrentPinInstanceCount--;
|
|
||||||
DPRINT1("InstanceCount %u\n", Descriptor->Factory.Instances[This->ConnectDetails->PinId].CurrentPinInstanceCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (This->Stream)
|
|
||||||
{
|
|
||||||
This->Stream->lpVtbl->SetState(This->Stream, KSSTATE_STOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
This->ServiceGroup->lpVtbl->RemoveMember(This->ServiceGroup, (PSERVICESINK)&This->lpVtblServiceSink);
|
|
||||||
This->ServiceGroup->lpVtbl->Release(This->ServiceGroup);
|
|
||||||
This->DmaChannel->lpVtbl->Release(This->DmaChannel);
|
|
||||||
|
|
||||||
if (This->Format)
|
|
||||||
ExFreePool(This->Format);
|
|
||||||
|
|
||||||
This->IrpQueue->lpVtbl->Release(This->IrpQueue);
|
|
||||||
|
|
||||||
|
|
||||||
if (This->Stream)
|
if (This->Stream)
|
||||||
{
|
{
|
||||||
WorkItem = IoAllocateWorkItem(DeviceObject);
|
WorkItem = IoAllocateWorkItem(DeviceObject);
|
||||||
if (WorkItem)
|
if (WorkItem)
|
||||||
{
|
{
|
||||||
IoQueueWorkItem(WorkItem, CloseStreamRoutine, DelayedWorkQueue, (PVOID)This->Stream);
|
if (Irp)
|
||||||
|
{
|
||||||
|
This->CloseIrp = Irp;
|
||||||
|
IoMarkIrpPending(Irp);
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
Irp->IoStatus.Status = STATUS_PENDING;
|
||||||
|
}
|
||||||
|
IoQueueWorkItem(WorkItem, CloseStreamRoutine, DelayedWorkQueue, (PVOID)This);
|
||||||
|
return STATUS_PENDING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Irp->IoStatus.Information = 0;
|
if (Irp)
|
||||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
{
|
||||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
Irp->IoStatus.Information = 0;
|
||||||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
|
}
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -598,7 +598,7 @@ PcCreateItemDispatch(
|
||||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
}
|
}
|
||||||
DPRINT1("Queueing IRP %p\n", Irp);
|
DPRINT1("Queueing IRP %p Irql %u\n", Irp, KeGetCurrentIrql());
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = 0;
|
||||||
Irp->IoStatus.Status = STATUS_PENDING;
|
Irp->IoStatus.Status = STATUS_PENDING;
|
||||||
IoMarkIrpPending(Irp);
|
IoMarkIrpPending(Irp);
|
||||||
|
|
Loading…
Reference in a new issue