RT_C_DECLS_END

#ifdef ALLOC_PRAGMA
# pragma alloc_text(INIT, vgdrvNt4CreateDevice)
# pragma alloc_text(INIT, vgdrvNt4FindPciDevice)
#endif


/**
 * Legacy helper function to create the device object.
 *
 * @returns NT status code.
 *
 * @param   pDrvObj         The driver object.
 * @param   pRegPath        The driver registry path.
 */
NTSTATUS vgdrvNt4CreateDevice(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
{
    Log(("vgdrvNt4CreateDevice: pDrvObj=%p, pRegPath=%p\n", pDrvObj, pRegPath));

    /*
     * Find our virtual PCI device
     */
    ULONG uBusNumber;
    PCI_SLOT_NUMBER SlotNumber;
    NTSTATUS rc = vgdrvNt4FindPciDevice(&uBusNumber, &SlotNumber);
    if (NT_ERROR(rc))
    {
        Log(("vgdrvNt4CreateDevice: Device not found!\n"));
        return rc;
    }

    /*
     * Create device.
     */
    UNICODE_STRING szDevName;
    RtlInitUnicodeString(&szDevName, VBOXGUEST_DEVICE_NAME_NT);
    PDEVICE_OBJECT pDeviceObject = NULL;
    rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &szDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
    if (NT_SUCCESS(rc))
    {
        Log(("vgdrvNt4CreateDevice: Device created\n"));

        UNICODE_STRING DosName;
        RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS);
        rc = IoCreateSymbolicLink(&DosName, &szDevName);
        if (NT_SUCCESS(rc))
        {
            Log(("vgdrvNt4CreateDevice: Symlink created\n"));

            /*
             * Setup the device extension.
             */
            Log(("vgdrvNt4CreateDevice: Setting up device extension ...\n"));

            PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension;
            RT_ZERO(*pDevExt);

            Log(("vgdrvNt4CreateDevice: Device extension created\n"));

            /* Store a reference to ourself. */
            pDevExt->pDeviceObject = pDeviceObject;

            /* Store bus and slot number we've queried before. */
            pDevExt->busNumber  = uBusNumber;
            pDevExt->slotNumber = SlotNumber.u.AsULONG;

#ifdef VBOX_WITH_GUEST_BUGCHECK_DETECTION
            rc = hlpRegisterBugCheckCallback(pDevExt);
#endif

            /* Do the actual VBox init ... */
            if (NT_SUCCESS(rc))
            {
                rc = vgdrvNtInit(pDrvObj, pDeviceObject, pRegPath);
                if (NT_SUCCESS(rc))
                {
                    Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x (succcess)\n", rc));
                    return rc;
                }

                /* bail out */
            }
            IoDeleteSymbolicLink(&DosName);
        }
        else
            Log(("vgdrvNt4CreateDevice: IoCreateSymbolicLink failed with rc = %#x\n", rc));
        IoDeleteDevice(pDeviceObject);
    }
    else
        Log(("vgdrvNt4CreateDevice: IoCreateDevice failed with rc = %#x\n", rc));
    Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x\n", rc));
    return rc;
}
RT_C_DECLS_END

#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, vboxguestwinnt4CreateDevice)
#pragma alloc_text (INIT, vboxguestwinnt4FindPCIDevice)
#endif


/**
 * Legacy helper function to create the device object.
 *
 * @returns NT status code.
 *
 * @param pDrvObj
 * @param pDevObj
 * @param pRegPath
 */
NTSTATUS vboxguestwinnt4CreateDevice(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath)
{
    int vrc = VINF_SUCCESS;
    NTSTATUS rc = STATUS_SUCCESS;

    Log(("VBoxGuest::vboxguestwinnt4CreateDevice: pDrvObj=%p, pDevObj=%p, pRegPath=%p\n",
         pDrvObj, pDevObj, pRegPath));

    /*
     * Find our virtual PCI device
     */
    ULONG uBusNumber, uSlotNumber;
    rc = vboxguestwinnt4FindPCIDevice(&uBusNumber, (PCI_SLOT_NUMBER*)&uSlotNumber);
    if (NT_ERROR(rc))
        Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Device not found!\n"));

    bool fSymbolicLinkCreated = false;
    UNICODE_STRING szDosName;
    PDEVICE_OBJECT pDeviceObject = NULL;
    if (NT_SUCCESS(rc))
    {
        /*
         * Create device.
         */
        UNICODE_STRING szDevName;
        RtlInitUnicodeString(&szDevName, VBOXGUEST_DEVICE_NAME_NT);
        rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXT), &szDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
        if (NT_SUCCESS(rc))
        {
            Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Device created\n"));

            RtlInitUnicodeString(&szDosName, VBOXGUEST_DEVICE_NAME_DOS);
            rc = IoCreateSymbolicLink(&szDosName, &szDevName);
            if (NT_SUCCESS(rc))
            {
                Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Symlink created\n"));
                fSymbolicLinkCreated = true;
            }
            else
                Log(("VBoxGuest::vboxguestwinnt4CreateDevice: IoCreateSymbolicLink failed with rc = %#x\n", rc));
        }
        else
            Log(("VBoxGuest::vboxguestwinnt4CreateDevice: IoCreateDevice failed with rc = %#x\n", rc));
    }

    /*
     * Setup the device extension.
     */
    PVBOXGUESTDEVEXT pDevExt = NULL;
    if (NT_SUCCESS(rc))
    {
        Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Setting up device extension ...\n"));

        pDevExt = (PVBOXGUESTDEVEXT)pDeviceObject->DeviceExtension;
        RtlZeroMemory(pDevExt, sizeof(VBOXGUESTDEVEXT));
    }

    if (NT_SUCCESS(rc) && pDevExt)
    {
        Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Device extension created\n"));

        /* Store a reference to ourself. */
        pDevExt->win.s.pDeviceObject = pDeviceObject;

        /* Store bus and slot number we've queried before. */
        pDevExt->win.s.busNumber = uBusNumber;
        pDevExt->win.s.slotNumber = uSlotNumber;

#ifdef VBOX_WITH_GUEST_BUGCHECK_DETECTION
        rc = hlpRegisterBugCheckCallback(pDevExt);
#endif
    }

    /* Do the actual VBox init ... */
    if (NT_SUCCESS(rc))
        rc = vboxguestwinInit(pDrvObj, pDeviceObject, pRegPath);

    /* Clean up in case of errors. */
    if (NT_ERROR(rc))
    {
        if (fSymbolicLinkCreated && szDosName.Length > 0)
            IoDeleteSymbolicLink(&szDosName);
        if (pDeviceObject)
            IoDeleteDevice(pDeviceObject);
    }

    Log(("VBoxGuest::vboxguestwinnt4CreateDevice: Returning rc = 0x%x\n", rc));
    return rc;
}