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\n");
ret = acpi_cpufreq_early_init();
if (ret)
return ret;
ret = cpufreq_register_driver(&acpi_cpufreq_driver);//核心
if (ret)
free_acpi_perf_data();
return ret;
}
/*********************************************************************
* 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\n", 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\n",
driver_data->name);
goto err_sysdev_unreg;
}
}
register_hotcpu_notifier(&cpufreq_cpu_notifier);
pr_debug("driver %s up and running\n", 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;