- 核心概念:ACPI (高级配置与电源接口)
- Linux 内核中的电池驱动架构
- 关键的数据结构:
power_supply类 - 用户空间如何获取电池信息
- 如何排查电池驱动问题
核心概念:ACPI (高级配置与电源接口)
现代笔记本电脑、服务器和台式机的电源管理(包括电池)都依赖于一个叫做 ACPI 的工业标准,ACPI 是一个开放标准,定义了操作系统与固件(BIOS/UEFI)之间的接口。

- 固件的作用:硬件(主板上的 PMIC - 电源管理集成电路、电池本身等)通过 ACPI 提供的“方法”(Methods)和“对象”(Objects)来报告其状态。
- 驱动的作用:Linux 内核的 ACPI 子系统(
drivers/acpi/)会解析这些 ACPI 表(如BAT0,ACAD等),并根据这些信息来与硬件交互,例如读取电量、计算剩余时间、控制充电等。
ACPI 是连接硬件固件和 Linux 操作系统的“语言”,而电池驱动就是“翻译官”,负责“说”这门语言。
Linux 内核中的电池驱动架构
Linux 内核的驱动架构是分层的,电池驱动也不例外,这种分层设计使得代码结构清晰,并且可以方便地支持不同的硬件。
电池驱动通常位于 drivers/power/supply/ 目录下,主要分为以下几个层次:
a) 平台层 / 硬件抽象层
这是最底层,直接与硬件寄存器或通过 I2C/SPI 等总线通信的驱动代码。

