text: //---------------------------------------------------------------------------
  //
  //  Module:   perf.c
  //
  //  Description:
  //
  //
  //@@BEGIN_MSINTERNAL
  //
  //  History:   Date       Author      Comment
  //             --------------------------------------------------------------
  //             12/12/00   ArthurZ     Created
  //
  //@@END_MSINTERNAL
  //---------------------------------------------------------------------------
  //
  //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  //  PURPOSE.
  //
  //  Copyright (c) 1995-1999 Microsoft Corporation.  All Rights Reserved.
  //
  //---------------------------------------------------------------------------
  
  #include "private.h"
  #include "perf.h"
  
  #define PROC_REG_PATH L"System\\CurrentControlSet\\Services\\Portcls"
  
  GUID ControlGuid =
  { 0x28cf047a, 0x2437, 0x4b24, 0xb6, 0x53, 0xb9, 0x44, 0x6a, 0x41, 0x9a, 0x69 };
  
  GUID TraceGuid =
  { 0x9d447297, 0xc576, 0x4015, 0x87, 0xb5, 0xa5, 0xa6, 0x98, 0xfd, 0x4d, 0xd1 };
  
  GUID TraceDMAGuid =
  { 0xf27b2e65, 0x15f0, 0x4d01, 0xab, 0xe2, 0xf7, 0x68, 0x5d, 0xf6, 0xe5, 0x72 };
  
  ULONG TraceEnable;
  TRACEHANDLE LoggerHandle;
  
  typedef struct PERFINFO_AUDIOGLITCH {
      ULONGLONG   cycleCounter;
      ULONG       glitchType;
      LONGLONG    sampleTime;
      LONGLONG    previousTime;
      ULONG_PTR   instanceId;
  } PERFINFO_AUDIOGLITCH, *PPERFINFO_AUDIOGLITCH;
  
  typedef struct PERFINFO_WMI_AUDIOGLITCH {
      EVENT_TRACE_HEADER          header;
      PERFINFO_AUDIOGLITCH        data;
  } PERFINFO_WMI_AUDIO_GLITCH, *PPERFINFO_WMI_AUDIOGLITCH;
  
  ///////////////////////////////////////////////////////////////////////////
  
  VOID
  PerfRegisterProvider (
      IN PDEVICE_OBJECT DeviceObject
      )
  
  /*++
  
  Routine Description:
  
      This routine registers this component as a WMI event tracing provider.
  
  --*/
  
  {
      IoWMIRegistrationControl (DeviceObject, WMIREG_ACTION_REGISTER);
  }
  
  ///////////////////////////////////////////////////////////////////////////
  
  VOID
  PerfUnregisterProvider (
      IN PDEVICE_OBJECT DeviceObject
      )
  
  /*++
  
  Routine Description:
  
      This routine unregisters this component as a WMI event tracing provider.
  
  --*/
  
  {
      IoWMIRegistrationControl (DeviceObject, WMIREG_ACTION_DEREGISTER);
  }
  
  ///////////////////////////////////////////////////////////////////////////
  
  NTSTATUS
  RegisterWmiGuids (
      IN PWMIREGINFO WmiRegInfo,
      IN ULONG RegInfoSize,
      IN PULONG ReturnSize
      )
  
  /*++
  
  Routine Description:
  
      This routine registers WMI event tracing streams.
  
  --*/
  
  {
      ULONG SizeNeeded;
      PWMIREGGUIDW WmiRegGuidPtr;
      ULONG status;
      ULONG GuidCount;
      ULONG RegistryPathSize;
      PUCHAR Temp;
  
      if (WmiRegInfo == NULL ||
          ReturnSize == NULL ) {
          return STATUS_INVALID_PARAMETER;
      }
  
      GuidCount = 1;
  
      RegistryPathSize = sizeof (PROC_REG_PATH) - sizeof (WCHAR) + sizeof (USHORT);
      SizeNeeded = sizeof (WMIREGINFOW) + GuidCount * sizeof (WMIREGGUIDW) + RegistryPathSize;
  
      if (SizeNeeded > RegInfoSize) {
          if ( RegInfoSize >= sizeof(ULONG) ) {
              *((PULONG)WmiRegInfo) = SizeNeeded;
              *ReturnSize = sizeof (ULONG);
              return STATUS_BUFFER_OVERFLOW;
          }
          else {
              *ReturnSize = 0;
              return STATUS_BUFFER_TOO_SMALL;
          }
      }
  
      RtlZeroMemory (WmiRegInfo, SizeNeeded);
      WmiRegInfo->BufferSize = SizeNeeded;
      WmiRegInfo->GuidCount = GuidCount;
  
      WmiRegGuidPtr = WmiRegInfo->WmiRegGuid;
      WmiRegGuidPtr->Guid = ControlGuid;
      WmiRegGuidPtr->Flags |= (WMIREG_FLAG_TRACED_GUID | WMIREG_FLAG_TRACE_CONTROL_GUID);
  
      Temp = (PUCHAR)(WmiRegGuidPtr + 1);
      WmiRegInfo->RegistryPath = PtrToUlong ((PVOID)(Temp - (PUCHAR)WmiRegInfo));
      *((PUSHORT)Temp) = (USHORT)(sizeof (PROC_REG_PATH) - sizeof (WCHAR));
  
      Temp += sizeof (USHORT);
      RtlCopyMemory (Temp, PROC_REG_PATH, sizeof (PROC_REG_PATH) - sizeof (WCHAR));
  
      *ReturnSize = SizeNeeded;
  
      return STATUS_SUCCESS;
  }
  
  ///////////////////////////////////////////////////////////////////////////
  
  NTSTATUS
  PcDispatchSystemControl
  (
      IN      PDEVICE_OBJECT  pDeviceObject,
      IN      PIRP            pIrp
  );
  
  NTSTATUS
  PerfWmiDispatch (
      IN PDEVICE_OBJECT DeviceObject,
      IN PIRP Irp
      )
  
  /*++
  
  Routine Description:
  
      This routine handles IRP_MJ_SYSTEM_CONTROL calls. It processes
      WMI requests and passes everything else on to KS.
  
  --*/
  
  {
      PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
      ULONG ReturnSize=0;
      PWNODE_HEADER Wnode;
      NTSTATUS ntStatus = STATUS_SUCCESS;
  
      if ((PDEVICE_OBJECT)IrpSp->Parameters.WMI.ProviderId != DeviceObject) {
          return PcDispatchSystemControl(DeviceObject, Irp);
      }
  
      switch (IrpSp->MinorFunction) {
  
      case IRP_MN_REGINFO:
          ntStatus = RegisterWmiGuids ((PWMIREGINFO)IrpSp->Parameters.WMI.Buffer,
                            IrpSp->Parameters.WMI.BufferSize,
                            &ReturnSize);
          break;
  
      case IRP_MN_ENABLE_EVENTS:
          InterlockedExchange ((PLONG)&TraceEnable, 1);
          Wnode = (PWNODE_HEADER)IrpSp->Parameters.WMI.Buffer;
          if (IrpSp->Parameters.WMI.BufferSize >= sizeof (WNODE_HEADER)) {
              LoggerHandle = Wnode->HistoricalContext;
          }
          break;
  
      case IRP_MN_DISABLE_EVENTS:
          InterlockedExchange ((PLONG)&TraceEnable, 0);
          break;
  
      case IRP_MN_ENABLE_COLLECTION:
      case IRP_MN_DISABLE_COLLECTION:
          break;
  
      default:
          ntStatus = STATUS_NOT_SUPPORTED;
      }
  
      // Do not modify Irp Status if this WMI call is not
      // handled.
      //
      if (STATUS_NOT_SUPPORTED == ntStatus)
      {
          ntStatus = Irp->IoStatus.Status;
      }
      else
      {
          Irp->IoStatus.Status = ntStatus;
          Irp->IoStatus.Information = ReturnSize;
      }
  
      IoCompleteRequest (Irp, IO_NO_INCREMENT);
      return ntStatus;
  }
  
  ///////////////////////////////////////////////////////////////////////////
  VOID
  PerfLogGlitch (
      IN GUID Guid,
      IN ULONG_PTR InstanceId,
      IN ULONG Type,
      IN LONGLONG CurrentTime,
      IN LONGLONG PreviousTime
      )
  
  /*++
  
  Routine Description:
  
      This routine logs a WMI event tracing event with an audio glitch GUID
      and the supplied glitch type.
  
  --*/
  
  {
      PERFINFO_WMI_AUDIO_GLITCH Event;
  
      if (LoggerHandle == (TRACEHANDLE)NULL || TraceEnable == 0) {
          return;
      }
  
      RtlZeroMemory (&Event, sizeof (Event));
      Event.header.Size = sizeof (Event);
      Event.header.Flags = WNODE_FLAG_TRACED_GUID;
      Event.header.Guid = Guid;
      Event.data.glitchType = Type;
      Event.data.instanceId = InstanceId;
      Event.data.sampleTime = CurrentTime;
      Event.data.previousTime = PreviousTime;
  
      ((PWNODE_HEADER)&Event)->HistoricalContext = LoggerHandle;
  
      IoWMIWriteEvent ((PVOID)&Event);
  }
  
  
  VOID
  PerfLogInsertSilenceGlitch (
      IN ULONG_PTR InstanceId,
      IN ULONG Type,
      IN LONGLONG CurrentTime,
      IN LONGLONG PreviousTime
      )
  
  {
      PerfLogGlitch (TraceGuid,InstanceId,Type,CurrentTime,PreviousTime);
  }
  
  VOID
  PerfLogDMAGlitch (
      IN ULONG_PTR InstanceId,
      IN ULONG Type,
      IN LONGLONG CurrentTime,
      IN LONGLONG PreviousTime
      )
  
  {
      PerfLogGlitch (TraceDMAGuid,InstanceId,Type,CurrentTime,PreviousTime);
  }
  
  //---------------------------------------------------------------------------
  //  End of File: perf.c
  //---------------------------------------------------------------------------
  
  