static int VBoxGuestFreeBSDDetach(device_t pDevice)
{
    struct VBoxGuestDeviceState *pState = device_get_softc(pDevice);

    if (cUsers > 0)
        return EBUSY;

    /*
     * Reverse what we did in VBoxGuestFreeBSDAttach.
     */
    if (g_VBoxGuestFreeBSDEHTag != NULL)
        EVENTHANDLER_DEREGISTER(dev_clone, g_VBoxGuestFreeBSDEHTag);

    clone_cleanup(&g_pVBoxGuestFreeBSDClones);

    VBoxGuestFreeBSDRemoveIRQ(pDevice, pState);

    if (pState->pVMMDevMemRes)
        bus_release_resource(pDevice, SYS_RES_MEMORY, pState->iVMMDevMemResId, pState->pVMMDevMemRes);
    if (pState->pIOPortRes)
        bus_release_resource(pDevice, SYS_RES_IOPORT, pState->iIOPortResId, pState->pIOPortRes);

    VbgdCommonDeleteDevExt(&g_DevExt);

    RTR0Term();

    return 0;
}
/**
 * Detach entry point, to detach a device to the system or suspend it.
 *
 * @param   pDip            The module structure instance.
 * @param   enmCmd          Attach type (ddi_attach_cmd_t)
 *
 * @return  corresponding solaris error code.
 */
static int VBoxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
{
    LogFlow((DEVICE_NAME "::Detach\n"));
    switch (enmCmd)
    {
    case DDI_DETACH:
    {
        VBoxGuestSolarisRemoveIRQ(pDip);
        ddi_regs_map_free(&g_PciIOHandle);
        ddi_regs_map_free(&g_PciMMIOHandle);
        ddi_remove_minor_node(pDip, NULL);
        VbgdCommonDeleteDevExt(&g_DevExt);
        g_pDip = NULL;
        return DDI_SUCCESS;
    }

    case DDI_SUSPEND:
    {
        /** @todo implement suspend for guest driver. */
        return DDI_SUCCESS;
    }

    default:
        return DDI_FAILURE;
    }
}
Пример #3
0
/**
 * Unload the module.
 */
static void __exit vboxguestLinuxModExit(void)
{
    /*
     * Inverse order of init.
     */
    vboxguestLinuxTermDeviceNodes();
#ifdef VBOXGUEST_WITH_INPUT_DRIVER
    vboxguestLinuxTermInputDevice();
#endif
    VbgdCommonCloseSession(&g_DevExt, g_pKernelSession);
    VbgdCommonDeleteDevExt(&g_DevExt);
    vboxguestLinuxTermISR();
    pci_unregister_driver(&g_PciDriver);
    RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
    RTLogDestroy(RTLogSetDefaultInstance(NULL));
    RTR0Term();
}
Пример #4
0
/**
 * Initialize module.
 *
 * @returns appropriate status code.
 */
static int __init vboxguestLinuxModInit(void)
{
    static const char * const   s_apszGroups[] = VBOX_LOGGROUP_NAMES;
    PRTLOGGER                   pRelLogger;
    int                         rc;

    /*
     * Initialize IPRT first.
     */
    rc = RTR0Init(0);
    if (RT_FAILURE(rc))
    {
        printk(KERN_ERR DEVICE_NAME ": RTR0Init failed, rc=%d.\n", rc);
        return -EINVAL;
    }

    /*
     * Create the release log.
     * (We do that here instead of common code because we want to log
     * early failures using the LogRel macro.)
     */
    rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
                     "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
                     RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER | RTLOGDEST_USER, NULL);
    if (RT_SUCCESS(rc))
    {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
        RTLogGroupSettings(pRelLogger, g_szLogGrp);
        RTLogFlags(pRelLogger, g_szLogFlags);
        RTLogDestinations(pRelLogger, g_szLogDst);
#endif
        RTLogRelSetDefaultInstance(pRelLogger);
    }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
    g_fLoggerCreated = true;
#endif

    /*
     * Locate and initialize the PCI device.
     */
    rc = pci_register_driver(&g_PciDriver);
    if (rc >= 0 && g_pPciDev)
    {
        /*
         * Register the interrupt service routine for it.
         */
        rc = vboxguestLinuxInitISR();
        if (rc >= 0)
        {
            /*
             * Call the common device extension initializer.
             */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_X86)
            VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_AMD64)
            VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26_x64;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_X86)
            VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_AMD64)
            VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24_x64;
#else
# warning "huh? which arch + version is this?"
            VBOXOSTYPE enmOsType = VBOXOSTYPE_Linux;
#endif
            rc = VbgdCommonInitDevExt(&g_DevExt,
                                      g_IOPortBase,
                                      g_pvMMIOBase,
                                      g_cbMMIO,
                                      enmOSType,
                                      VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
            if (RT_SUCCESS(rc))
            {
                /*
                 * Create the kernel session for this driver.
                 */
                rc = VbgdCommonCreateKernelSession(&g_DevExt,
                                                  &g_pKernelSession);
                if (RT_SUCCESS(rc))
                {
                    /*
                     * Create the kernel input device.
                     */
#ifdef VBOXGUEST_WITH_INPUT_DRIVER
                    rc = vboxguestLinuxCreateInputDevice();
                    if (rc >= 0)
                    {
#endif
                        /*
                         * Finally, create the device nodes.
                         */
                        rc = vboxguestLinuxInitDeviceNodes();
                        if (rc >= 0)
                        {
                            /* some useful information for the user but don't show this on the console */
                            LogRel((DEVICE_NAME ": misc device minor %d, IRQ %d, I/O port %RTiop, MMIO at %RHp (size 0x%x)\n",
                                    g_MiscDevice.minor, g_pPciDev->irq, g_IOPortBase, g_MMIOPhysAddr, g_cbMMIO));
                            printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
                                   VBOX_VERSION_STRING " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
                            return rc;
                        }

                        /* bail out */
#ifdef VBOXGUEST_WITH_INPUT_DRIVER
                        vboxguestLinuxTermInputDevice();
                    }
                    else
                    {
                        LogRel((DEVICE_NAME ": vboxguestCreateInputDevice failed with rc=%Rrc\n", rc));
                        rc = RTErrConvertFromErrno(rc);
                    }
#endif
                    VbgdCommonCloseSession(&g_DevExt, g_pKernelSession);
                }
                VbgdCommonDeleteDevExt(&g_DevExt);
            }
            else
            {
                LogRel((DEVICE_NAME ": VbgdCommonInitDevExt failed with rc=%Rrc\n", rc));
                rc = RTErrConvertFromErrno(rc);
            }
            vboxguestLinuxTermISR();
        }
    }
    else
    {
        LogRel((DEVICE_NAME ": PCI device not found, probably running on physical hardware.\n"));
        rc = -ENODEV;
    }
    pci_unregister_driver(&g_PciDriver);
    RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
    RTLogDestroy(RTLogSetDefaultInstance(NULL));
    RTR0Term();
    return rc;
}
/**
 * PnP Request handler.
 *
 * @param  pDevObj    Device object.
 * @param  pIrp       Request packet.
 */
NTSTATUS vbgdNtPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
    PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
    PIO_STACK_LOCATION  pStack  = IoGetCurrentIrpStackLocation(pIrp);

#ifdef LOG_ENABLED
    static char *s_apszFnctName[] =
    {
        "IRP_MN_START_DEVICE",
        "IRP_MN_QUERY_REMOVE_DEVICE",
        "IRP_MN_REMOVE_DEVICE",
        "IRP_MN_CANCEL_REMOVE_DEVICE",
        "IRP_MN_STOP_DEVICE",
        "IRP_MN_QUERY_STOP_DEVICE",
        "IRP_MN_CANCEL_STOP_DEVICE",
        "IRP_MN_QUERY_DEVICE_RELATIONS",
        "IRP_MN_QUERY_INTERFACE",
        "IRP_MN_QUERY_CAPABILITIES",
        "IRP_MN_QUERY_RESOURCES",
        "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
        "IRP_MN_QUERY_DEVICE_TEXT",
        "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
        "IRP_MN_0xE",
        "IRP_MN_READ_CONFIG",
        "IRP_MN_WRITE_CONFIG",
        "IRP_MN_EJECT",
        "IRP_MN_SET_LOCK",
        "IRP_MN_QUERY_ID",
        "IRP_MN_QUERY_PNP_DEVICE_STATE",
        "IRP_MN_QUERY_BUS_INFORMATION",
        "IRP_MN_DEVICE_USAGE_NOTIFICATION",
        "IRP_MN_SURPRISE_REMOVAL",
    };
    Log(("VBoxGuest::vbgdNtGuestPnp: MinorFunction: %s\n",
         pStack->MinorFunction < RT_ELEMENTS(s_apszFnctName) ? s_apszFnctName[pStack->MinorFunction] : "Unknown"));
