コード例 #1
0
__private_extern__ kern_return_t
chudxnu_cpu_timer_callback_enter(
	chudxnu_cpu_timer_callback_func_t	func,
	uint32_t				time,
	uint32_t				units)
{
	chudcpu_data_t	*chud_proc_info;
	boolean_t	oldlevel;

	oldlevel = ml_set_interrupts_enabled(FALSE);
	chud_proc_info = (chudcpu_data_t *)(current_cpu_datap()->cpu_chud);

	// cancel any existing callback for this cpu
	timer_call_cancel(&(chud_proc_info->cpu_timer_call));

	chud_proc_info->cpu_timer_callback_fn = func;

	clock_interval_to_deadline(time, units, &(chud_proc_info->t_deadline));
	timer_call_setup(&(chud_proc_info->cpu_timer_call),
			 chudxnu_private_cpu_timer_callback, NULL);
	timer_call_enter(&(chud_proc_info->cpu_timer_call),
			 chud_proc_info->t_deadline);

	KERNEL_DEBUG_CONSTANT(
		MACHDBG_CODE(DBG_MACH_CHUD,
			     CHUD_TIMER_CALLBACK_ENTER) | DBG_FUNC_NONE,
		(uint32_t) func, time, units, 0, 0);

	ml_set_interrupts_enabled(oldlevel);
	return KERN_SUCCESS;
}
コード例 #2
0
ファイル: testthreadcall.cpp プロジェクト: DJHartley/xnu
bool
testthreadcall::start( IOService * provider )
{
	boolean_t ret;
	uint64_t deadline;
    
    IOLog("%s\n", __PRETTY_FUNCTION__);
    
    if (!super::start(provider)) {
        return false;
    }
    
    IOLog("Attempting thread_call_allocate\n");
	tcall = thread_call_allocate(thread_call_test_func, this);
    IOLog("thread_call_t %p\n", tcall);
    
	tlock = IOSimpleLockAlloc();
	IOLog("tlock %p\n", tlock);
	
	clock_interval_to_deadline(5, NSEC_PER_SEC, &deadline);
	IOLog("%d sec deadline is %llu\n", 5, deadline);
	
	ret = thread_call_enter_delayed(tcall, deadline);
	
    return true;
}
void
SCSIPressurePathManager::PortBandwidthGlobals::SetTimer ( void )
{
	
	AbsoluteTime	time;
	
	clock_interval_to_deadline ( 3000, kMillisecondScale, &time );
	thread_call_enter_delayed ( gThread, time );
	
}
コード例 #4
0
static IOReturn
IOPolledFilePollersIODone(IOPolledFilePollers * vars, bool abortable)
{
    IOReturn            err = kIOReturnSuccess;
    int32_t		idx = 0;
    IOPolledInterface * poller;
    AbsoluteTime        deadline;

    if (!vars->io) return (kIOReturnSuccess);

    abortable &= vars->abortable;

    clock_interval_to_deadline(2000, kMillisecondScale, &deadline);

    while (-1 == vars->ioStatus)
    {
        for (idx = 0;
                (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
                idx++)
        {
            IOReturn newErr;
            newErr = poller->checkForWork();
            if ((newErr == kIOReturnAborted) && !abortable)
                newErr = kIOReturnSuccess;
            if (kIOReturnSuccess == err)
                err = newErr;
        }
        if ((false) && (kIOReturnSuccess == err) && (mach_absolute_time() > AbsoluteTime_to_scalar(&deadline)))
        {
            HIBLOG("IOPolledInterface::forced timeout\n");
            vars->ioStatus = kIOReturnTimeout;
        }
    }
    vars->io = false;

#if HIBERNATION
    if ((kIOReturnSuccess == err) && abortable && hibernate_should_abort())
    {
        err = kIOReturnAborted;
        HIBLOG("IOPolledInterface::checkForWork sw abort\n");
    }
#endif

    if (err)
    {
        HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx, err);
    }
    else
    {
        err = vars->ioStatus;
        if (kIOReturnSuccess != err) HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err);
    }

    return (err);
}
コード例 #5
0
ファイル: clock.c プロジェクト: Prajna/xnu
void
delay_for_interval(
	uint32_t		interval,
	uint32_t		scale_factor)
{
	uint64_t		end;

	clock_interval_to_deadline(interval, scale_factor, &end);

	clock_delay_until(end);
}
コード例 #6
0
/*
 *	Set a timeout.
 *
 *	fcn:		function to call
 *	param:		parameter to pass to function
 *	interval:	timeout interval, in hz.
 */
