/**
 * Stop this service.
 */
void org_virtualbox_VBoxVFS::stop(IOService *pProvider)
{
    int rc;

    AssertReturnVoid(ASMAtomicReadBool(&g_fInstantiated));

    rc = VBoxVFSUnRegisterFilesystem();
    if (RT_FAILURE(rc))
    {
        PERROR("VBoxVFS filesystem is busy. Make sure all "
               "shares are unmounted (%d)", rc);
    }

    vboxDisconnect(&g_vboxSFClient);
    PINFO("VBox client disconnected");

    vboxUninit();
    PINFO("Low level uninit done");

    coreService->release();
    PINFO("VBoxGuest service released");

    IOService::stop(pProvider);

    ASMAtomicWriteBool(&g_fInstantiated, false);

    PINFO("Successfully stopped I/O kit class instance");
}
IOService * IOPlatformExpert::createNub( OSDictionary * from )
{
    IOService *		nub;

    nub = new IOPlatformDevice;
    if(nub) {
	if( !nub->init( from )) {
	    nub->release();
	    nub = 0;
	}
    }
    return( nub);
}
static IOReturn
IOGetVolumeCryptKey(dev_t block_dev,  OSString ** pKeyUUID,
                    uint8_t * volumeCryptKey, size_t keySize)
{
    IOReturn         err;
    IOService *      part;
    OSString *       keyUUID = 0;
    OSString *       keyStoreUUID = 0;
    uuid_t           volumeKeyUUID;
    aks_volume_key_t vek;

    static IOService * sKeyStore;

    part = IOCopyMediaForDev(block_dev);
    if (!part) return (kIOReturnNotFound);

    err = part->callPlatformFunction(PLATFORM_FUNCTION_GET_MEDIA_ENCRYPTION_KEY_UUID, false,
                                     (void *) &keyUUID, (void *) &keyStoreUUID, NULL, NULL);
    if ((kIOReturnSuccess == err) && keyUUID && keyStoreUUID)
    {
//            IOLog("got volume key %s\n", keyStoreUUID->getCStringNoCopy());

        if (!sKeyStore)
            sKeyStore = (IOService *) IORegistryEntry::fromPath(AKS_SERVICE_PATH, gIOServicePlane);
        if (sKeyStore)
            err = uuid_parse(keyStoreUUID->getCStringNoCopy(), volumeKeyUUID);
        else
            err = kIOReturnNoResources;
        if (kIOReturnSuccess == err)
            err = sKeyStore->callPlatformFunction(gAKSGetKey, true, volumeKeyUUID, &vek, NULL, NULL);
        if (kIOReturnSuccess != err)
            IOLog("volume key err 0x%x\n", err);
        else
        {
            if (vek.key.keybytecount < keySize) keySize = vek.key.keybytecount;
            bcopy(&vek.key.keybytes[0], volumeCryptKey, keySize);
        }
        bzero(&vek, sizeof(vek));

    }
    part->release();
    if (pKeyUUID) *pKeyUUID = keyUUID;

    return (err);
}
bool IOHIDInterface::matchPropertyTable(
                                OSDictionary *              table, 
                                SInt32 *                    score)
{
    IOService * provider;
    bool        ret;
    RETAIN_ON_STACK(this);
    
    if ( !super::matchPropertyTable(table, score) || !(provider = OSDynamicCast(IOService, copyParentEntry(gIOServicePlane))) )
        return false;
        
    // We should retain a reference to our provider while calling matchPropertyTable.
    // This is necessary in a situation where a user space process could be searching
    // the registry during termination.    
    ret = provider->matchPropertyTable(table, score);
    
    provider->release();
    
    return ret;
}
bool
IOATABlockStorageDriver::createNub ( IOService * provider )
{
	
	IOService *		nub = NULL;
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::createNub entering.\n" ) );
	
	// Instantiate a generic hard disk nub so a generic driver
	// can match above us.
	nub = instantiateNub ( );
	if ( nub == NULL )
	{
		
		ERROR_LOG ( ( "IOATABlockStorageDriver::createNub instantiateNub() failed, returning false\n" ) );
		return false;
		
	}
	
	nub->init ( );
	
	if ( !nub->attach ( this ) )
	{
		
		// panic since the nub can't attach
		PANIC_NOW ( ( "IOATABlockStorageDriver::createNub() unable to attach nub" ) );
		return false;
		
	}
	
	nub->registerService ( );
	
	// The IORegistry retains the nub, so we can release our refcount
	// because we don't need it any more.
	nub->release ( );
	
	STATUS_LOG ( ( "IOATABlockStorageDriver::createNub exiting true.\n" ) );
	
	return true;
	
}
BrcmFirmwareStore* BrcmPatchRAM::getFirmwareStore()
{
    if (!mFirmwareStore)
    {
        // check to see if it already loaded
        mFirmwareStore = OSDynamicCast(BrcmFirmwareStore, waitForMatchingService(serviceMatching(kBrcmFirmwareStoreService), 0));
        if (!mFirmwareStore)
        {
            // not loaded, so publish personality...
            publishResourcePersonality(kBrcmFirmwareStoreService);
            // and wait...
            mFirmwareStore = OSDynamicCast(BrcmFirmwareStore, waitForMatchingService(serviceMatching(kBrcmFirmwareStoreService), 2000UL*1000UL*1000UL));
        }

#ifdef NON_RESIDENT
        // also need BrcmPatchRAMResidency
        IOService* residency = OSDynamicCast(BrcmPatchRAMResidency, waitForMatchingService(serviceMatching(kBrcmPatchRAMResidency), 0));
        if (!residency)
        {
            // not loaded, so publish personality...
            publishResourcePersonality(kBrcmPatchRAMResidency);
            // and wait...
            residency = OSDynamicCast(BrcmPatchRAMResidency, waitForMatchingService(serviceMatching(kBrcmPatchRAMResidency), 2000UL*1000UL*1000UL));
            if (residency)
                residency->release();
            else
                AlwaysLog("[%04x:%04x]: BrcmPatchRAMResidency does not appear to be available.\n", mVendorId, mProductId);
        }
#endif
    }
    
    if (!mFirmwareStore)
        AlwaysLog("[%04x:%04x]: BrcmFirmwareStore does not appear to be available.\n", mVendorId, mProductId);
    
    return mFirmwareStore;
}
/**
 * Start this service.
 */