#endif

    NTSTATUS rc = STATUS_SUCCESS;
    switch (pStack->MinorFunction)
    {
        case IRP_MN_START_DEVICE:
        {
            Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE\n"));

            /* This must be handled first by the lower driver. */
            rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);

            if (   NT_SUCCESS(rc)
                && NT_SUCCESS(pIrp->IoStatus.Status))
            {
                Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
                     pStack->Parameters.StartDevice.AllocatedResources));

                if (!pStack->Parameters.StartDevice.AllocatedResources)
                {
                    Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
                         pDevExt, pDevExt ? pDevExt->pNextLowerDriver : NULL));
                    rc = STATUS_UNSUCCESSFUL;
                }
                else
                {
                    rc = vbgdNtInit(pDevObj, pIrp);
                }
            }

            if (NT_ERROR(rc))
            {
                Log(("VBoxGuest::vbgdNtGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc));

                /* Need to unmap memory in case of errors ... */
                vbgdNtUnmapVMMDevMemory(pDevExt);
            }
            break;
        }

        case IRP_MN_CANCEL_REMOVE_DEVICE:
        {
            Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n"));

            /* This must be handled first by the lower driver. */
            rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);

            if (NT_SUCCESS(rc) && pDevExt->devState == PENDINGREMOVE)
            {
                /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
                pDevExt->devState = pDevExt->prevDevState;
            }

            /* Complete the IRP. */
            break;
        }

        case IRP_MN_SURPRISE_REMOVAL:
        {
            Log(("VBoxGuest::vbgdNtVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n"));

            VBOXGUEST_UPDATE_DEVSTATE(pDevExt, SURPRISEREMOVED);

            /* Do nothing here actually. Cleanup is done in IRP_MN_REMOVE_DEVICE.
             * This request is not expected for VBoxGuest.
             */
            LogRel(("VBoxGuest: unexpected device removal\n"));

            /* Pass to the lower driver. */
            pIrp->IoStatus.Status = STATUS_SUCCESS;

            IoSkipCurrentIrpStackLocation(pIrp);

            rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);

            /* Do not complete the IRP. */
            return rc;
        }

        case IRP_MN_QUERY_REMOVE_DEVICE:
        {
            Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_REMOVE_DEVICE\n"));

#ifdef VBOX_REBOOT_ON_UNINSTALL
            Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
            rc = STATUS_UNSUCCESSFUL;
#endif

            if (NT_SUCCESS(rc))
            {
                VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGREMOVE);

                /* This IRP passed down to lower driver. */
                pIrp->IoStatus.Status = STATUS_SUCCESS;

                IoSkipCurrentIrpStackLocation(pIrp);

                rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
                Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));

                /* we must not do anything the IRP after doing IoSkip & CallDriver
                 * since the driver below us will complete (or already have completed) the IRP.
                 * I.e. just return the status we got from IoCallDriver */
                return rc;
            }

            /* Complete the IRP on failure. */
            break;
        }

        case IRP_MN_REMOVE_DEVICE:
        {
            Log(("VBoxGuest::vbgdNtVBoxGuestPnP: REMOVE_DEVICE\n"));

            VBOXGUEST_UPDATE_DEVSTATE(pDevExt, REMOVED);

            /* Free hardware resources. */
            /** @todo this should actually free I/O ports, interrupts, etc.
             * Update/bird: vbgdNtCleanup actually does that... So, what's there to do?  */
            rc = vbgdNtCleanup(pDevObj);
            Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: vbgdNtCleanup rc = 0x%08X\n", rc));

            /*
             * We need to send the remove down the stack before we detach,
             * but we don't need to wait for the completion of this operation
             * (and to register a completion routine).
             */
            pIrp->IoStatus.Status = STATUS_SUCCESS;

            IoSkipCurrentIrpStackLocation(pIrp);

            rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
            Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));

            IoDetachDevice(pDevExt->pNextLowerDriver);

            Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Removing device ...\n"));

            /* Destroy device extension and clean up everything else. */
            VbgdCommonDeleteDevExt(&pDevExt->Core);

            /* Remove DOS device + symbolic link. */
            UNICODE_STRING win32Name;
            RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
            IoDeleteSymbolicLink(&win32Name);

            Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Deleting device ...\n"));

            /* Last action: Delete our device! pDevObj is *not* failed
             * anymore after this call! */
            IoDeleteDevice(pDevObj);

            Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Device removed!\n"));

            /* Propagating rc from IoCallDriver. */
            return rc; /* Make sure that we don't do anything below here anymore! */
        }

        case IRP_MN_CANCEL_STOP_DEVICE:
        {
            Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));

            /* This must be handled first by the lower driver. */
            rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);

            if (NT_SUCCESS(rc) && pDevExt->devState == PENDINGSTOP)
            {
                /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
                pDevExt->devState = pDevExt->prevDevState;
            }

            /* Complete the IRP. */
            break;
        }

        case IRP_MN_QUERY_STOP_DEVICE:
        {
            Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_STOP_DEVICE\n"));

#ifdef VBOX_REBOOT_ON_UNINSTALL
            Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
            pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
#endif

            if (NT_SUCCESS(rc))
            {
                VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGSTOP);

                /* This IRP passed down to lower driver. */
                pIrp->IoStatus.Status = STATUS_SUCCESS;

                IoSkipCurrentIrpStackLocation(pIrp);

                rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
                Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));

                /* we must not do anything with the IRP after doing IoSkip & CallDriver
                 * since the driver below us will complete (or already have completed) the IRP.
                 * I.e. just return the status we got from IoCallDriver */
                return rc;
            }

            /* Complete the IRP on failure. */
            break;
        }

        case IRP_MN_STOP_DEVICE:
        {
            Log(("VBoxGuest::vbgdNtVBoxGuestPnP: STOP_DEVICE\n"));

            VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED);

            /* Free hardware resources. */
            /** @todo this should actually free I/O ports, interrupts, etc.
             * Update/bird: vbgdNtCleanup actually does that... So, what's there to do?  */
            rc = vbgdNtCleanup(pDevObj);
            Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc));

            /* Pass to the lower driver. */
            pIrp->IoStatus.Status = STATUS_SUCCESS;

            IoSkipCurrentIrpStackLocation(pIrp);

            rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
            Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));

            return rc;
        }

        default:
        {
            IoSkipCurrentIrpStackLocation(pIrp);
            rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
            return rc;
        }
    }

    pIrp->IoStatus.Status = rc;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    Log(("VBoxGuest::vbgdNtGuestPnp: Returning with rc = 0x%x\n", rc));
    return rc;
}
static int VBoxGuestFreeBSDAttach(device_t pDevice)
{
    int rc = VINF_SUCCESS;
    int iResId = 0;
    struct VBoxGuestDeviceState *pState = NULL;

    cUsers = 0;

    /*
     * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
     */
    rc = RTR0Init(0);
    if (RT_FAILURE(rc))
    {
        LogFunc(("RTR0Init failed.\n"));
        return ENXIO;
    }

    pState = device_get_softc(pDevice);

    /*
     * Allocate I/O port resource.
     */
    iResId                 = PCIR_BAR(0);
    pState->pIOPortRes     = bus_alloc_resource_any(pDevice, SYS_RES_IOPORT, &iResId, RF_ACTIVE);
    pState->uIOPortBase    = rman_get_start(pState->pIOPortRes);
    pState->iIOPortResId   = iResId;
    if (pState->uIOPortBase)
    {
        /*
         * Map the MMIO region.
         */
        iResId                   = PCIR_BAR(1);
        pState->pVMMDevMemRes    = bus_alloc_resource_any(pDevice, SYS_RES_MEMORY, &iResId, RF_ACTIVE);
        pState->VMMDevMemHandle  = rman_get_bushandle(pState->pVMMDevMemRes);
        pState->VMMDevMemSize    = rman_get_size(pState->pVMMDevMemRes);

        pState->pMMIOBase       = rman_get_virtual(pState->pVMMDevMemRes);
        pState->iVMMDevMemResId = iResId;
        if (pState->pMMIOBase)
        {
            /*
             * Call the common device extension initializer.
             */
            rc = VbgdCommonInitDevExt(&g_DevExt, pState->uIOPortBase,
                                      pState->pMMIOBase, pState->VMMDevMemSize,
#if ARCH_BITS == 64
                                      VBOXOSTYPE_FreeBSD_x64,
#else
                                      VBOXOSTYPE_FreeBSD,
#endif
                                      VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
            if (RT_SUCCESS(rc))
            {
                /*
                 * Add IRQ of VMMDev.
                 */
                rc = VBoxGuestFreeBSDAddIRQ(pDevice, pState);
                if (RT_SUCCESS(rc))
                {
                    /*
                     * Configure device cloning.
                     */
                    clone_setup(&g_pVBoxGuestFreeBSDClones);
                    g_VBoxGuestFreeBSDEHTag = EVENTHANDLER_REGISTER(dev_clone, VBoxGuestFreeBSDClone, 0, 1000);
                    if (g_VBoxGuestFreeBSDEHTag)
                    {
                        printf(DEVICE_NAME ": loaded successfully\n");
                        return 0;
                    }

                    printf(DEVICE_NAME ": EVENTHANDLER_REGISTER(dev_clone,,,) failed\n");
                    clone_cleanup(&g_pVBoxGuestFreeBSDClones);
                    VBoxGuestFreeBSDRemoveIRQ(pDevice, pState);
                }
                else
                    printf((DEVICE_NAME ":VbgdCommonInitDevExt failed.\n"));
                VbgdCommonDeleteDevExt(&g_DevExt);
            }
            else
                printf((DEVICE_NAME ":VBoxGuestFreeBSDAddIRQ failed.\n"));
        }
        else
            printf((DEVICE_NAME ":MMIO region setup failed.\n"));
    }
    else
        printf((DEVICE_NAME ":IOport setup failed.\n"));

    RTR0Term();
    return ENXIO;
}
/**
 * Attach entry point, to attach a device to the system or resume it.
 *
 * @param   pDip            The module structure instance.
 * @param   enmCmd          Attach type (ddi_attach_cmd_t)
 *
 * @return  corresponding solaris error code.
 */
static int VBoxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
{
    LogFlow((DEVICE_NAME "::Attach\n"));
    switch (enmCmd)
    {
    case DDI_ATTACH:
    {
        if (g_pDip)
        {
            LogRel((DEVICE_NAME "::Attach: Only one instance supported.\n"));
            return DDI_FAILURE;
        }

        int instance = ddi_get_instance(pDip);

        /*
         * Enable resources for PCI access.
         */
        ddi_acc_handle_t PciHandle;
        int rc = pci_config_setup(pDip, &PciHandle);
        if (rc == DDI_SUCCESS)
        {
            /*
             * Map the register address space.
             */
            caddr_t baseAddr;
            ddi_device_acc_attr_t deviceAttr;
            deviceAttr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
            deviceAttr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
            deviceAttr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
            deviceAttr.devacc_attr_access = DDI_DEFAULT_ACC;
            rc = ddi_regs_map_setup(pDip, 1, &baseAddr, 0, 0, &deviceAttr, &g_PciIOHandle);
            if (rc == DDI_SUCCESS)
            {
                /*
                 * Read size of the MMIO region.
                 */
                g_uIOPortBase = (uintptr_t)baseAddr;
                rc = ddi_dev_regsize(pDip, 2, &g_cbMMIO);
                if (rc == DDI_SUCCESS)
                {
                    rc = ddi_regs_map_setup(pDip, 2, &g_pMMIOBase, 0, g_cbMMIO, &deviceAttr,
                                            &g_PciMMIOHandle);
                    if (rc == DDI_SUCCESS)
                    {
                        /*
                         * Add IRQ of VMMDev.
                         */
                        rc = VBoxGuestSolarisAddIRQ(pDip);
                        if (rc == DDI_SUCCESS)
                        {
                            /*
                             * Call the common device extension initializer.
                             */
                            rc = VbgdCommonInitDevExt(&g_DevExt, g_uIOPortBase, g_pMMIOBase, g_cbMMIO,
#if ARCH_BITS == 64
                                                      VBOXOSTYPE_Solaris_x64,
#else
                                                      VBOXOSTYPE_Solaris,
#endif
                                                      VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
                            if (RT_SUCCESS(rc))
                            {
                                rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0 /* fFlags */);
                                if (rc == DDI_SUCCESS)
                                {
                                    g_pDip = pDip;
                                    pci_config_teardown(&PciHandle);
                                    return DDI_SUCCESS;
                                }

                                LogRel((DEVICE_NAME "::Attach: ddi_create_minor_node failed.\n"));
                                VbgdCommonDeleteDevExt(&g_DevExt);
                            }
                            else
                                LogRel((DEVICE_NAME "::Attach: VbgdCommonInitDevExt failed.\n"));
                            VBoxGuestSolarisRemoveIRQ(pDip);
                        }
                        else
                            LogRel((DEVICE_NAME "::Attach: VBoxGuestSolarisAddIRQ failed.\n"));
                        ddi_regs_map_free(&g_PciMMIOHandle);
                    }
                    else
                        LogRel((DEVICE_NAME "::Attach: ddi_regs_map_setup for MMIO region failed.\n"));
                }
                else
                    LogRel((DEVICE_NAME "::Attach: ddi_dev_regsize for MMIO region failed.\n"));
                ddi_regs_map_free(&g_PciIOHandle);
            }
            else
                LogRel((DEVICE_NAME "::Attach: ddi_regs_map_setup for IOport failed.\n"));
            pci_config_teardown(&PciHandle);
        }
        else
            LogRel((DEVICE_NAME "::Attach: pci_config_setup failed rc=%d.\n", rc));
        return DDI_FAILURE;
    }

    case DDI_RESUME:
    {
        /** @todo implement resume for guest driver. */
        return DDI_SUCCESS;
    }

    default:
        return DDI_FAILURE;
    }
}
/**
 * Start this service.
 */
bool org_virtualbox_VBoxGuest::start(IOService *pProvider)
{
    if (!IOService::start(pProvider))
        return false;

    /* Low level initialization should be performed only once */
    if (!ASMAtomicCmpXchgBool(&g_fInstantiated, true, false))
    {
        IOService::stop(pProvider);
        return false;
    }

    m_pIOPCIDevice = OSDynamicCast(IOPCIDevice, pProvider);
    if (m_pIOPCIDevice)
    {
        if (isVmmDev(m_pIOPCIDevice))
        {
            /* Enable memory response from VMM device */
            m_pIOPCIDevice->setMemoryEnable(true);
            m_pIOPCIDevice->setIOEnable(true);

            IOMemoryDescriptor *pMem = m_pIOPCIDevice->getDeviceMemoryWithIndex(0);
            if (pMem)
            {
                IOPhysicalAddress IOPortBasePhys = pMem->getPhysicalAddress();
                /* Check that returned value is from I/O port range (at least it is 16-bit lenght) */
                if((IOPortBasePhys >> 16) == 0)
                {

                    RTIOPORT IOPortBase = (RTIOPORT)IOPortBasePhys;
                    void    *pvMMIOBase = NULL;
                    uint32_t cbMMIO     = 0;
                    m_pMap = m_pIOPCIDevice->mapDeviceMemoryWithIndex(1);
                    if (m_pMap)
                    {
                        pvMMIOBase = (void *)m_pMap->getVirtualAddress();
                        cbMMIO     = m_pMap->getLength();
                    }

                    int rc = VbgdCommonInitDevExt(&g_DevExt,
                                                  IOPortBase,
                                                  pvMMIOBase,
                                                  cbMMIO,
#if ARCH_BITS == 64
                                                  VBOXOSTYPE_MacOS_x64,
#else
                                                  VBOXOSTYPE_MacOS,
#endif
                                                  0);
                    if (RT_SUCCESS(rc))
                    {
                        rc = VbgdDarwinCharDevInit();
                        if (rc == KMOD_RETURN_SUCCESS)
                        {
                            if (setupVmmDevInterrupts(pProvider))
                            {
                                /* register the service. */
                                registerService();
                                LogRel(("VBoxGuest: IOService started\n"));
                                return true;
                            }

                            LogRel(("VBoxGuest: Failed to set up interrupts\n"));
                            VbgdDarwinCharDevRemove();
                        }
                        else
                            LogRel(("VBoxGuest: Failed to initialize character device (rc=%d).\n", rc));

                        VbgdCommonDeleteDevExt(&g_DevExt);
                    }
                    else
                        LogRel(("VBoxGuest: Failed to initialize common code (rc=%d).\n", rc));

                    if (m_pMap)
                    {
                        m_pMap->release();
                        m_pMap = NULL;
                    }
                }
            }
            else
                LogRel(("VBoxGuest: The device missing is the I/O port range (#0).\n"));
        }
        else