- 作用:负责最原始的数据读写,比如从电池管理芯片的寄存器中读取电压、电流、温度等原始值。
- 例子:
i2c-charger.c: 用于通过 I2C 总线与充电芯片通信。max77693-charger.c: 针对特定芯片(如 Maxim MAX77693)的驱动。- 一些老式的或简单的电池驱动可能直接在这里实现所有逻辑。
b) 核心层 / power_supply 类
这是电池驱动的核心,位于 drivers/power/supply/ 下的核心文件(如 power_supply_core.c, power_supply_sysfs.c)。几乎所有现代的电池驱动最终都会通过这个框架来暴露信息。
- 作用:
- 提供标准接口:定义了一套标准的属性(如
status,capacity,present,health等),使得用户空间的应用程序(如upower,acpi_call)可以用统一的方式访问不同品牌的电池。 - 管理电源状态:处理电源事件,如 AC 插入/拔出、电池电量变化等,并通知上层(如用户空间)。
- 提供 sysfs 接口:在
/sys/class/power_supply/目录下创建文件,将电池信息暴露给用户空间。
- 提供标准接口:定义了一套标准的属性(如
c) ACPI 子系统层
这是目前笔记本电池驱动最主流的实现方式。
- 作用:ACPI 子系统解析 ACPI 表,找到电池相关的设备描述(
_BIF- Battery Information,_BST- Battery Status,_BTP- Battery Trip Points 等)。 - 实现:
drivers/acpi/battery.c是一个“通用”的 ACPI 电池驱动,当内核发现一个符合 ACPI 规范的电池设备时,会自动加载这个驱动,这个驱动会调用power_supply核心层的接口来注册自己,并将从 ACPI 获取的数据填充进去。
分层总结:
ACPI 表 -> ACPI 电池驱动 -> power_supply 核心框架 -> /sys/class/power_supply/ -> 用户空间工具
关键的数据结构:power_supply 类
power_supply 是内核中表示一个电源供应源的抽象类,它可以是电池、交流适配器、USB 电源等,驱动开发者通过注册一个 power_supply 结构体来告诉内核自己是一个电源设备。
核心结构体:struct power_supply
驱动程序需要填充这个结构体,最重要的部分是 desc (描述符) 和 properties (属性)。
-
struct power_supply_desc desc:name: 电源设备的名称,如BAT0,ACAD,这个名字会出现在/sys/class/power_supply/目录下。type: 电源类型,如POWER_SUPPLY_TYPE_BATTERY,POWER_SUPPLY_TYPE_MAINS(交流电)。get_property: 这是一个函数指针,是驱动的核心,当用户空间(如通过cat /sys/class/power_supply/BAT0/capacity)请求某个属性时,内核会调用这个函数,驱动程序负责从硬件或 ACPI 数据中获取该值并返回。
-
enum power_supply_property properties[]:- 这是一个属性列表,定义了该电源设备支持哪些属性,
POWER_SUPPLY_PROP_STATUS: 电池状态 (Unknown,Charging,Discharging,Not charging,Full)。POWER_SUPPLY_PROP_CAPACITY: 当前电量百分比 (0-100)。POWER_SUPPLY_PROP_PRESENT: 电池是否物理存在。POWER_SUPPLY_PROP_HEALTH: 电池健康状态 (Good,Overheat,Dead等)。POWER_SUPPLY_PROP_TECHNOLOGY: 电池技术 (NiMH,Li-ion,Li-poly等)。POWER_SUPPLY_PROP_VOLTAGE_NOW: 当前电压。POWER_SUPPLY_PROP_CURRENT_NOW: 当前电流。POWER_SUPPLY_PROP_CAPACITY_LEVEL: 电量等级 (Critical,Low,Normal,High,Full)。
- 这是一个属性列表,定义了该电源设备支持哪些属性,
用户空间如何获取电池信息
用户空间的应用程序通过以下几种主要方式与电池驱动交互:
a) /sys 文件系统 (最直接)
这是内核提供给用户空间的标准化接口,所有电池信息都在这里。
# 查看所有注册的电源设备 ls /sys/class/power_supply/ # 输出可能类似于: AC ADP1 BAT0 # 查看 BAT0 电池的信息 ls /sys/class/power_supply/BAT0/ # 输出: capacity, capacity_level, current_now, health, present, status, type, voltage_now, ... # 读取当前电量 cat /sys/class/power_supply/BAT0/capacity # 输出: 85 # 查看充电状态 cat /sys/class/power_supply/BAT0/status # 输出: Discharging
b) upower 工具 (最常用)
upower 是一个系统守护进程,它聚合了来自 /sys 的电源信息,并为其他应用程序(如桌面环境、GNOME Power Manager)提供一个统一的 D-Bus 接口。
# 查看 upower 知道的所有电源设备 upower -e # 输出: /org/freedesktop/UPower/devices/line_power_AC0 /org/freedesktop/UPower/devices/battery_BAT0 # 查看电池详细信息 upower -i /org/freedesktop/UPower/devices/battery_BAT0
c) acpi 命令行工具
acpi 命令是一个更底层的工具,它直接读取 ACPI 信息,有时可以提供 power_supply 没有或显示不友好的信息。
acpi -V # 输出: Battery 0: 85%, Discharging, 02:45:17 remaining
如何排查电池驱动问题
如果遇到电池信息不显示、信息不准、无法充电等问题,可以按照以下步骤排查:
-
检查内核是否加载了驱动:
# 查看内核日志,看有没有电池相关的信息 dmesg | grep -i "battery\|power_supply\|ACPI" # 如果看到类似 "battery: ACPI battery driver registered" 的信息,说明驱动已加载。
-
检查
/sys文件系统:# 检查设备是否存在 ls /sys/class/power_supply/ # 检查关键文件是否有内容,而不是空文件 cat /sys/class/power_supply/BAT0/status # 如果文件存在但读取为空或报错,可能是驱动没有正确获取硬件信息。
-
检查内核配置: 确保内核编译时启用了相关选项:
# 查看当前内核配置 zcat /proc/config.gz | grep -E "CONFIG_ACPI|CONFIG_POWER_SUPPLY" # 应该看到 CONFIG_ACPI=y 和 CONFIG_POWER_SUPPLY=y
-
检查硬件和固件:
- BIOS/UEFI 更新:有时电池问题是由于 BIOS/UEFI 的 Bug 引起的,尝试更新到最新版本。
- 硬件问题:如果所有驱动和软件都正常,但电池就是无法识别或充电,可能是电池本身或主板上的充电电路硬件损坏。
-
使用
acpi_call(高级): 这是一个非常有用的工具,允许你在用户空间直接调用 ACPI 方法,可以用来测试 ACPI 表是否工作正常,或者进行一些高级的电源管理操作。# 安装 acpi_call sudo apt-get install acpi-call-dkms # for Debian/Ubuntu # 或者从源码编译 # 调用一个方法(示例,具体方法名因主板而异) sudo modprobe acpi_call echo '\_SB.PCI0.LPCB.EC0.V0B0' | sudo tee /proc/acpi/call # 这需要你知道具体的 ACPI 方法路径,通常需要查阅硬件文档或社区资料。
Linux 电池驱动是一个成熟且标准化的子系统,其核心思想是:
- 硬件通过 ACPI 提供信息。
- 内核的 ACPI 子系统解析这些信息。
- 驱动通过
power_supply框架将信息标准化。 - 用户空间通过
/sys,upower等接口访问这些信息。
对于大多数用户来说,你不需要关心底层驱动细节,只需知道如何通过 upower 或 /sys 来查看和管理电池即可,但对于开发者来说,理解这个分层架构对于编写、调试或移植电池驱动至关重要。