bool org_virtualbox_VBoxVFS::start(IOService *pProvider)
{
    int rc;

    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;
    }

    /* Wait for VBoxGuest to be started */
    coreService = waitForCoreService();
    if (coreService)
    {
        rc = vboxInit();
        if (RT_SUCCESS(rc))
        {
            /* Connect to the host service. */
            rc = vboxConnect(&g_vboxSFClient);
            if (RT_SUCCESS(rc))
            {
                PINFO("VBox client connected");
                rc = vboxCallSetUtf8(&g_vboxSFClient);
                if (RT_SUCCESS(rc))
                {
                    rc = VBoxVFSRegisterFilesystem();
                    if (RT_SUCCESS(rc))
                    {
                        registerService();
                        PINFO("Successfully started I/O kit class instance");
                        return true;
                    }
                    PERROR("Unable to register VBoxVFS filesystem");
                }
                else
                {
                    PERROR("vboxCallSetUtf8 failed: rc=%d", rc);
                }
                vboxDisconnect(&g_vboxSFClient);
            }
            else
            {
                PERROR("Failed to get connection to host: rc=%d", rc);
            }
            vboxUninit();
        }
        else
        {
            PERROR("Failed to initialize low level library");
        }
        coreService->release();
    }
    else
    {
        PERROR("VBoxGuest KEXT not started");
    }

    ASMAtomicXchgBool(&g_fInstantiated, false);
    IOService::stop(pProvider);

    return false;
}
IOReturn
IOPolledFileOpen(const char * filename,
                 uint64_t setFileSize, uint64_t fsFreeSize,
                 void * write_file_addr, size_t write_file_len,
                 IOPolledFileIOVars ** fileVars,
                 OSData ** imagePath,
                 uint8_t * volumeCryptKey, size_t keySize)
{
    IOReturn             err = kIOReturnSuccess;
    IOPolledFileIOVars * vars;
    _OpenFileContext     ctx;
    OSData *             extentsData;
    OSNumber *           num;
    IOService *          part = 0;
    dev_t                block_dev;
    dev_t                image_dev;
    AbsoluteTime         startTime, endTime;
    uint64_t             nsec;

    vars = IONew(IOPolledFileIOVars, 1);
    if (!vars) return (kIOReturnNoMemory);
    bzero(vars, sizeof(*vars));
    vars->allocated = true;

    do
    {
        extentsData = OSData::withCapacity(32);
        ctx.extents = extentsData;
        ctx.size    = 0;
        clock_get_uptime(&startTime);

        vars->fileRef = kern_open_file_for_direct_io(filename,
                        (write_file_addr != NULL) || (0 != setFileSize),
                        &file_extent_callback, &ctx,
                        setFileSize,
                        fsFreeSize,
                        // write file:
                        0, write_file_addr, write_file_len,
                        // results
                        &block_dev,
                        &image_dev,
                        &vars->block0,
                        &vars->maxiobytes,
                        &vars->flags);
#if 0
        uint32_t msDelay = (131071 & random());
        HIBLOG("sleep %d\n", msDelay);
        IOSleep(msDelay);
#endif
        clock_get_uptime(&endTime);
        SUB_ABSOLUTETIME(&endTime, &startTime);
        absolutetime_to_nanoseconds(endTime, &nsec);

        if (!vars->fileRef) err = kIOReturnNoSpace;

        HIBLOG("kern_open_file_for_direct_io took %qd ms\n", nsec / 1000000ULL);
        if (kIOReturnSuccess != err) break;

        HIBLOG("Opened file %s, size %qd, extents %ld, maxio %qx ssd %d\n", filename, ctx.size,
               (extentsData->getLength() / sizeof(IOPolledFileExtent)) - 1,
               vars->maxiobytes, kIOPolledFileSSD & vars->flags);
        assert(!vars->block0);
        if (extentsData->getLength() < sizeof(IOPolledFileExtent))
        {
            err = kIOReturnNoSpace;
            break;
        }

        vars->fileSize = ctx.size;
        vars->extentMap = (IOPolledFileExtent *) extentsData->getBytesNoCopy();

        part = IOCopyMediaForDev(image_dev);
        if (!part)
        {
            err = kIOReturnNotFound;
            break;
        }

        if (!(vars->pollers = IOPolledFilePollers::copyPollers(part))) break;

        if ((num = OSDynamicCast(OSNumber, part->getProperty(kIOMediaPreferredBlockSizeKey))))
            vars->blockSize = num->unsigned32BitValue();
        if (vars->blockSize < 4096) vars->blockSize = 4096;

        HIBLOG("polled file major %d, minor %d, blocksize %ld, pollers %d\n",
               major(image_dev), minor(image_dev), (long)vars->blockSize,
               vars->pollers->pollers->getCount());

        OSString * keyUUID = NULL;
        if (volumeCryptKey)
        {
            err = IOGetVolumeCryptKey(block_dev, &keyUUID, volumeCryptKey, keySize);
        }

        *fileVars    = vars;
        vars->fileExtents = extentsData;

        // make imagePath
        OSData * data;
        if (imagePath)
        {
#if defined(__i386__) || defined(__x86_64__)
            char str2[24 + sizeof(uuid_string_t) + 2];

            if (keyUUID)
                snprintf(str2, sizeof(str2), "%qx:%s",
                         vars->extentMap[0].start, keyUUID->getCStringNoCopy());
            else
                snprintf(str2, sizeof(str2), "%qx", vars->extentMap[0].start);

            err = IOService::getPlatform()->callPlatformFunction(
                      gIOCreateEFIDevicePathSymbol, false,
                      (void *) part, (void *) str2,
                      (void *) (uintptr_t) true, (void *) &data);
#else
            data = 0;
            err = kIOReturnSuccess;
#endif
            if (kIOReturnSuccess != err)
            {
                HIBLOG("error 0x%x getting path\n", err);
                break;
            }
            *imagePath = data;
        }
    }
    while (false);

    if (kIOReturnSuccess != err)
    {
        HIBLOG("error 0x%x opening polled file\n", err);
        IOPolledFileClose(&vars, 0, 0, 0, 0, 0);
    }

    if (part) part->release();

    return (err);
}