⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 battery.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  battery.c - ACPI Battery Driver (Revision: 2.0) * *  Copyright (C) 2007 Alexey Starikovskiy <astarikovskiy@suse.de> *  Copyright (C) 2004-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com> *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or (at *  your option) any later version. * *  This program is distributed in the hope that it will be useful, but *  WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *  General Public License for more details. * *  You should have received a copy of the GNU General Public License along *  with this program; if not, write to the Free Software Foundation, Inc., *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/jiffies.h>#ifdef CONFIG_ACPI_PROCFS_POWER#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <asm/uaccess.h>#endif#include <acpi/acpi_bus.h>#include <acpi/acpi_drivers.h>#ifdef CONFIG_ACPI_SYSFS_POWER#include <linux/power_supply.h>#endif#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF#define ACPI_BATTERY_COMPONENT		0x00040000#define ACPI_BATTERY_CLASS		"battery"#define ACPI_BATTERY_DEVICE_NAME	"Battery"#define ACPI_BATTERY_NOTIFY_STATUS	0x80#define ACPI_BATTERY_NOTIFY_INFO	0x81#define _COMPONENT		ACPI_BATTERY_COMPONENTACPI_MODULE_NAME("battery");MODULE_AUTHOR("Paul Diefenbaugh");MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");MODULE_DESCRIPTION("ACPI Battery Driver");MODULE_LICENSE("GPL");static unsigned int cache_time = 1000;module_param(cache_time, uint, 0644);MODULE_PARM_DESC(cache_time, "cache time in milliseconds");#ifdef CONFIG_ACPI_PROCFS_POWERextern struct proc_dir_entry *acpi_lock_battery_dir(void);extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);enum acpi_battery_files {	info_tag = 0,	state_tag,	alarm_tag,	ACPI_BATTERY_NUMFILES,};#endifstatic const struct acpi_device_id battery_device_ids[] = {	{"PNP0C0A", 0},	{"", 0},};MODULE_DEVICE_TABLE(acpi, battery_device_ids);struct acpi_battery {	struct mutex lock;#ifdef CONFIG_ACPI_SYSFS_POWER	struct power_supply bat;#endif	struct acpi_device *device;	unsigned long update_time;	int current_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 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;	u8 alarm_present;};#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);inline int acpi_battery_present(struct acpi_battery *battery){	return battery->device->status.battery_present;}#ifdef CONFIG_ACPI_SYSFS_POWERstatic int acpi_battery_technology(struct acpi_battery *battery){	if (!strcasecmp("NiCd", battery->type))		return POWER_SUPPLY_TECHNOLOGY_NiCd;	if (!strcasecmp("NiMH", battery->type))		return POWER_SUPPLY_TECHNOLOGY_NiMH;	if (!strcasecmp("LION", battery->type))		return POWER_SUPPLY_TECHNOLOGY_LION;	if (!strncasecmp("LI-ION", battery->type, 6))		return POWER_SUPPLY_TECHNOLOGY_LION;	if (!strcasecmp("LiP", battery->type))		return POWER_SUPPLY_TECHNOLOGY_LIPO;	return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;}static int acpi_battery_get_state(struct acpi_battery *battery);static int acpi_battery_get_property(struct power_supply *psy,				     enum power_supply_property psp,				     union power_supply_propval *val){	struct acpi_battery *battery = to_acpi_battery(psy);	if (acpi_battery_present(battery)) {		/* run battery update only if it is present */		acpi_battery_get_state(battery);	} else if (psp != POWER_SUPPLY_PROP_PRESENT)		return -ENODEV;	switch (psp) {	case POWER_SUPPLY_PROP_STATUS:		if (battery->state & 0x01)			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;		else if (battery->state & 0x02)			val->intval = POWER_SUPPLY_STATUS_CHARGING;		else if (battery->state == 0)			val->intval = POWER_SUPPLY_STATUS_FULL;		else			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;		break;	case POWER_SUPPLY_PROP_PRESENT:		val->intval = acpi_battery_present(battery);		break;	case POWER_SUPPLY_PROP_TECHNOLOGY:		val->intval = acpi_battery_technology(battery);		break;	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:		val->intval = battery->design_voltage * 1000;		break;	case POWER_SUPPLY_PROP_VOLTAGE_NOW:		val->intval = battery->voltage_now * 1000;		break;	case POWER_SUPPLY_PROP_CURRENT_NOW:		val->intval = battery->current_now * 1000;		break;	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:		val->intval = battery->design_capacity * 1000;		break;	case POWER_SUPPLY_PROP_CHARGE_FULL:	case POWER_SUPPLY_PROP_ENERGY_FULL:		val->intval = battery->full_charge_capacity * 1000;		break;	case POWER_SUPPLY_PROP_CHARGE_NOW:	case POWER_SUPPLY_PROP_ENERGY_NOW:		val->intval = battery->capacity_now * 1000;		break;	case POWER_SUPPLY_PROP_MODEL_NAME:		val->strval = battery->model_number;		break;	case POWER_SUPPLY_PROP_MANUFACTURER:		val->strval = battery->oem_info;		break;	default:		return -EINVAL;	}	return 0;}static enum power_supply_property charge_battery_props[] = {	POWER_SUPPLY_PROP_STATUS,	POWER_SUPPLY_PROP_PRESENT,	POWER_SUPPLY_PROP_TECHNOLOGY,	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,	POWER_SUPPLY_PROP_VOLTAGE_NOW,	POWER_SUPPLY_PROP_CURRENT_NOW,	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,	POWER_SUPPLY_PROP_CHARGE_FULL,	POWER_SUPPLY_PROP_CHARGE_NOW,	POWER_SUPPLY_PROP_MODEL_NAME,	POWER_SUPPLY_PROP_MANUFACTURER,};static enum power_supply_property energy_battery_props[] = {	POWER_SUPPLY_PROP_STATUS,	POWER_SUPPLY_PROP_PRESENT,	POWER_SUPPLY_PROP_TECHNOLOGY,	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,	POWER_SUPPLY_PROP_VOLTAGE_NOW,	POWER_SUPPLY_PROP_CURRENT_NOW,	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,	POWER_SUPPLY_PROP_ENERGY_FULL,	POWER_SUPPLY_PROP_ENERGY_NOW,	POWER_SUPPLY_PROP_MODEL_NAME,	POWER_SUPPLY_PROP_MANUFACTURER,};#endif#ifdef CONFIG_ACPI_PROCFS_POWERinline char *acpi_battery_units(struct acpi_battery *battery){	return (battery->power_unit)?"mA":"mW";}#endif/* --------------------------------------------------------------------------                               Battery Management   -------------------------------------------------------------------------- */struct acpi_offsets {	size_t offset;		/* offset inside struct acpi_sbs_battery */	u8 mode;		/* int or string? */};static struct acpi_offsets state_offsets[] = {	{offsetof(struct acpi_battery, state), 0},	{offsetof(struct acpi_battery, current_now), 0},	{offsetof(struct acpi_battery, capacity_now), 0},	{offsetof(struct acpi_battery, voltage_now), 0},};static 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 int extract_package(struct acpi_battery *battery,			   union acpi_object *package,			   struct acpi_offsets *offsets, int num){	int i;	union acpi_object *element;	if (package->type != ACPI_TYPE_PACKAGE)		return -EFAULT;	for (i = 0; i < num; ++i) {		if (package->package.count <= i)			return -EFAULT;		element = &package->package.elements[i];		if (offsets[i].mode) {			u8 *ptr = (u8 *)battery + offsets[i].offset;			if (element->type == ACPI_TYPE_STRING ||			    element->type == ACPI_TYPE_BUFFER)				strncpy(ptr, element->string.pointer, 32);			else if (element->type == ACPI_TYPE_INTEGER) {				strncpy(ptr, (u8 *)&element->integer.value,					sizeof(acpi_integer));				ptr[sizeof(acpi_integer)] = 0;			} else return -EFAULT;		} else {			if (element->type == ACPI_TYPE_INTEGER) {				int *x = (int *)((u8 *)battery +						offsets[i].offset);				*x = element->integer.value;			} else return -EFAULT;		}	}	return 0;}static int acpi_battery_get_status(struct acpi_battery *battery){	if (acpi_bus_get_status(battery->device)) {		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));		return -ENODEV;	}	return 0;}static int acpi_battery_get_info(struct acpi_battery *battery){	int result = -EFAULT;	acpi_status status = 0;	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };	if (!acpi_battery_present(battery))		return 0;	mutex_lock(&battery->lock);	status = acpi_evaluate_object(battery->device->handle, "_BIF",				      NULL, &buffer);	mutex_unlock(&battery->lock);	if (ACPI_FAILURE(status)) {		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));		return -ENODEV;	}	result = extract_package(battery, buffer.pointer,				 info_offsets, ARRAY_SIZE(info_offsets));	kfree(buffer.pointer);	return result;}static int acpi_battery_get_state(struct acpi_battery *battery){	int result = 0;	acpi_status status = 0;	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };	if (!acpi_battery_present(battery))		return 0;	if (battery->update_time &&	    time_before(jiffies, battery->update_time +			msecs_to_jiffies(cache_time)))		return 0;	mutex_lock(&battery->lock);	status = acpi_evaluate_object(battery->device->handle, "_BST",				      NULL, &buffer);	mutex_unlock(&battery->lock);	if (ACPI_FAILURE(status)) {		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));		return -ENODEV;	}	result = extract_package(battery, buffer.pointer,				 state_offsets, ARRAY_SIZE(state_offsets));	battery->update_time = jiffies;	kfree(buffer.pointer);	return result;}static int acpi_battery_set_alarm(struct acpi_battery *battery){	acpi_status status = 0;	union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER };	struct acpi_object_list arg_list = { 1, &arg0 };	if (!acpi_battery_present(battery)|| !battery->alarm_present)		return -ENODEV;	arg0.integer.value = battery->alarm;	mutex_lock(&battery->lock);	status = acpi_evaluate_object(battery->device->handle, "_BTP",				 &arg_list, NULL);	mutex_unlock(&battery->lock);	if (ACPI_FAILURE(status))		return -ENODEV;	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", battery->alarm));	return 0;}static int acpi_battery_init_alarm(struct acpi_battery *battery){	acpi_status status = AE_OK;	acpi_handle handle = NULL;	/* See if alarms are supported, and if so, set default */	status = acpi_get_handle(battery->device->handle, "_BTP", &handle);	if (ACPI_FAILURE(status)) {		battery->alarm_present = 0;		return 0;	}	battery->alarm_present = 1;	if (!battery->alarm)		battery->alarm = battery->design_capacity_warning;	return acpi_battery_set_alarm(battery);}#ifdef CONFIG_ACPI_SYSFS_POWERstatic ssize_t acpi_battery_alarm_show(struct device *dev,					struct device_attribute *attr,					char *buf){	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));	return sprintf(buf, "%d\n", battery->alarm * 1000);}static ssize_t acpi_battery_alarm_store(struct device *dev,					struct device_attribute *attr,					const char *buf, size_t count){	unsigned long x;	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));	if (sscanf(buf, "%ld\n", &x) == 1)		battery->alarm = x/1000;	if (acpi_battery_present(battery))		acpi_battery_set_alarm(battery);	return count;}static struct device_attribute alarm_attr = {	.attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},	.show = acpi_battery_alarm_show,	.store = acpi_battery_alarm_store,};static int sysfs_add_battery(struct acpi_battery *battery){	int result;	if (battery->power_unit) {		battery->bat.properties = charge_battery_props;		battery->bat.num_properties =			ARRAY_SIZE(charge_battery_props);	} else {		battery->bat.properties = energy_battery_props;		battery->bat.num_properties =			ARRAY_SIZE(energy_battery_props);	}	battery->bat.name = acpi_device_bid(battery->device);	battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;	battery->bat.get_property = acpi_battery_get_property;	result = power_supply_register(&battery->device->dev, &battery->bat);	if (result)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -