ACPI包括很多功能,电源管理是其功能之一,具体的ACPI的介绍可以参考ACPI的技术文档。
Linux中利用模块机制,实现ACPI对电源的管理:
static struct cpufreq_driver acpi_cpufreq_driver = {
.verify = acpi_cpufreq_verify,
.target = acpi_cpufreq_target,
.bios_limit = acpi_processor_get_bios_limit,
.init = acpi_cpufreq_cpu_init,
.exit = acpi_cpufreq_cpu_exit,
.resume = acpi_cpufreq_resume,
.name = "acpi-cpufreq",
.owner = THIS_MODULE,
.attr = acpi_cpufreq_attr,
};
模块的初始化工作由以下代码完成:
static int __init acpi_cpufreq_init(void)
{
int ret;
if (acpi_disabled)
return 0;
pr_debug("acpi_cpufreq_init
");
ret = acpi_cpufreq_early_init();
if (ret)
return ret;
ret = cpufreq_register_driver(&acpi_cpufreq_driver);//核心
if (ret)
free_acpi_perf_data();
return ret;
}
主要是cpufreq_register_driver:
/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
/**
* cpufreq_register_driver - register a CPU Frequency driver
* @driver_data: A struct cpufreq_driver containing the values#
* submitted by the CPU Frequency driver.
*
* Registers a CPU Frequency driver to this core code. This code
* returns zero on success, -EBUSY when another driver got here first
* (and isn't unregistered in the meantime).
*
*/
int cpufreq_register_driver(struct cpufreq_driver *driver_data)
{
unsigned long flags;
int ret;
if (!driver_data || !driver_data->verify || !driver_data->init ||
((!driver_data->setpolicy) && (!driver_data->target)))
return -EINVAL;
pr_debug("trying to register driver %s
", driver_data->name);
if (driver_data->setpolicy)
driver_data->flags |= CPUFREQ_CONST_LOOPS;
spin_lock_irqsave(&cpufreq_driver_lock, flags);
if (cpufreq_driver) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
return -EBUSY;
}
cpufreq_driver = driver_data;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
ret = sysdev_driver_register(&cpu_sysdev_class,
&cpufreq_sysdev_driver);
if (ret)
goto err_null_driver;
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i;
ret = -ENODEV;
/* check for at least one working CPU */
for (i = 0; i < nr_cpu_ids; i++)
if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) {
ret = 0;
break;
}
/* if all ->init() calls failed, unregister */
if (ret) {
pr_debug("no CPU initialized for driver %s
",
driver_data->name);
goto err_sysdev_unreg;
}
}
register_hotcpu_notifier(&cpufreq_cpu_notifier);
pr_debug("driver %s up and running
", driver_data->name);
return 0;
err_sysdev_unreg:
sysdev_driver_unregister(&cpu_sysdev_class,
&cpufreq_sysdev_driver);
err_null_driver:
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
return ret;
}
为什么不直接引用acpi_cpufreq_driver呢?
由于传递过来的参数是acpi_cpufreq_driver,因此以后引用cpufreq_driver就相当于引用acpi_cpufreq_driver了。为什么这么做呢?因为,还有一种叫做pcc_cpufreq_driver的东西,和acpi_cpufreq_driver一样,是电源管理的一种方式,它的初始化也是用这个函数,因为这两种方式你只能选择一种,因此,cpufreq_driver要么是acpi_cpufreq_driver,要么是pcc_cpufreq_driver。这样的实现方式,避免了代码的重复!
有这样一行代码
cpufreq_driver = driver_data;