void
timeout(
	timeout_fcn_t			fcn,
	void					*param,
	int						interval)
{
	uint64_t		deadline;

	clock_interval_to_deadline(interval, NSEC_PER_SEC / hz, &deadline);
	thread_call_func_delayed((thread_call_func_t)fcn, param, deadline);
}
コード例 #7
0
__private_extern__ kern_return_t
chudxnu_timer_callback_enter(
	chud_timer_t timer,
	uint32_t param1,
	uint32_t time,
	uint32_t units)
{
    uint64_t t_delay;
    clock_interval_to_deadline(time, units, &t_delay);
    thread_call_enter1_delayed((thread_call_t)timer, (thread_call_param_t)param1, t_delay);
    return KERN_SUCCESS;
}
コード例 #8
0
static int rtR0ThreadDarwinSleepCommon(RTMSINTERVAL cMillies)
{
    RT_ASSERT_PREEMPTIBLE();
    IPRT_DARWIN_SAVE_EFL_AC();

    uint64_t u64Deadline;
    clock_interval_to_deadline(cMillies, kMillisecondScale, &u64Deadline);
    clock_delay_until(u64Deadline);

    IPRT_DARWIN_RESTORE_EFL_AC();
    return VINF_SUCCESS;
}
コード例 #9
0
void OSMetaClass::considerUnloads()
{
    static thread_call_t unloadCallout;
    AbsoluteTime when;

    mutex_lock(loadLock);

    if (!unloadCallout)
        unloadCallout = thread_call_allocate(&_OSMetaClassConsiderUnloads, 0);

    thread_call_cancel(unloadCallout);
    clock_interval_to_deadline(sConsiderUnloadDelay, 1000 * 1000 * 1000, &when);
    thread_call_enter_delayed(unloadCallout, when);

    mutex_unlock(loadLock);
}
コード例 #10
0
ファイル: iwi3945.cpp プロジェクト: Klozz/iwidarwin
void darwin_iwi3945::queue_te(int num, thread_call_func_t func, thread_call_param_t par, UInt32 timei, bool start)
{
	if (tlink[num]) queue_td(num,NULL);
	//IWI_DEBUG("queue_te0 %d\n",tlink[num]);
	if (!tlink[num]) tlink[num]=thread_call_allocate(func,this);
	//IWI_DEBUG("queue_te1 %d\n",tlink[num]);
	uint64_t timei2;
	if (timei) clock_interval_to_deadline(timei,kMillisecondScale,&timei2);
	//IWI_DEBUG("queue_te time %d %d\n",timei,timei2);
	int r;
	if (start==true && tlink[num])
	{
		if (!par && !timei)	r=thread_call_enter(tlink[num]);
		if (!par && timei)	r=thread_call_enter_delayed(tlink[num],timei2);
		if (par && !timei)	r=thread_call_enter1(tlink[num],par);
		if (par && timei)	r=thread_call_enter1_delayed(tlink[num],par,timei2);
	}
	//IWI_DEBUG("queue_te result %d\n",r);
}
コード例 #11
0
ファイル: serial_general.c プロジェクト: aglab2/darwin-xnu
void
serial_keyboard_poll(void)
{
	int chr;
	uint64_t next;

	while(1) {
		chr = _serial_getc(0, 1, 0, 1);	/* Get a character if there is one */
		if(chr < 0) /* The serial buffer is empty */
			break;
		cons_cinput((char)chr);			/* Buffer up the character */
	}

	clock_interval_to_deadline(16, 1000000, &next);	/* Get time of pop */

	assert_wait_deadline((event_t)serial_keyboard_poll, THREAD_UNINT, next);	/* Show we are "waiting" */
	thread_block((thread_continue_t)serial_keyboard_poll);	/* Wait for it */
	panic("serial_keyboard_poll: Shouldn't never ever get here...\n");
}
コード例 #12
0
__private_extern__
kern_return_t chudxnu_cpu_timer_callback_enter(chudxnu_cpu_timer_callback_func_t func, uint32_t time, uint32_t units)
{
    int cpu;
    boolean_t oldlevel;

    oldlevel = ml_set_interrupts_enabled(FALSE);
    cpu = cpu_number();

    timer_call_cancel(&(cpu_timer_call[cpu])); // cancel any existing callback for this cpu

    cpu_timer_callback_fn[cpu] = func;

    clock_interval_to_deadline(time, units, &(t_deadline[cpu]));
    timer_call_setup(&(cpu_timer_call[cpu]), chudxnu_private_cpu_timer_callback, NULL);
    timer_call_enter(&(cpu_timer_call[cpu]), t_deadline[cpu]);

    ml_set_interrupts_enabled(oldlevel);
    return KERN_SUCCESS;
}
コード例 #13
0
IOReturn NoSleepExtension::clamshellEventInterestHandler(UInt32 messageType, IOService * provider,
                                                         void * messageArgument, vm_size_t argSize)
{
    if(messageType == kIOPMMessageClamshellStateChange)
    {
#ifdef DEBUG
        IOLog("%s[%p]::%s(%u, %p, %p, %lu)\n", getName(), this, __FUNCTION__,
              (unsigned int)messageType, provider, messageArgument, (long unsigned int)argSize);
#endif
        
        clamshellState = (bool)(((uintptr_t)messageArgument) & kClamshellStateBit);
        clamshellShouldSleep = (bool)(((uintptr_t)messageArgument) & kClamshellSleepBit);
        isClamshellStateInitialized = true;
        
        if((getCurrentSleepSuppressionState() == kNoSleepStateEnabled)) {
            setUserSleepDisabled(true);
            
            UInt64 deadline;
            clock_interval_to_deadline(10, kSecondScale, &deadline);
            thread_call_enter_delayed(delayTimer, deadline);
            
            if(clamshellShouldSleep) {
                pRootDomain->receivePowerNotification(kIOPMDisableClamshell);
            }

            // Lock screen when lid closed
            if(clamshellState == true && oldClamshellState == false) {
                lockScreen();
                //notify_
                //notify_post("com.apple.loginwindow.notify");
                //mach_port_t bp = bootstrap_port;
                //task_get_bootstrap_port(bootstrap_port, &bp);
            }
        }
        
        oldClamshellState = clamshellState;
    } 
    
    return kIOReturnSuccess;
}
コード例 #14
0
void
IOCatalogue::ping(thread_call_param_t arg, thread_call_param_t)
{
    IOCatalogue 	 * self = (IOCatalogue *) arg;
    OSOrderedSet         * set;
    OSDictionary         * table;
    int	                   newLimit;

    set = OSOrderedSet::withCapacity( 1 );

    IOLockLock( &self->lock );

    for( newLimit = 0; newLimit < kDriversPerIter; newLimit++) {
        table = (OSDictionary *) self->array->getObject(
                    hackLimit + newLimit );
        if( table) {
            set->setLastObject( table );

            OSSymbol * sym = (OSSymbol *) table->getObject(gIOClassKey);
            kprintf("enabling %s\n", sym->getCStringNoCopy());

        } else {
            newLimit--;
            break;
        }
    }

    IOService::catalogNewDrivers( set );

    hackLimit += newLimit;
    self->generation++;

    IOLockUnlock( &self->lock );

    if( kDriversPerIter == newLimit) {
        AbsoluteTime deadline;
        clock_interval_to_deadline(500, kMillisecondScale);
        thread_call_func_delayed(ping, this, deadline);
    }
}
コード例 #15
0
int PEHaltRestart(unsigned int type)
{
  IOPMrootDomain    *pmRootDomain = IOService::getPMRootDomain();
  bool              noWaitForResponses;
  AbsoluteTime      deadline;
  thread_call_t     shutdown_hang;
  
  if(type == kPEHaltCPU || type == kPERestartCPU)
  {
    /* Notify IOKit PM clients of shutdown/restart
       Clients subscribe to this message with a call to
       IOService::registerInterest()
    */
    
    /* Spawn a thread that will panic in 30 seconds. 
       If all goes well the machine will be off by the time
       the timer expires.
     */
    shutdown_hang = thread_call_allocate( &IOPMPanicOnShutdownHang, (thread_call_param_t) type);
    clock_interval_to_deadline( 30, kSecondScale, &deadline );
    thread_call_enter1_delayed( shutdown_hang, 0, deadline );
    
    noWaitForResponses = pmRootDomain->tellChangeDown2(type); 
    /* This notification should have few clients who all do 
       their work synchronously.
             
       In this "shutdown notification" context we don't give
       drivers the option of working asynchronously and responding 
       later. PM internals make it very hard to wait for asynchronous
       replies. In fact, it's a bad idea to even be calling
       tellChangeDown2 from here at all.
     */
   }

  if (gIOPlatform) return gIOPlatform->haltRestart(type);
  else return -1;
}
コード例 #16
0
/*********************************************************************
* Initialize the IOCatalog object.
*********************************************************************/
bool IOCatalogue::init(OSArray * initArray)
{
    OSDictionary         * dict;

    if ( !super::init() )
        return false;

    generation = 1;

    array = initArray;
    array->retain();
    kernelTables = OSCollectionIterator::withCollection( array );

    gIOCatalogLock = IOLockAlloc();

    lock     = gIOCatalogLock;
#if __ppc__ || __i386__
    kld_lock = NULL;
#endif /* __ppc__ || __i386__ */

    kernelTables->reset();
    while( (dict = (OSDictionary *) kernelTables->getNextObject())) {
        UniqueProperties(dict);
        if( 0 == dict->getObject( gIOClassKey ))
            IOLog("Missing or bad \"%s\" key\n",
                  gIOClassKey->getCStringNoCopy());
    }

#if CATALOGTEST
    AbsoluteTime deadline;
    clock_interval_to_deadline( 1000, kMillisecondScale );
    thread_call_func_delayed( ping, this, deadline );
#endif

    return true;
}
コード例 #17
0
ファイル: ipc_mqueue.c プロジェクト: Apple-FOSS-Mirror/xnu
wait_result_t
ipc_mqueue_receive_on_thread(
        ipc_mqueue_t            mqueue,
	mach_msg_option_t       option,
	mach_msg_size_t         max_size,
	mach_msg_timeout_t      rcv_timeout,
	int                     interruptible,
	thread_t                thread)
{
	ipc_kmsg_queue_t        kmsgs;
	wait_result_t           wresult;
	uint64_t		deadline;
	spl_t                   s;

	s = splsched();
	imq_lock(mqueue);
	
	if (imq_is_set(mqueue)) {
		queue_t q;

		q = &mqueue->imq_preposts;

		/*
		 * If we are waiting on a portset mqueue, we need to see if
		 * any of the member ports have work for us.  Ports that
		 * have (or recently had) messages will be linked in the
		 * prepost queue for the portset. By holding the portset's
		 * mqueue lock during the search, we tie up any attempts by
		 * mqueue_deliver or portset membership changes that may
		 * cross our path.
		 */
	search_set:
		while(!queue_empty(q)) {
			wait_queue_link_t wql;
			ipc_mqueue_t port_mq;

			queue_remove_first(q, wql, wait_queue_link_t, wql_preposts);
			assert(!wql_is_preposted(wql));

			/*
			 * This is a lock order violation, so we have to do it
			 * "softly," putting the link back on the prepost list
			 * if it fails (at the tail is fine since the order of
			 * handling messages from different sources in a set is
			 * not guaranteed and we'd like to skip to the next source
			 * if one is available).
			 */
			port_mq = (ipc_mqueue_t)wql->wql_queue;
			if (!imq_lock_try(port_mq)) {
				queue_enter(q, wql, wait_queue_link_t, wql_preposts);
				imq_unlock(mqueue);
				splx(s);
				mutex_pause(0);
				s = splsched();
				imq_lock(mqueue);
				goto search_set; /* start again at beginning - SMP */
			}

			/*
			 * If there are no messages on this queue, just skip it
			 * (we already removed the link from the set's prepost queue).
			 */
			kmsgs = &port_mq->imq_messages;
			if (ipc_kmsg_queue_first(kmsgs) == IKM_NULL) {
				imq_unlock(port_mq);
				continue;
			}

			/*
			 * There are messages, so reinsert the link back
			 * at the tail of the preposted queue (for fairness)
			 * while we still have the portset mqueue locked.
			 */
			queue_enter(q, wql, wait_queue_link_t, wql_preposts);
			imq_unlock(mqueue);

			/*
			 * Continue on to handling the message with just
			 * the port mqueue locked.
			 */
			ipc_mqueue_select_on_thread(port_mq, option, max_size, thread);
			imq_unlock(port_mq);
			splx(s);
			return THREAD_NOT_WAITING;
			
		}

	} else {

		/*
		 * Receive on a single port. Just try to get the messages.
		 */
	  	kmsgs = &mqueue->imq_messages;
		if (ipc_kmsg_queue_first(kmsgs) != IKM_NULL) {
			ipc_mqueue_select_on_thread(mqueue, option, max_size, thread);
			imq_unlock(mqueue);
			splx(s);
			return THREAD_NOT_WAITING;
		}
	}
	
	/*
	 * Looks like we'll have to block.  The mqueue we will
	 * block on (whether the set's or the local port's) is
	 * still locked.
	 */
	if (option & MACH_RCV_TIMEOUT) {
		if (rcv_timeout == 0) {
			imq_unlock(mqueue);
			splx(s);
			thread->ith_state = MACH_RCV_TIMED_OUT;
			return THREAD_NOT_WAITING;
		}
	}

	thread_lock(thread);
	thread->ith_state = MACH_RCV_IN_PROGRESS;
	thread->ith_option = option;
	thread->ith_msize = max_size;

	if (option & MACH_RCV_TIMEOUT)
		clock_interval_to_deadline(rcv_timeout, 1000*NSEC_PER_USEC, &deadline);
	else
		deadline = 0;

	wresult = wait_queue_assert_wait64_locked(&mqueue->imq_wait_queue,
						  IPC_MQUEUE_RECEIVE,
						  interruptible, 
						  TIMEOUT_URGENCY_USER_NORMAL,
						  deadline, 0,
						  thread);
	/* preposts should be detected above, not here */
	if (wresult == THREAD_AWAKENED)
		panic("ipc_mqueue_receive_on_thread: sleep walking");

	thread_unlock(thread);
	imq_unlock(mqueue);
	splx(s);
	return wresult;
}
コード例 #18
0
ファイル: ipc_mqueue.c プロジェクト: Apple-FOSS-Mirror/xnu
/*
 *	Routine:	ipc_mqueue_send
 *	Purpose:
 *		Send a message to a message queue.  The message holds a reference
 *		for the destination port for this message queue in the 
 *		msgh_remote_port field.
 *
 *		If unsuccessful, the caller still has possession of
 *		the message and must do something with it.  If successful,
 *		the message is queued, given to a receiver, or destroyed.
 *	Conditions:
 *		mqueue is locked.
 *	Returns:
 *		MACH_MSG_SUCCESS	The message was accepted.
 *		MACH_SEND_TIMED_OUT	Caller still has message.
 *		MACH_SEND_INTERRUPTED	Caller still has message.
 */
mach_msg_return_t
ipc_mqueue_send(
	ipc_mqueue_t		mqueue,
	ipc_kmsg_t		kmsg,
	mach_msg_option_t	option,
	mach_msg_timeout_t	send_timeout,
	spl_t			s)
{
	int wresult;

	/*
	 *  Don't block if:
	 *	1) We're under the queue limit.
	 *	2) Caller used the MACH_SEND_ALWAYS internal option.
	 *	3) Message is sent to a send-once right.
	 */
	if (!imq_full(mqueue) ||
	    (!imq_full_kernel(mqueue) && 
	     ((option & MACH_SEND_ALWAYS) ||
	      (MACH_MSGH_BITS_REMOTE(kmsg->ikm_header->msgh_bits) ==
	       MACH_MSG_TYPE_PORT_SEND_ONCE)))) {
		mqueue->imq_msgcount++;
		assert(mqueue->imq_msgcount > 0);
		imq_unlock(mqueue);
		splx(s);
	} else {
		thread_t cur_thread = current_thread();
		uint64_t deadline;

		/* 
		 * We have to wait for space to be granted to us.
		 */
		if ((option & MACH_SEND_TIMEOUT) && (send_timeout == 0)) {
			imq_unlock(mqueue);
			splx(s);
			return MACH_SEND_TIMED_OUT;
		}
		if (imq_full_kernel(mqueue)) {
			imq_unlock(mqueue);
			splx(s);
			return MACH_SEND_NO_BUFFER;
		}
		mqueue->imq_fullwaiters = TRUE;
		thread_lock(cur_thread);
		if (option & MACH_SEND_TIMEOUT)
			clock_interval_to_deadline(send_timeout, 1000*NSEC_PER_USEC, &deadline);
		else
			deadline = 0;
		wresult = wait_queue_assert_wait64_locked(
						&mqueue->imq_wait_queue,
						IPC_MQUEUE_FULL,
						THREAD_ABORTSAFE,
						TIMEOUT_URGENCY_USER_NORMAL,
						deadline, 0,
						cur_thread);
		thread_unlock(cur_thread);
		imq_unlock(mqueue);
		splx(s);
		
		if (wresult == THREAD_WAITING) {
			wresult = thread_block(THREAD_CONTINUE_NULL);
			counter(c_ipc_mqueue_send_block++);
		}
		
		switch (wresult) {
		case THREAD_TIMED_OUT:
			assert(option & MACH_SEND_TIMEOUT);
			return MACH_SEND_TIMED_OUT;
			
		case THREAD_AWAKENED:
			/* we can proceed - inherited msgcount from waker */
			assert(mqueue->imq_msgcount > 0);
			break;
			
		case THREAD_INTERRUPTED:
			return MACH_SEND_INTERRUPTED;
			
		case THREAD_RESTART:
			/* mqueue is being destroyed */
			return MACH_SEND_INVALID_DEST;
		default:
			panic("ipc_mqueue_send");
		}
	}

	ipc_mqueue_post(mqueue, kmsg);
	return MACH_MSG_SUCCESS;
}
コード例 #19
0
ファイル: IOI2CDevice.cpp プロジェクト: aosm/IOI2CFamily
bool
IOI2CDevice::start(
	IOService	*provider)
{
	OSData		*regprop;
	IOReturn	status;

	DLOG("+IOI2CDevice::start\n");

	if (false == super::start(provider))
		return false;

	fProvider = provider;

	// Get I2C slave address. (required)
	if (regprop = OSDynamicCast(OSData, fProvider->getProperty("reg")))
	{
		fI2CAddress = *((UInt32 *)regprop->getBytesNoCopy());
		if (false == isI2C10BitAddress(fI2CAddress))
			fI2CAddress &= 0xff;
	}
	else
	{
		ERRLOG("-IOI2CDevice::start no \"reg\" property\n");
		return false;
	}

	if (fProvider->getProperty("AAPL,no-power"))
		fStateFlags |= kStateFlags_DISABLE_PM;

	// Initailize I2C resources.
	if (kIOReturnSuccess != (status = initI2CResources()))
	{
		ERRLOG("-IOI2CDevice@%lx::start initI2CResources failed:0x%lx\n", fI2CAddress, (UInt32)status);
		freeI2CResources();
		return false;
	}

	AbsoluteTime deadline, currentTime;

	// The original deadline was for 3 seconds, but this proved to short in some systems with densely populated I2C busses [4103531]
	clock_interval_to_deadline(15, kSecondScale, &deadline);

	while (isI2COffline())
	{
		IOSleep(10);
		clock_get_uptime(&currentTime);
		if ( CMP_ABSOLUTETIME(&currentTime, &deadline) > 0 )
		{
			ERRLOG("-IOI2CDevice@%lx::start timed out waiting to power on\n", fI2CAddress);
			freeI2CResources();
			return false;
		}
	}

	// Is this is a non-subclassed IOI2CDevice instance? Then enable on-demand platform functions and call registerService.
	// Otherwise the subclass driver can choose to enable on-demand PFs by setting the fEnableOnDemandPlatformFunctions flag.
	const char *name;
	if ( (name = getName()) && (0 == strcmp(name, "IOI2CDevice")) )
	{
		DLOG("%s@%lx::start enabling on demand PF functions\n", name, fI2CAddress);
		fEnableOnDemandPlatformFunctions = true;
		registerService();
	}

	DLOG("-IOI2CDevice@%lx::start\n",fI2CAddress);
	return true;
}
コード例 #20
0
ファイル: IOI2CDevice.cpp プロジェクト: aosm/IOI2CFamily
void
IOI2CDevice::freeI2CResources(void)
{
	if (fStateFlags & kStateFlags_TEARDOWN)
		return;
	fStateFlags |= kStateFlags_TEARDOWN;
	DLOG("+IOI2CDevice@%lx::freeI2CResources %x\n",fI2CAddress, fStateFlags);

#ifdef kUSE_IOLOCK
	if(fClientLock)
#else
	if(fClientSem)
#endif
	I2CLOCK;

	fDeviceOffline = TRUE;

#ifdef kUSE_IOLOCK
	if(fClientLock)
#else
	if(fClientSem)
#endif
	I2CUNLOCK;

	DLOG("+IOI2CDevice@%lx::freeI2CResources\n",fI2CAddress);
	if (fStateFlags & kStateFlags_PMInit)	// Don't rely on initialized flag to identify if PMinit was called.
	{
		DLOGPWR("+IOI2CDevice@%lx::freeI2CResources requesting power OFF\n",fI2CAddress);
		changePowerStateTo(kIOI2CPowerState_OFF);

		AbsoluteTime deadline, currentTime;
		clock_interval_to_deadline(20, kSecondScale, &deadline);

		while (fCurrentPowerState != kIOI2CPowerState_OFF)
		{
			IOSleep(10);
			clock_get_uptime(&currentTime);
			if ( CMP_ABSOLUTETIME(&currentTime, &deadline) > 0 )
			{
				ERRLOG("IOI2CDevice@%lx::freeI2CResources timed out waiting to power off\n", fI2CAddress);
				break;
			}
		}

		DLOGPWR("+IOI2CDevice@%lx::freeI2CResources calling PMStop\n",fI2CAddress);
		if (fStateFlags & kStateFlags_PMInit)
		{
			fStateFlags &= ~kStateFlags_PMInit;
			PMstop();
		}
	}
	DLOG("IOI2CDevice@%lx::freeI2CResources 1\n",fI2CAddress);

	if (fPowerStateThreadCall)
	{
		thread_call_cancel(fPowerStateThreadCall);
		thread_call_free(fPowerStateThreadCall);
		fPowerStateThreadCall = 0;
	}

	if (fProvider)
		fProvider->callPlatformFunction("IOI2CPowerStateInterest", FALSE, (void *)this, (void *)false, 0, 0);

	DLOG("IOI2CDevice@%lx::freeI2CResources 2\n",fI2CAddress);
	if (symLockI2CBus)		{ symLockI2CBus->release();		symLockI2CBus = 0; }
	if (symUnlockI2CBus)	{ symUnlockI2CBus->release();	symUnlockI2CBus = 0; }
	if (symWriteI2CBus)		{ symWriteI2CBus->release();	symWriteI2CBus = 0; }
	if (symReadI2CBus)		{ symReadI2CBus->release();		symReadI2CBus = 0; }

	DLOG("IOI2CDevice@%lx::freeI2CResources 3\n",fI2CAddress);

#ifdef kUSE_IOLOCK
	if (fClientLock)		{ IOLockFree(fClientLock);		fClientLock = 0; }
#else
	if (fClientSem)			{ semaphore_destroy(current_task(), fClientSem);	fClientSem = 0; }
#endif

	DLOG("IOI2CDevice@%lx::freeI2CResources 4\n",fI2CAddress);
	if (reserved)
	{
		if (symClientRead)		{ symClientRead->release();		symClientRead = 0; }
		if (symClientWrite)		{ symClientWrite->release();	symClientWrite = 0; }
		if (symPowerInterest)	{ symPowerInterest->release();	symPowerInterest = 0; }
	}

	DLOG("-IOI2CDevice@%lx::freeI2CResources\n",fI2CAddress);
}