当前流行的计算机系统都支持电源管理。特备是在笔记本电脑中电源管理有非常重要的作用。
目前比较流行的电源管理技术主要有两种: 高级电源管理(APM) , 高级配置与能源接口(ACPI).其中 ACPI 在两者中比较先进, 它将电源管理交由操作系统负责, 可以有更灵活的管理方式。 有实例表明采用ACPI 管理方式的计算机在能耗方面比采用APM 管理方式的计算机明显比较节能。
能否使用电源管理, 以及是否可以启用ACPI, 不仅仅要求操作系统进行支持,同时也依赖于硬件环境。 例如计算机的主板不支持ACPI的话, 操作系统也不可能利用ACPI进行电源管理。
在Linux操作系统比较新的内核中, 缺省的配置均是使用ACPI进行电源管理。 但是要注意一点, 就是ACPI 与APM两种管理方式只能有一种进行实际的控制管理。 如果在编译系统内核时两种管理方式都选择了,那么系统内核会自动判断该计算机的硬件配置适合两种方式中的哪一种。如果该计算机的硬件对这两种管理方式都支持,那么操作系统将会自动选择ACPI方式进行管理。
在设备的驱动程序中,应该对电源管理有足够的重视。哪怕只有一设备没有按照规范进行设备的电源管理,都会引起整个系统的电源管理失效,通常会使系统不能正常挂起。
电源管理的框架如下 :
1)在设备初始化时采用pm_register 函数进行注册。
2) 在每次对硬件的操作之前调用pm_access函数,确认设血是否处理准备好的状态。
3)在进入和退出挂起姿状态时,调用pm_callback函数。
4)在设备不再使用时,调用pm_dev_idle以利于设备的空闲检测。
5)当卸载设备驱动时,调用pm_umregister.
数据结构:
typedef int (*pm_callback)(struct pm_dev *dev, pm_request_t rqst, void *data);
此处定义了pm_callback 函数的接口信息。
/*
* Dynamic device information
*/
struct pm_dev
{
pm_dev_t type;
unsigned long id;
pm_callback callback;
void *data;
unsigned long flags;
unsigned long state;
unsigned long prev_state;
struct list_head entry;
};
pm_dev{ } 是内核进行电源管理的结构。其中包括设备的类型, id号,内部数据存储空间,标志flags, 状态state, 上一个状态以及进行链表管理的list_head{}变量。
设备注册时调用pm_register()进行注册。 其中参数如下:
type :设备的类型。
id :设备的序号
callback: 该设备的能源管理函数。
函数pm_register() 的主要功能是注册一个需要进行能源管理的设备,获得pm_dev{}. 这样当系统发生一些能源管理的事件时(如硬盘待机时),将会通知该设备,来进行一些准备工作。如果成功的话,将会返回pm_dev{ }的指针;如果失败了,则返回NULL 指针。
/**
* pm_register - register a device with power management
* @type: device type
* @id: device ID
* @callback: callback function
*
* Add a device to the list of devices that wish to be notified about
* power management events. A &pm_dev structure is returned on success,
* on failure the return is %NULL.
*
* The callback function will be called in process context and
* it may sleep.
*/
struct pm_dev *pm_register(pm_dev_t type,
unsigned long id,
pm_callback callback)
{
struct pm_dev *dev = kzalloc(sizeof(struct pm_dev), GFP_KERNEL); // 获取内存空间保存pm_dev{} 结构
if (dev) {
dev->type = type;
dev->id = id;
dev->callback = callback;
down(&pm_devs_lock);
list_add(&dev->entry, &pm_devs); // 将dev加入pm_devs所连接起来的链表中。
up(&pm_devs_lock);
}
return dev;
}
设备卸载时,调用pm_unregister() 删除电源管理中的相关记录。当今后发生能源管理事件时,该设备将不会再接收到通知。它只需要提供注册时获得的pm_dev{ } 结构的指针。
/**
* pm_unregister - unregister a device with power management
* @dev: device to unregister
*
* Remove a device from the power management notification lists. The
* dev passed must be a handle previously returned by pm_register.
*/
void pm_unregister(struct pm_dev *dev)
{
if (dev) {
down(&pm_devs_lock);
list_del(&dev->entry); // 对pm_devs 管理的链表进行删除操作
up(&pm_devs_lock);
kfree(dev); // 释放dev 指向的pm_dev{}所占用的内存空间
}
}