//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#include "windows.h"
#include "ntstatus.h"
#include "wdm1394.h"
#include <1394.h>
#include <61883.h>
#include <avc.h>
#include "local_unit.h"
#include "avfns.h"
#ifndef MIN
#define MIN(x,y) ( (x) < (y) ? (x) : (y) )
#endif
/* ======================================================================== */
//
// The Unit Driver is somewhat unique; it isn't exactly a Subunit Driver --
// it's a sole instance of a 'Unit' driver. A Subunit is a component
// within a particular device. All communication with a Subunit (we're
// talking about Virtual Drivers, that is -- 'servers') happens through a
// driver directly targetted at that Subunit. However, for AV/C
// communication dealing with the entire Unit (the whole device), there
// isn't a singular place to communicate.
//
// The Unit driver is intended to be a single location for storage and
// inquiry of information specific to the whole Unit. It exists in the
// driver stack as a Filter driver _directly above_ the AV/C FDO.
// [This is as the AV/C Driver's architecture intends such a facility to
// exist.]
//
/* ======================================================================== */
#ifdef DEBUG
#define DBG_ERROR 1
#define DBG_WARNING 2
#define DBG_REQUESTS 4
DBGPARAM dpCurSettings = {
TEXT("AV/C Unit Filter Driver"),
{
TEXT("Errors"), TEXT("Warnings"), TEXT("Requests"), TEXT("Undefined"),
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"),
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"),
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined")
},
DBG_ERROR | DBG_WARNING
};
#endif
/* ======================================================================== */
typedef struct
{
ULONG SubunitType;
ULONG SubunitID;
PVOID RegistrationToken;
STREAM_MediaType MediaType;
ULONG SampleFrequency;
DWORD Direction;
HANDLE Handle;
AV_PCR LastPCR;
BOOL Unprocessed;
ULONG SubunitPlugID;
ULONG Flags;
} UNIT_Plug;
//
// Global Data -- 'Unit Specific'.
//
KSPIN_LOCK UnitLock;
UNIT_Plug UnitPlugs[TOTAL_NUM_PLUGS];
typedef struct
{
ULONG FMT;
ULONG FDF;
} MediaTypeFormat;
MediaTypeFormat FormatCodes[]=
{
{0x20, 0x000000}, // UNIT_REGISTER_PLUG_MediaType_MPEG
{0x20, 0x800000}, // UNIT_REGISTER_PLUG_MediaType_MPEG_TimeShifted
{0x21, 0x000000}, // UNIT_REGISTER_PLUG_MediaType_DSS
{0x21, 0x800000}, // UNIT_REGISTER_PLUG_MediaType_DSS_TimeShifted
{0x10, 0x00}, // UNIT_REGISTER_PLUG_MediaType_Audio_AM824
{0x10, 0x10}, // UNIT_REGISTER_PLUG_MediaType_Audio_24x4Pack
{0x10, 0x20}, // UNIT_REGISTER_PLUG_MediaType_Audio_32fp
{0x00, 0x20}, // UNIT_REGISTER_PLUG_MediaType_DV_SD_625_50Hz,
{0x00, 0x00}, // UNIT_REGISTER_PLUG_MediaType_DV_SD_525_60Hz
{0x00, 0x24}, // UNIT_REGISTER_PLUG_MediaType_DV_SDL_625_50Hz
{0x00, 0x04}, // UNIT_REGISTER_PLUG_MediaType_DV_SDL_525_60Hz
{0x00, 0x28}, // UNIT_REGISTER_PLUG_MediaType_DV_HD_1250_50Hz
{0x00, 0x08}, // UNIT_REGISTER_PLUG_MediaType_DV_HD_1125_60Hz
};
/* ======================================================================== */
static VOID PlugWaitersCancelRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
KIRQL irql;
LIST_ENTRY *le;
UNIT_FDO_DEVICE_EXTENSION *dfde = (UNIT_FDO_DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
KIRQL orig_irql;
orig_irql = Irp->CancelIrql;
KeAcquireSpinLock(&dfde->dfde_PlugWaitersLock, &irql);
for (le = dfde->dfde_PlugWaiters.Flink;
le != &dfde->dfde_PlugWaiters;
le = le->Flink)
{
PIRP TIrp;
TIrp = CONTAINING_RECORD(le, IRP, Tail.Overlay.ListEntry);
if (TIrp == Irp)
{
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoSetCancelRoutine(Irp, NULL);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
}
}
KeReleaseSpinLock(&dfde->dfde_PlugWaitersLock, irql);
IoReleaseCancelSpinLock(orig_irql);
}
/* ======================================================================== */
static UNIT_AVC_REQ_BLOCK *RawAllocUARB(PDEVICE_OBJECT DeviceObject)
{
UNIT_FDO_DEVICE_EXTENSION *dfde = (UNIT_FDO_DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
UNIT_AVC_REQ_BLOCK *uarb;
uarb = ExAllocatePool(NonPagedPool, sizeof(UNIT_AVC_REQ_BLOCK));
if (uarb)
{
uarb->uarb_Irp = IoAllocateIrp( (CCHAR) (dfde->dfde_Common.dcde_ParentDeviceObject->StackSize + 1), FALSE);
if (uarb->uarb_Irp)
{
return(uarb);
}
ExFreePool(uarb);
uarb = NULL;
}
return(uarb);
}
static VOID RawFreeUARB(UNIT_AVC_REQ_BLOCK *uarb)
{
IoFreeIrp(uarb->uarb_Irp);
ExFreePool(uarb);
}
/* ======================================================================== */
static UNIT_AVC_REQ_BLOCK *UNIT_AllocateUARB(PDEVICE_OBJECT DeviceObject)
{
UNIT_FDO_DEVICE_EXTENSION *dfde = (UNIT_FDO_DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
KIRQL oldirql;
UNIT_AVC_REQ_BLOCK *uarb;
KeAcquireSpinLock(&dfde->dfde_UARBLock, &oldirql);
if (!IsListEmpty(&dfde->dfde_FreeUARBs))
{
uarb = (UNIT_AVC_REQ_BLOCK *) RemoveHeadList(&dfde->dfde_FreeUARBs);
}
else
uarb = RawAllocUARB(DeviceObject);
InsertTailList(&dfde->dfde_OutstandingUARBs, &uarb->uarb);
KeReleaseSpinLock(&dfde->dfde_UARBLock, oldirql);
return(uarb);
}
static VOID UNIT_FreeUARB(UNIT_AVC_REQ_BLOCK *uarb)
{
UNIT_FDO_DEVICE_EXTENSION *dfde = uarb->uarb_DeviceExtension;
KIRQL oldirql;
KeAcquireSpinLock(&dfde->dfde_UARBLock, &oldirql);
RemoveEntryList(&uarb->uarb);
InsertTailList(&dfde->dfde_FreeUARBs, &uarb->uarb);
KeReleaseSpinLock(&dfde->dfde_UARBLock, oldirql);
}
/* ======================================================================== */
static NTSTATUS UNIT_UARBRespCompletionRoutine(
IN PDEVICE_OBJECT DeviceObjectUnused,
IN PIRP Irp,
IN PVOID Context)
{
UNIT_AVC_REQ_BLOCK *uarb = (UNIT_AVC_REQ_BLOCK *) Context;
UNIT_FDO_DEVICE_EXTENSION *dfde = uarb->uarb_DeviceExtension;
NTSTATUS status;
PDEVICE_OBJECT DeviceObject;
UNREFERENCED_PARAMETER(DeviceObjectUnused);
DeviceObject = uarb->uarb_FDO;
status = Irp->IoStatus.Status;
KeSetEvent(&uarb->uarb_Event, 0, FALSE);
status = uarb->uarb_Irp->IoStatus.Status;
if (status != STATUS_CANCELLED)
{
UNIT_FreeUARB(uarb);
}
return(STATUS_MORE_PROCESSING_REQUIRED);
}
static NTSTATUS UNIT_SendRespUARB(PDEVICE_OBJECT DeviceObject, UNIT_AVC_REQ_BLOCK *uarb)
{
NTSTATUS status;
UNIT_FDO_DEVICE_EXTENSION *dfde;
PIO_STACK_LOCATION isl;
CCHAR pss