cregit-Linux how code gets into the kernel

Release 4.14 drivers/power/supply/apm_power.c

/*
 * 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/device.h>
#include <linux/power_supply.h>
#include <linux/apm-emulation.h>



#define PSY_PROP(psy, prop, val) (power_supply_get_property(psy, \
                         POWER_SUPPLY_PROP_##prop, val))


#define _MPSY_PROP(prop, val) (power_supply_get_property(main_battery, \
                                                         prop, val))


#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)

static DEFINE_MUTEX(apm_mutex);

static struct power_supply *main_battery;


enum apm_source {
	
SOURCE_ENERGY,
	
SOURCE_CHARGE,
	
SOURCE_VOLTAGE,
};


struct find_bat_param {
	
struct power_supply *main;
	
struct power_supply *bat;
	
struct power_supply *max_charge_bat;
	
struct power_supply *max_energy_bat;
	
union power_supply_propval full;
	
int max_charge;
	
int max_energy;
};


static int __find_main_battery(struct device *dev, void *data) { struct find_bat_param *bp = (struct find_bat_param *)data; bp->bat = dev_get_drvdata(dev); if (bp->bat->desc->use_for_apm) { /* nice, we explicitly asked to report this battery. */ bp->main = bp->bat; return 1; } if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) || !PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) { if (bp->full.intval > bp->max_charge) { bp->max_charge_bat = bp->bat; bp->max_charge = bp->full.intval; } } else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) || !PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) { if (bp->full.intval > bp->max_energy) { bp->max_energy_bat = bp->bat; bp->max_energy = bp->full.intval; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov11357.65%250.00%
Dave Young8141.33%125.00%
Krzysztof Kozlowski21.02%125.00%
Total196100.00%4100.00%


static void find_main_battery(void) { struct find_bat_param bp; int error; memset(&bp, 0, sizeof(struct find_bat_param)); main_battery = NULL; bp.main = main_battery; error = class_for_each_device(power_supply_class, NULL, &bp, __find_main_battery); if (error) { main_battery = bp.main; return; } if ((bp.max_energy_bat && bp.max_charge_bat) && (bp.max_energy_bat != bp.max_charge_bat)) { /* try guess battery with more capacity */ if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN, &bp.full)) { if (bp.max_energy > bp.max_charge * bp.full.intval) main_battery = bp.max_energy_bat; else main_battery = bp.max_charge_bat; } else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN, &bp.full)) { if (bp.max_charge > bp.max_energy / bp.full.intval) main_battery = bp.max_charge_bat; else main_battery = bp.max_energy_bat; } else { /* give up, choice any */ main_battery = bp.max_energy_bat; } } else if (bp.max_charge_bat) { main_battery = bp.max_charge_bat; } else if (bp.max_energy_bat) { main_battery = bp.max_energy_bat; } else { /* give up, try the last if any */ main_battery = bp.bat; } }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov12652.94%250.00%
Dave Young11046.22%125.00%
Greg Kroah-Hartman20.84%125.00%
Total238100.00%4100.00%


static int do_calculate_time(int status, enum apm_source source) { 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 (!I.intval) return 0; switch (source) { case SOURCE_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; break; case SOURCE_ENERGY: 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; break; case SOURCE_VOLTAGE: full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; break; default: printk(KERN_ERR "Unsupported source: %d\n", source); return -1; } 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; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov26782.92%375.00%
Dmitry Baryshkov5517.08%125.00%
Total322100.00%4100.00%


static int calculate_time(int status) { int time; time = do_calculate_time(status, SOURCE_ENERGY); if (time != -1) return time; time = do_calculate_time(status, SOURCE_CHARGE); if (time != -1) return time; time = do_calculate_time(status, SOURCE_VOLTAGE); if (time != -1) return time; return -1; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Baryshkov73100.00%1100.00%
Total73100.00%1100.00%


static int calculate_capacity(enum apm_source source) { 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; switch (source) { case SOURCE_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; break; case SOURCE_ENERGY: 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; break; case SOURCE_VOLTAGE: full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; break; default: printk(KERN_ERR "Unsupported source: %d\n", source); return -1; } 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; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov23581.60%266.67%
Dmitry Baryshkov5318.40%133.33%
Total288100.00%3100.00%


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; mutex_lock(&apm_mutex); find_main_battery(); if (!main_battery) { mutex_unlock(&apm_mutex); 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(SOURCE_ENERGY); /* if failed try calculate using charge instead */ if (info->battery_life == -1) info->battery_life = calculate_capacity(SOURCE_CHARGE); if (info->battery_life == -1) info->battery_life = calculate_capacity(SOURCE_VOLTAGE); } /* 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); } 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); } mutex_unlock(&apm_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov32592.86%360.00%
Dmitry Baryshkov195.43%120.00%
Dave Young61.71%120.00%
Total350100.00%5100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov22100.00%1100.00%
Total22100.00%1100.00%


static void __exit apm_battery_exit(void) { apm_get_power_status = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov13100.00%1100.00%
Total13100.00%1100.00%

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");

Overall Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov119873.68%650.00%
Dmitry Baryshkov21613.28%18.33%
Dave Young20312.48%18.33%
Krzysztof Kozlowski40.25%216.67%
Paul Gortmaker30.18%18.33%
Greg Kroah-Hartman20.12%18.33%
Total1626100.00%12100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.