ACPI Battery 電池管理 - 1

定義acpi battery 結構體保存global的一些參數

struct acpi_battery {
	struct mutex lock;
	struct mutex sysfs_lock;
	struct power_supply *bat;
	struct power_supply_desc bat_desc;
	struct acpi_device *device;
	struct notifier_block pm_nb;
	struct list_head list;
	unsigned long update_time;
	int revision;
	int rate_now;
	int capacity_now;
	int voltage_now;
	int design_capacity;
	int full_charge_capacity;
	int technology;
	int design_voltage;
	int design_capacity_warning;
	int design_capacity_low;
	int cycle_count;
	int measurement_accuracy;
	int max_sampling_time;
	int min_sampling_time;
	int max_averaging_interval;
	int min_averaging_interval;
	int capacity_granularity_1;
	int capacity_granularity_2;
	int alarm;
	char model_number[32];
	char serial_number[32];
	char type[32];
	char oem_info[32];
	int state;
	int power_unit;
	unsigned long flags;
};

ACPI battery 結構體中很多的參數都有一個offset

/* --------------------------------------------------------------------------
                               Battery Management
   -------------------------------------------------------------------------- */
struct acpi_offsets {
	size_t offset;		/* offset inside struct acpi_sbs_battery */
	u8 mode;		/* int or string? */
};

static const struct acpi_offsets state_offsets[] = {
	{offsetof(struct acpi_battery, state), 0},
	{offsetof(struct acpi_battery, rate_now), 0},
	{offsetof(struct acpi_battery, capacity_now), 0},
	{offsetof(struct acpi_battery, voltage_now), 0},
};

static const struct acpi_offsets info_offsets[] = {
	{offsetof(struct acpi_battery, power_unit), 0},
	{offsetof(struct acpi_battery, design_capacity), 0},
	{offsetof(struct acpi_battery, full_charge_capacity), 0},
	{offsetof(struct acpi_battery, technology), 0},
	{offsetof(struct acpi_battery, design_voltage), 0},
	{offsetof(struct acpi_battery, design_capacity_warning), 0},
	{offsetof(struct acpi_battery, design_capacity_low), 0},
	{offsetof(struct acpi_battery, capacity_granularity_1), 0},
	{offsetof(struct acpi_battery, capacity_granularity_2), 0},
	{offsetof(struct acpi_battery, model_number), 1},
	{offsetof(struct acpi_battery, serial_number), 1},
	{offsetof(struct acpi_battery, type), 1},
	{offsetof(struct acpi_battery, oem_info), 1},
};

static const struct acpi_offsets extended_info_offsets[] = {
	{offsetof(struct acpi_battery, revision), 0},
	{offsetof(struct acpi_battery, power_unit), 0},
	{offsetof(struct acpi_battery, design_capacity), 0},
	{offsetof(struct acpi_battery, full_charge_capacity), 0},
	{offsetof(struct acpi_battery, technology), 0},
	{offsetof(struct acpi_battery, design_voltage), 0},
	{offsetof(struct acpi_battery, design_capacity_warning), 0},
	{offsetof(struct acpi_battery, design_capacity_low), 0},
	{offsetof(struct acpi_battery, cycle_count), 0},
	{offsetof(struct acpi_battery, measurement_accuracy), 0},
	{offsetof(struct acpi_battery, max_sampling_time), 0},
	{offsetof(struct acpi_battery, min_sampling_time), 0},
	{offsetof(struct acpi_battery, max_averaging_interval), 0},
	{offsetof(struct acpi_battery, min_averaging_interval), 0},
	{offsetof(struct acpi_battery, capacity_granularity_1), 0},
	{offsetof(struct acpi_battery, capacity_granularity_2), 0},
	{offsetof(struct acpi_battery, model_number), 1},
	{offsetof(struct acpi_battery, serial_number), 1},
	{offsetof(struct acpi_battery, type), 1},
	{offsetof(struct acpi_battery, oem_info), 1},
};

然後開始battery 參數的初始化流程
用acpi_evaluate_object 去call BIOS ACPI的_BIX 方法或者_BIF
在acpi的spec 中定義如下:

_BIF
Battery Information – returns a Control Method Battery information block.
Section 10.2.2.1
_BIX
Battery Information Extended – returns a Control Method Battery extended information block.
Section 10.2.2.2
10.2.2.2 _BIX (Battery Information Extended)
The _BIX object returns the static portion of the Control Method Battery information. This information remains constant until the battery is changed. The _BIX object returns all information available via the _BIF object plus additional battery information. The _BIF object is deprecated in lieu of _BIX in ACPI 4.0.
Arguments:
None
Return Value:
A Package containing the battery information as described below
Return Value Information:
_BIX returns a package in the format below
Package {
// ASCIIZ is ASCII character string terminated with a 0x00.
Revision //Integer
Power Unit //Integer (DWORD)
Design Capacity //Integer (DWORD)
Last Full Charge Capacity //Integer (DWORD)
Battery Technology //Integer (DWORD)
Design Voltage //Integer (DWORD)
Design Capacity of Warning //Integer (DWORD)
Design Capacity of Low //Integer (DWORD)
Cycle Count //Integer (DWORD)
Measurement Accuracy //Integer (DWORD)
Max Sampling Time //Integer (DWORD)
Min Sampling Time //Integer (DWORD)
Max Averaging Interval //Integer (DWORD)
Min Averaging Interval //Integer (DWORD)
Battery Capacity Granularity 1 //Integer (DWORD)
Battery Capacity Granularity 2 //Integer (DWORD)
Model Number //String (ASCIIZ)
Serial Number //String (ASCIIZ)
Battery Type //String (ASCIIZ)
OEM Information //String (ASCIIZ)
Battery Swapping Capability //Integer (DWORD)
}

Kernel 通過ACPi方法 獲取了battery的全部參數,然後填充這些參數到kernel的driver中,之後直接查詢kernel的參數,而不是去掉ACPI 去查找.
常見的ACPI 操作。

static int acpi_battery_get_info(struct acpi_battery *battery)
{
	const int xinfo = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
	int use_bix;
	int result = -ENODEV;

	if (!acpi_battery_present(battery))
		return 0;


	for (use_bix = xinfo ? 1 : 0; use_bix >= 0; use_bix--) {
		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
		acpi_status status = AE_ERROR;

		mutex_lock(&battery->lock);
		status = acpi_evaluate_object(battery->device->handle,
					      use_bix ? "_BIX":"_BIF",
					      NULL, &buffer);
		mutex_unlock(&battery->lock);

		if (ACPI_FAILURE(status)) {
			ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s",
					use_bix ? "_BIX":"_BIF"));
		} else {
			result = extract_battery_info(use_bix,
						      battery,
						      &buffer);

			kfree(buffer.pointer);
			break;
		}
	}

	if (!result && !use_bix && xinfo)
		pr_warn(FW_BUG "The _BIX method is broken, using _BIF.\n");

	return result;
}

通過ACPI 方法從BIOS 獲取全部電池相關的參數
status = acpi_evaluate_object(battery->device->handle,
use_bix ? “_BIX”:"_BIF",
NULL, &buffer);
然後提取相關的Battery info 填充acpi_battery 結構體內各個battery 參數
result = extract_battery_info(use_bix,
battery,
&buffer);

static int extract_battery_info(const int use_bix,
			 struct acpi_battery *battery,
			 const struct acpi_buffer *buffer)
{
	int result = -EFAULT;

	if (use_bix && battery_bix_broken_package)
		result = extract_package(battery, buffer->pointer,
				extended_info_offsets + 1,
				ARRAY_SIZE(extended_info_offsets) - 1);
	else if (use_bix)
		result = extract_package(battery, buffer->pointer,
				extended_info_offsets,
				ARRAY_SIZE(extended_info_offsets));
	else
		result = extract_package(battery, buffer->pointer,
				info_offsets, ARRAY_SIZE(info_offsets));
	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
		battery->full_charge_capacity = battery->design_capacity;
	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
	    battery->power_unit && battery->design_voltage) {
		battery->design_capacity = battery->design_capacity *
		    10000 / battery->design_voltage;
		battery->full_charge_capacity = battery->full_charge_capacity *
		    10000 / battery->design_voltage;
		battery->design_capacity_warning =
		    battery->design_capacity_warning *
		    10000 / battery->design_voltage;
		/* Curiously, design_capacity_low, unlike the rest of them,
		   is correct.  */
		/* capacity_granularity_* equal 1 on the systems tested, so
		   it's impossible to tell if they would need an adjustment
		   or not if their values were higher.  */
	}
	if (test_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags) &&
	    battery->capacity_now > battery->full_charge_capacity)
		battery->capacity_now = battery->full_charge_capacity;

	return result;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章