apm_power.c

来自「linux 内核源代码」· C语言 代码 · 共 303 行

C
303
字号
/* * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> * Copyright © 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru> * * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru> * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is * preserved in its entirety in all copies and derived works. */#include <linux/module.h>#include <linux/power_supply.h>#include <linux/apm-emulation.h>#define PSY_PROP(psy, prop, val) psy->get_property(psy, \			 POWER_SUPPLY_PROP_##prop, val)#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \							 prop, val)#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)static struct power_supply *main_battery;static void find_main_battery(void){	struct device *dev;	struct power_supply *bat = NULL;	struct power_supply *max_charge_bat = NULL;	struct power_supply *max_energy_bat = NULL;	union power_supply_propval full;	int max_charge = 0;	int max_energy = 0;	main_battery = NULL;	list_for_each_entry(dev, &power_supply_class->devices, node) {		bat = dev_get_drvdata(dev);		if (bat->use_for_apm) {			/* nice, we explicitly asked to report this battery. */			main_battery = bat;			return;		}		if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) ||				!PSY_PROP(bat, CHARGE_FULL, &full)) {			if (full.intval > max_charge) {				max_charge_bat = bat;				max_charge = full.intval;			}		} else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) ||				!PSY_PROP(bat, ENERGY_FULL, &full)) {			if (full.intval > max_energy) {				max_energy_bat = bat;				max_energy = full.intval;			}		}	}	if ((max_energy_bat && max_charge_bat) &&			(max_energy_bat != max_charge_bat)) {		/* try guess battery with more capacity */		if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) {			if (max_energy > max_charge * full.intval)				main_battery = max_energy_bat;			else				main_battery = max_charge_bat;		} else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN,								  &full)) {			if (max_charge > max_energy / full.intval)				main_battery = max_charge_bat;			else				main_battery = max_energy_bat;		} else {			/* give up, choice any */			main_battery = max_energy_bat;		}	} else if (max_charge_bat) {		main_battery = max_charge_bat;	} else if (max_energy_bat) {		main_battery = max_energy_bat;	} else {		/* give up, try the last if any */		main_battery = bat;	}}static int calculate_time(int status, int using_charge){	union power_supply_propval full;	union power_supply_propval empty;	union power_supply_propval cur;	union power_supply_propval I;	enum power_supply_property full_prop;	enum power_supply_property full_design_prop;	enum power_supply_property empty_prop;	enum power_supply_property empty_design_prop;	enum power_supply_property cur_avg_prop;	enum power_supply_property cur_now_prop;	if (MPSY_PROP(CURRENT_AVG, &I)) {		/* if battery can't report average value, use momentary */		if (MPSY_PROP(CURRENT_NOW, &I))			return -1;	}	if (using_charge) {		full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;		full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;		empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;		cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;		cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;	} else {		full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;		full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;		empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;		cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;		cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;	}	if (_MPSY_PROP(full_prop, &full)) {		/* if battery can't report this property, use design value */		if (_MPSY_PROP(full_design_prop, &full))			return -1;	}	if (_MPSY_PROP(empty_prop, &empty)) {		/* if battery can't report this property, use design value */		if (_MPSY_PROP(empty_design_prop, &empty))			empty.intval = 0;	}	if (_MPSY_PROP(cur_avg_prop, &cur)) {		/* if battery can't report average value, use momentary */		if (_MPSY_PROP(cur_now_prop, &cur))			return -1;	}	if (status == POWER_SUPPLY_STATUS_CHARGING)		return ((cur.intval - full.intval) * 60L) / I.intval;	else		return -((cur.intval - empty.intval) * 60L) / I.intval;}static int calculate_capacity(int using_charge){	enum power_supply_property full_prop, empty_prop;	enum power_supply_property full_design_prop, empty_design_prop;	enum power_supply_property now_prop, avg_prop;	union power_supply_propval empty, full, cur;	int ret;	if (using_charge) {		full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;		empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;		full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;		now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;		avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;	} else {		full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;		empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;		full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;		empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;		now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;		avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;	}	if (_MPSY_PROP(full_prop, &full)) {		/* if battery can't report this property, use design value */		if (_MPSY_PROP(full_design_prop, &full))			return -1;	}	if (_MPSY_PROP(avg_prop, &cur)) {		/* if battery can't report average value, use momentary */		if (_MPSY_PROP(now_prop, &cur))			return -1;	}	if (_MPSY_PROP(empty_prop, &empty)) {		/* if battery can't report this property, use design value */		if (_MPSY_PROP(empty_design_prop, &empty))			empty.intval = 0;	}	if (full.intval - empty.intval)		ret =  ((cur.intval - empty.intval) * 100L) /		       (full.intval - empty.intval);	else		return -1;	if (ret > 100)		return 100;	else if (ret < 0)		return 0;	return ret;}static void apm_battery_apm_get_power_status(struct apm_power_info *info){	union power_supply_propval status;	union power_supply_propval capacity, time_to_full, time_to_empty;	down(&power_supply_class->sem);	find_main_battery();	if (!main_battery) {		up(&power_supply_class->sem);		return;	}	/* status */	if (MPSY_PROP(STATUS, &status))		status.intval = POWER_SUPPLY_STATUS_UNKNOWN;	/* ac line status */	if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) ||	    (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) ||	    (status.intval == POWER_SUPPLY_STATUS_FULL))		info->ac_line_status = APM_AC_ONLINE;	else		info->ac_line_status = APM_AC_OFFLINE;	/* battery life (i.e. capacity, in percents) */	if (MPSY_PROP(CAPACITY, &capacity) == 0) {		info->battery_life = capacity.intval;	} else {		/* try calculate using energy */		info->battery_life = calculate_capacity(0);		/* if failed try calculate using charge instead */		if (info->battery_life == -1)			info->battery_life = calculate_capacity(1);	}	/* charging status */	if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {		info->battery_status = APM_BATTERY_STATUS_CHARGING;	} else {		if (info->battery_life > 50)			info->battery_status = APM_BATTERY_STATUS_HIGH;		else if (info->battery_life > 5)			info->battery_status = APM_BATTERY_STATUS_LOW;		else			info->battery_status = APM_BATTERY_STATUS_CRITICAL;	}	info->battery_flag = info->battery_status;	/* time */	info->units = APM_UNITS_MINS;	if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {		if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||				!MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {			info->time = time_to_full.intval / 60;		} else {			info->time = calculate_time(status.intval, 0);			if (info->time == -1)				info->time = calculate_time(status.intval, 1);		}	} else {		if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||			      !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {			info->time = time_to_empty.intval / 60;		} else {			info->time = calculate_time(status.intval, 0);			if (info->time == -1)				info->time = calculate_time(status.intval, 1);		}	}	up(&power_supply_class->sem);}static int __init apm_battery_init(void){	printk(KERN_INFO "APM Battery Driver\n");	apm_get_power_status = apm_battery_apm_get_power_status;	return 0;}static void __exit apm_battery_exit(void){	apm_get_power_status = NULL;}module_init(apm_battery_init);module_exit(apm_battery_exit);MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>");MODULE_DESCRIPTION("APM emulation driver for battery monitoring class");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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