📄 power.cxx
字号:
// the policy callback will be changed while the system is running,
// but just in case somebody installs a null pointer between the
// check and the call...
void (*callback)(PowerController*, PowerMode, PowerMode, PowerMode, PowerMode) = __power_policy_callback;
if (0 != callback) {
(*callback)(controller, old_mode, controller->mode, desired_mode, controller->desired_mode);
}
}
// power_doit() is responsible for a single iteration over the various controllers,
// aborting if there is a global mode change during the current iteration. The
// calling code, either power_thread_fn() or power_nothread_doit(), will take
// care of the higher-level iterating while there is work to be done.
//
// If a global mode change has been requested then the order in which the controllers
// are invoked is significant: front->back for lowering power modes, back->front for
// a higher power mode. If there are individual changes to be processed then
// arbitrarily front->back is used as well.
static inline void
power_doit()
{
PowerController* controller;
abort_mode_change = false;
if (__power_desired_mode < __power_mode) {
// The new mode is more active than the old one, so start with
// the power controllers at the back of the table.
for (controller = &(__POWER_END__) - 1; !abort_mode_change && (controller >= &(__POWER__[0])); controller--) {
PowerMode desired_mode;
cyg_bool change_this;
#ifdef CYGPKG_POWER_THREAD
// Read the desired_mode and change_this flags atomically.
cyg_scheduler_lock();
desired_mode = controller->desired_mode;
change_this = controller->change_this;
cyg_scheduler_unlock();
#else
desired_mode = controller->desired_mode;
change_this = controller->change_this;
#endif
// If this controller is not running at the desired mode, change it.
if (desired_mode != controller->mode) {
power_change_controller_mode(controller, desired_mode, change_this);
}
}
} else { // __power_desired_mode >= __power_mode.
// Either a global mode change to a less active mode, or
// one or more individual controller changes. Other than
// iterating in a different direction, the code is the same
// as above.
for (controller = &(__POWER__[0]); !abort_mode_change && (controller != &(__POWER_END__)); controller++) {
PowerMode desired_mode;
cyg_bool change_this;
#ifdef CYGPKG_POWER_THREAD
cyg_scheduler_lock();
desired_mode = controller->desired_mode;
change_this = controller->change_this;
cyg_scheduler_unlock();
#else
desired_mode = controller->desired_mode;
change_this = controller->change_this;
#endif
if (desired_mode != controller->mode) {
power_change_controller_mode(controller, desired_mode, change_this);
}
}
}
// All of the controllers have been invoked. If there have been no
// intervening calls to power_set_mode() (which would have updated
// abort_mode_change) then we must now be running at the desired
// global mode.
if (!abort_mode_change) {
__power_mode = __power_desired_mode;
}
}
#ifdef CYGPKG_POWER_THREAD
static void
power_thread_fn(cyg_addrword_t param)
{
for (;;) {
// Currently idle. Wait for a request to change power modes.
cyg_semaphore_wait(&power_thread_action);
power_doit();
}
}
#else
static inline void
power_nothread_doit()
{
power_todo_count++;
if (!power_doing_it) {
power_doing_it = true;
do {
power_doit();
} while (--power_todo_count > 0);
power_doing_it = false;
}
}
#endif
// ----------------------------------------------------------------------------
// The exported calls.
extern "C" void
power_set_controller_mode(PowerController* controller, PowerMode new_mode)
{
#ifdef CYGPKG_POWER_THREAD
cyg_scheduler_lock(); // Protect against concurrent calls
#endif
controller->desired_mode = new_mode;
controller->change_this = true;
#ifdef CYGPKG_POWER_THREAD
cyg_scheduler_unlock();
cyg_semaphore_post(&power_thread_action);
#else
power_nothread_doit();
#endif
}
extern "C" void
power_set_mode(PowerMode new_mode)
{
PowerController* controller;
#ifdef CYGPKG_POWER_THREAD
cyg_scheduler_lock();
#endif
__power_desired_mode = new_mode;
abort_mode_change = true;
// Update each controller. Most importantly, clear the
// "change_this" flag in every power controller. The net result is
// that power_set_mode() overrides any power_set_controller_mode()
// operations that have not yet been processed, but future
// power_set_controller_mode() calls will have the desired effect.
for (controller = &(__POWER__[0]); controller != &(__POWER_END__); controller++) {
if (controller->attached) {
controller->change_this = 0;
controller->desired_mode = new_mode;
}
}
#ifdef CYGPKG_POWER_THREAD
cyg_scheduler_unlock();
cyg_semaphore_post(&power_thread_action);
#else
power_nothread_doit();
#endif
}
// ----------------------------------------------------------------------------
// Power management initialization. This gets called from
// power_data.cxx using a prioritized constructors. Doing this way
// minimizes the amount of data that is going to end up in libextras.a
// and hence in the final executable, allowing linker garbage collection
// to clean up as much as possible. The main operation here is to start
// up a separate power management thread when configured to do so.
//
// If no separate thread is being used then no run-time initialization
// is needed.
#ifdef CYGPKG_POWER_THREAD
extern "C" void
power_init(void)
{
cyg_semaphore_init(&power_thread_action, 0);
cyg_thread_create(CYGNUM_POWER_THREAD_PRIORITY,
&power_thread_fn,
(cyg_addrword_t) 0,
"Power management thread",
power_thread_stack,
CYGNUM_POWER_THREAD_STACKSIZE,
&power_thread_handle,
&power_thread
);
cyg_thread_resume(power_thread_handle);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -