IopCompleteUnloadOrDelete

UINT8 __stdcall IopCompleteUnloadOrDelete(_DEVICE_OBJECT *DeviceObject, UINT8 OnCleanStack, UINT8 Irql){
  UINT8 v3; 
  __int64 v4; 
  UINT8 v7; 
  char v8; 
  int v9; 
  __int64 v10; 
  void *v11; 
  __int64 v13; 
  void(__fastcall *v14)(DEVICE_OBJECT *, _DEVICE_OBJECT *); 
  void *v15; 
  __int64 v16; 
  __int64 v17; 
  int v18; 
  _DEVICE_OBJECT *v19; 
  DEVICE_OBJECT **v20; 
  int v21; 
  int IsAnyDeviceInUse; 
  INT64 v23; 
  INT64 v24; 
  struct _WORK_QUEUE_ITEM WorkItem; 
  char Object[4]; 
  int v27; 
  __int64 v28[5]; 
  DEVICE_OBJECT *DeviceObjects; 
  UINT8 v30; 
  v30 = OnCleanStack;
  v3 = 0;
  v4 = *((_QWORD *)DeviceObject + 1);
  v7 = 0;
  v8 = 1;
  v9 = *(_DWORD *)(*((_QWORD *)DeviceObject + 39) + 32i64);
  if( (v9 & 4) == 0 )
  {
    if( (v9 & 2) != 0 )
    {
      if( (v9 & 1) == 0 || (*(_DWORD *)(v4 + 16) & 1) != 0 )
        v8 = 0;
      v10 = *((_QWORD *)DeviceObject + 3);
      DeviceObjects = (DEVICE_OBJECT *)v10;
      if( v10 )
      {
        v13 = *(_QWORD *)(*(_QWORD *)(v10 + 8) + 80i64);
        IopIncrementDeviceObjectRefCount(DeviceObject, 0);
        KeReleaseQueuedSpinLock(0xAui64, Irql);
        if( v13 )
        {
          if( *(_DWORD *)v13 > 0x68u )
          {
            v14 = *(void(__fastcall **)(DEVICE_OBJECT *, _DEVICE_OBJECT *))(v13 + 104);
            if( v14 )
            {
              v15 = (MmVerifierData & 0x10) != 0 ? VfFastIoSnapState() : 0i64;
              v14(DeviceObjects, DeviceObject);
              if( v15 )
                VfFastIoCheckState(v15, v14);
            }
          }
        }
        Irql = KeAcquireQueuedSpinLock(0xAui64);
        IopDecrementDeviceObjectRefCount(DeviceObject, 0);
        if( *((_QWORD *)DeviceObject + 3) || *((_DWORD *)DeviceObject + 1) )
          goto LABEL_18;
      }
      KeReleaseQueuedSpinLock(0xAui64, Irql);
      v11 = (void *)*((_QWORD *)DeviceObject + 34);
      if( v11 )
        ObDereferenceSecurityDescriptor(v11, 1ui64);
      IopInsertRemoveDevice(*((_DRIVER_OBJECT **)DeviceObject + 1), DeviceObject, 0);
      ObfDereferenceObjectWithTag(DeviceObject, 0x746C6644ui64);
      v7 = 1;
      if( !v8 )
        return v7;
      Irql = KeAcquireQueuedSpinLock(0xAui64);
      if( (*(_DWORD *)(v4 + 16) & 1) != 0 )
      {
        v3 = 1;
LABEL_18:
        KeReleaseQueuedSpinLock(0xAui64, Irql);
        return v3;
      }
    }
    v16 = *(_QWORD *)(v4 + 8);
    v17 = v16;
    if( v16 )
    {
      while( !*(_DWORD *)(v17 + 4) && !*(_QWORD *)(v17 + 24) && (*(_DWORD *)(*(_QWORD *)(v17 + 312) + 32i64) & 6) == 0 )
      {
        v17 = *(_QWORD *)(v17 + 16);
        if( !v17 )
          goto LABEL_24;
      }
      v8 = 0;
    }
LABEL_24:
    v18 = *(_DWORD *)(v4 + 16);
    if( (v18 & 0x80u) != 0 && v16 )
      v8 = 0;
    if( v8 )
      *(_DWORD *)(v4 + 16) = v18 | 1;
    KeReleaseQueuedSpinLock(0xAui64, Irql);
    if( v8 )
    {
      memset((INT64)&WorkItem, 0i64);
      Object[2] = 6;
      v28[1] = (__int64)v28;
      v27 = 0;
      v28[0] = (__int64)v28;
      v28[2] = v4;
      if( v30 )
      {
        IopLoadUnloadDriver(&WorkItem);
      }
      else
      {
        WorkItem.List.Flink = 0i64;
        WorkItem.WorkerRoutine = (void(__fastcall *)(void *))IopLoadUnloadDriver;
        WorkItem.Parameter = &WorkItem;
        ExQueueWorkItem(&WorkItem, DelayedWorkQueue);
        KeWaitForSingleObject(Object, Executive, 0, 0, 0i64);
      }
      ObMakeTemporaryObject((PVOID)v4);
      ObfDereferenceObjectWithTag((PVOID)v4, 0x746C6644ui64);
    }
    return v7;
  }
  DeviceObjects = IopGetDeviceAttachmentBase(DeviceObject);
  v19 = DeviceObjects;
  IsAnyDeviceInUse = PnpIsAnyDeviceInUse(&DeviceObjects, v20);
  KeReleaseQueuedSpinLock((unsigned int)(v21 + 10), Irql);
  if( IsAnyDeviceInUse != 1 )
    PnpChainDereferenceComplete(v19, v30, v23, v24);
  return 0;
}

Referenced by:

IoDeleteDevice
IoDetachDevice
IopDecrementDeviceObjectRef