brintos

brintos / linux-shallow public Read only

0
0
Text · 16.9 KiB · 442ceb7 Raw
627 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Power supply driver for testing.4 *5 * Copyright 2010  Anton Vorontsov <cbouatmailru@gmail.com>6 *7 * Dynamic module parameter code from the Virtual Battery Driver8 * Copyright (C) 2008 Pylone, Inc.9 * By: Masashi YOKOTA <yokota@pylone.jp>10 * Originally found here:11 * http://downloads.pylone.jp/src/virtual_battery/virtual_battery-0.0.1.tar.bz212 */13 14#include <linux/kernel.h>15#include <linux/module.h>16#include <linux/power_supply.h>17#include <linux/errno.h>18#include <linux/delay.h>19#include <generated/utsrelease.h>20 21enum test_power_id {22	TEST_AC,23	TEST_BATTERY,24	TEST_USB,25	TEST_POWER_NUM,26};27 28static int ac_online			= 1;29static int usb_online			= 1;30static int battery_status		= POWER_SUPPLY_STATUS_DISCHARGING;31static int battery_health		= POWER_SUPPLY_HEALTH_GOOD;32static int battery_present		= 1; /* true */33static int battery_technology		= POWER_SUPPLY_TECHNOLOGY_LION;34static int battery_capacity		= 50;35static int battery_voltage		= 3300;36static int battery_charge_counter	= -1000;37static int battery_current		= -1600;38static enum power_supply_charge_behaviour battery_charge_behaviour =39	POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;40 41static bool module_initialized;42 43static int test_power_get_ac_property(struct power_supply *psy,44				      enum power_supply_property psp,45				      union power_supply_propval *val)46{47	switch (psp) {48	case POWER_SUPPLY_PROP_ONLINE:49		val->intval = ac_online;50		break;51	default:52		return -EINVAL;53	}54	return 0;55}56 57static int test_power_get_usb_property(struct power_supply *psy,58				      enum power_supply_property psp,59				      union power_supply_propval *val)60{61	switch (psp) {62	case POWER_SUPPLY_PROP_ONLINE:63		val->intval = usb_online;64		break;65	default:66		return -EINVAL;67	}68	return 0;69}70 71static int test_power_get_battery_property(struct power_supply *psy,72					   enum power_supply_property psp,73					   union power_supply_propval *val)74{75	switch (psp) {76	case POWER_SUPPLY_PROP_MODEL_NAME:77		val->strval = "Test battery";78		break;79	case POWER_SUPPLY_PROP_MANUFACTURER:80		val->strval = "Linux";81		break;82	case POWER_SUPPLY_PROP_SERIAL_NUMBER:83		val->strval = UTS_RELEASE;84		break;85	case POWER_SUPPLY_PROP_STATUS:86		val->intval = battery_status;87		break;88	case POWER_SUPPLY_PROP_CHARGE_TYPE:89		val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;90		break;91	case POWER_SUPPLY_PROP_HEALTH:92		val->intval = battery_health;93		break;94	case POWER_SUPPLY_PROP_PRESENT:95		val->intval = battery_present;96		break;97	case POWER_SUPPLY_PROP_TECHNOLOGY:98		val->intval = battery_technology;99		break;100	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:101		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;102		break;103	case POWER_SUPPLY_PROP_CAPACITY:104	case POWER_SUPPLY_PROP_CHARGE_NOW:105		val->intval = battery_capacity;106		break;107	case POWER_SUPPLY_PROP_CHARGE_COUNTER:108		val->intval = battery_charge_counter;109		break;110	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:111	case POWER_SUPPLY_PROP_CHARGE_FULL:112		val->intval = 100;113		break;114	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:115	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:116		val->intval = 3600;117		break;118	case POWER_SUPPLY_PROP_TEMP:119		val->intval = 26;120		break;121	case POWER_SUPPLY_PROP_VOLTAGE_NOW:122		val->intval = battery_voltage;123		break;124	case POWER_SUPPLY_PROP_CURRENT_AVG:125	case POWER_SUPPLY_PROP_CURRENT_NOW:126		val->intval = battery_current;127		break;128	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:129		val->intval = battery_charge_behaviour;130		break;131	default:132		pr_info("%s: some properties deliberately report errors.\n",133			__func__);134		return -EINVAL;135	}136	return 0;137}138 139static int test_power_battery_property_is_writeable(struct power_supply *psy,140						    enum power_supply_property psp)141{142	return psp == POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR;143}144 145static int test_power_set_battery_property(struct power_supply *psy,146					   enum power_supply_property psp,147					   const union power_supply_propval *val)148{149	switch (psp) {150	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:151		if (val->intval < 0 ||152		    val->intval >= BITS_PER_TYPE(typeof(psy->desc->charge_behaviours)) ||153		    !(BIT(val->intval) & psy->desc->charge_behaviours)) {154			return -EINVAL;155		}156		battery_charge_behaviour = val->intval;157		break;158	default:159		return -EINVAL;160	}161	return 0;162}163 164static enum power_supply_property test_power_ac_props[] = {165	POWER_SUPPLY_PROP_ONLINE,166};167 168static enum power_supply_property test_power_battery_props[] = {169	POWER_SUPPLY_PROP_STATUS,170	POWER_SUPPLY_PROP_CHARGE_TYPE,171	POWER_SUPPLY_PROP_HEALTH,172	POWER_SUPPLY_PROP_PRESENT,173	POWER_SUPPLY_PROP_TECHNOLOGY,174	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,175	POWER_SUPPLY_PROP_CHARGE_FULL,176	POWER_SUPPLY_PROP_CHARGE_NOW,177	POWER_SUPPLY_PROP_CHARGE_COUNTER,178	POWER_SUPPLY_PROP_CAPACITY,179	POWER_SUPPLY_PROP_CAPACITY_LEVEL,180	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,181	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,182	POWER_SUPPLY_PROP_MODEL_NAME,183	POWER_SUPPLY_PROP_MANUFACTURER,184	POWER_SUPPLY_PROP_SERIAL_NUMBER,185	POWER_SUPPLY_PROP_TEMP,186	POWER_SUPPLY_PROP_VOLTAGE_NOW,187	POWER_SUPPLY_PROP_CURRENT_AVG,188	POWER_SUPPLY_PROP_CURRENT_NOW,189	POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,190};191 192static char *test_power_ac_supplied_to[] = {193	"test_battery",194};195 196static struct power_supply *test_power_supplies[TEST_POWER_NUM];197 198static const struct power_supply_desc test_power_desc[] = {199	[TEST_AC] = {200		.name = "test_ac",201		.type = POWER_SUPPLY_TYPE_MAINS,202		.properties = test_power_ac_props,203		.num_properties = ARRAY_SIZE(test_power_ac_props),204		.get_property = test_power_get_ac_property,205	},206	[TEST_BATTERY] = {207		.name = "test_battery",208		.type = POWER_SUPPLY_TYPE_BATTERY,209		.properties = test_power_battery_props,210		.num_properties = ARRAY_SIZE(test_power_battery_props),211		.get_property = test_power_get_battery_property,212		.set_property = test_power_set_battery_property,213		.property_is_writeable = test_power_battery_property_is_writeable,214		.charge_behaviours = BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO)215				   | BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)216				   | BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE),217	},218	[TEST_USB] = {219		.name = "test_usb",220		.type = POWER_SUPPLY_TYPE_USB,221		.properties = test_power_ac_props,222		.num_properties = ARRAY_SIZE(test_power_ac_props),223		.get_property = test_power_get_usb_property,224	},225};226 227static const struct power_supply_config test_power_configs[] = {228	{229		/* test_ac */230		.supplied_to = test_power_ac_supplied_to,231		.num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to),232	}, {233		/* test_battery */234	}, {235		/* test_usb */236		.supplied_to = test_power_ac_supplied_to,237		.num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to),238	},239};240 241static int __init test_power_init(void)242{243	int i;244	int ret;245 246	BUILD_BUG_ON(TEST_POWER_NUM != ARRAY_SIZE(test_power_supplies));247	BUILD_BUG_ON(TEST_POWER_NUM != ARRAY_SIZE(test_power_configs));248 249	for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) {250		test_power_supplies[i] = power_supply_register(NULL,251						&test_power_desc[i],252						&test_power_configs[i]);253		if (IS_ERR(test_power_supplies[i])) {254			pr_err("%s: failed to register %s\n", __func__,255				test_power_desc[i].name);256			ret = PTR_ERR(test_power_supplies[i]);257			goto failed;258		}259	}260 261	module_initialized = true;262	return 0;263failed:264	while (--i >= 0)265		power_supply_unregister(test_power_supplies[i]);266	return ret;267}268module_init(test_power_init);269 270static void __exit test_power_exit(void)271{272	int i;273 274	/* Let's see how we handle changes... */275	ac_online = 0;276	usb_online = 0;277	battery_status = POWER_SUPPLY_STATUS_DISCHARGING;278	for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)279		power_supply_changed(test_power_supplies[i]);280	pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n",281		__func__);282	ssleep(10);283 284	for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)285		power_supply_unregister(test_power_supplies[i]);286 287	module_initialized = false;288}289module_exit(test_power_exit);290 291 292 293#define MAX_KEYLENGTH 256294struct battery_property_map {295	int value;296	char const *key;297};298 299static struct battery_property_map map_ac_online[] = {300	{ 0,  "off"  },301	{ 1,  "on" },302	{ -1, NULL  },303};304 305static struct battery_property_map map_status[] = {306	{ POWER_SUPPLY_STATUS_CHARGING,     "charging"     },307	{ POWER_SUPPLY_STATUS_DISCHARGING,  "discharging"  },308	{ POWER_SUPPLY_STATUS_NOT_CHARGING, "not-charging" },309	{ POWER_SUPPLY_STATUS_FULL,         "full"         },310	{ -1,                               NULL           },311};312 313static struct battery_property_map map_health[] = {314	{ POWER_SUPPLY_HEALTH_GOOD,           "good"        },315	{ POWER_SUPPLY_HEALTH_OVERHEAT,       "overheat"    },316	{ POWER_SUPPLY_HEALTH_DEAD,           "dead"        },317	{ POWER_SUPPLY_HEALTH_OVERVOLTAGE,    "overvoltage" },318	{ POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, "failure"     },319	{ -1,                                 NULL          },320};321 322static struct battery_property_map map_present[] = {323	{ 0,  "false" },324	{ 1,  "true"  },325	{ -1, NULL    },326};327 328static struct battery_property_map map_technology[] = {329	{ POWER_SUPPLY_TECHNOLOGY_NiMH, "NiMH" },330	{ POWER_SUPPLY_TECHNOLOGY_LION, "LION" },331	{ POWER_SUPPLY_TECHNOLOGY_LIPO, "LIPO" },332	{ POWER_SUPPLY_TECHNOLOGY_LiFe, "LiFe" },333	{ POWER_SUPPLY_TECHNOLOGY_NiCd, "NiCd" },334	{ POWER_SUPPLY_TECHNOLOGY_LiMn, "LiMn" },335	{ -1,				NULL   },336};337 338 339static int map_get_value(struct battery_property_map *map, const char *key,340				int def_val)341{342	char buf[MAX_KEYLENGTH];343	int cr;344 345	strscpy(buf, key, MAX_KEYLENGTH);346 347	cr = strnlen(buf, MAX_KEYLENGTH) - 1;348	if (cr < 0)349		return def_val;350	if (buf[cr] == '\n')351		buf[cr] = '\0';352 353	while (map->key) {354		if (strncasecmp(map->key, buf, MAX_KEYLENGTH) == 0)355			return map->value;356		map++;357	}358 359	return def_val;360}361 362 363static const char *map_get_key(struct battery_property_map *map, int value,364				const char *def_key)365{366	while (map->key) {367		if (map->value == value)368			return map->key;369		map++;370	}371 372	return def_key;373}374 375static inline void signal_power_supply_changed(struct power_supply *psy)376{377	if (module_initialized)378		power_supply_changed(psy);379}380 381static int param_set_ac_online(const char *key, const struct kernel_param *kp)382{383	ac_online = map_get_value(map_ac_online, key, ac_online);384	signal_power_supply_changed(test_power_supplies[TEST_AC]);385	return 0;386}387 388static int param_get_ac_online(char *buffer, const struct kernel_param *kp)389{390	return sprintf(buffer, "%s\n",391			map_get_key(map_ac_online, ac_online, "unknown"));392}393 394static int param_set_usb_online(const char *key, const struct kernel_param *kp)395{396	usb_online = map_get_value(map_ac_online, key, usb_online);397	signal_power_supply_changed(test_power_supplies[TEST_USB]);398	return 0;399}400 401static int param_get_usb_online(char *buffer, const struct kernel_param *kp)402{403	return sprintf(buffer, "%s\n",404			map_get_key(map_ac_online, usb_online, "unknown"));405}406 407static int param_set_battery_status(const char *key,408					const struct kernel_param *kp)409{410	battery_status = map_get_value(map_status, key, battery_status);411	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);412	return 0;413}414 415static int param_get_battery_status(char *buffer, const struct kernel_param *kp)416{417	return sprintf(buffer, "%s\n",418			map_get_key(map_ac_online, battery_status, "unknown"));419}420 421static int param_set_battery_health(const char *key,422					const struct kernel_param *kp)423{424	battery_health = map_get_value(map_health, key, battery_health);425	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);426	return 0;427}428 429static int param_get_battery_health(char *buffer, const struct kernel_param *kp)430{431	return sprintf(buffer, "%s\n",432			map_get_key(map_ac_online, battery_health, "unknown"));433}434 435static int param_set_battery_present(const char *key,436					const struct kernel_param *kp)437{438	battery_present = map_get_value(map_present, key, battery_present);439	signal_power_supply_changed(test_power_supplies[TEST_AC]);440	return 0;441}442 443static int param_get_battery_present(char *buffer,444					const struct kernel_param *kp)445{446	return sprintf(buffer, "%s\n",447			map_get_key(map_ac_online, battery_present, "unknown"));448}449 450static int param_set_battery_technology(const char *key,451					const struct kernel_param *kp)452{453	battery_technology = map_get_value(map_technology, key,454						battery_technology);455	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);456	return 0;457}458 459static int param_get_battery_technology(char *buffer,460					const struct kernel_param *kp)461{462	return sprintf(buffer, "%s\n",463			map_get_key(map_ac_online, battery_technology,464					"unknown"));465}466 467static int param_set_battery_capacity(const char *key,468					const struct kernel_param *kp)469{470	int tmp;471 472	if (1 != sscanf(key, "%d", &tmp))473		return -EINVAL;474 475	battery_capacity = tmp;476	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);477	return 0;478}479 480#define param_get_battery_capacity param_get_int481 482static int param_set_battery_voltage(const char *key,483					const struct kernel_param *kp)484{485	int tmp;486 487	if (1 != sscanf(key, "%d", &tmp))488		return -EINVAL;489 490	battery_voltage = tmp;491	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);492	return 0;493}494 495#define param_get_battery_voltage param_get_int496 497static int param_set_battery_charge_counter(const char *key,498					const struct kernel_param *kp)499{500	int tmp;501 502	if (1 != sscanf(key, "%d", &tmp))503		return -EINVAL;504 505	battery_charge_counter = tmp;506	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);507	return 0;508}509 510#define param_get_battery_charge_counter param_get_int511 512static int param_set_battery_current(const char *key,513					const struct kernel_param *kp)514{515	int tmp;516 517	if (1 != sscanf(key, "%d", &tmp))518		return -EINVAL;519 520	battery_current = tmp;521	signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);522	return 0;523}524 525#define param_get_battery_current param_get_int526 527static const struct kernel_param_ops param_ops_ac_online = {528	.set = param_set_ac_online,529	.get = param_get_ac_online,530};531 532static const struct kernel_param_ops param_ops_usb_online = {533	.set = param_set_usb_online,534	.get = param_get_usb_online,535};536 537static const struct kernel_param_ops param_ops_battery_status = {538	.set = param_set_battery_status,539	.get = param_get_battery_status,540};541 542static const struct kernel_param_ops param_ops_battery_present = {543	.set = param_set_battery_present,544	.get = param_get_battery_present,545};546 547static const struct kernel_param_ops param_ops_battery_technology = {548	.set = param_set_battery_technology,549	.get = param_get_battery_technology,550};551 552static const struct kernel_param_ops param_ops_battery_health = {553	.set = param_set_battery_health,554	.get = param_get_battery_health,555};556 557static const struct kernel_param_ops param_ops_battery_capacity = {558	.set = param_set_battery_capacity,559	.get = param_get_battery_capacity,560};561 562static const struct kernel_param_ops param_ops_battery_voltage = {563	.set = param_set_battery_voltage,564	.get = param_get_battery_voltage,565};566 567static const struct kernel_param_ops param_ops_battery_charge_counter = {568	.set = param_set_battery_charge_counter,569	.get = param_get_battery_charge_counter,570};571 572static const struct kernel_param_ops param_ops_battery_current = {573	.set = param_set_battery_current,574	.get = param_get_battery_current,575};576 577#define param_check_ac_online(name, p) __param_check(name, p, void);578#define param_check_usb_online(name, p) __param_check(name, p, void);579#define param_check_battery_status(name, p) __param_check(name, p, void);580#define param_check_battery_present(name, p) __param_check(name, p, void);581#define param_check_battery_technology(name, p) __param_check(name, p, void);582#define param_check_battery_health(name, p) __param_check(name, p, void);583#define param_check_battery_capacity(name, p) __param_check(name, p, void);584#define param_check_battery_voltage(name, p) __param_check(name, p, void);585#define param_check_battery_charge_counter(name, p) __param_check(name, p, void);586#define param_check_battery_current(name, p) __param_check(name, p, void);587 588 589module_param(ac_online, ac_online, 0644);590MODULE_PARM_DESC(ac_online, "AC charging state <on|off>");591 592module_param(usb_online, usb_online, 0644);593MODULE_PARM_DESC(usb_online, "USB charging state <on|off>");594 595module_param(battery_status, battery_status, 0644);596MODULE_PARM_DESC(battery_status,597	"battery status <charging|discharging|not-charging|full>");598 599module_param(battery_present, battery_present, 0644);600MODULE_PARM_DESC(battery_present,601	"battery presence state <good|overheat|dead|overvoltage|failure>");602 603module_param(battery_technology, battery_technology, 0644);604MODULE_PARM_DESC(battery_technology,605	"battery technology <NiMH|LION|LIPO|LiFe|NiCd|LiMn>");606 607module_param(battery_health, battery_health, 0644);608MODULE_PARM_DESC(battery_health,609	"battery health state <good|overheat|dead|overvoltage|failure>");610 611module_param(battery_capacity, battery_capacity, 0644);612MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)");613 614module_param(battery_voltage, battery_voltage, 0644);615MODULE_PARM_DESC(battery_voltage, "battery voltage (millivolts)");616 617module_param(battery_charge_counter, battery_charge_counter, 0644);618MODULE_PARM_DESC(battery_charge_counter,619	"battery charge counter (microampere-hours)");620 621module_param(battery_current, battery_current, 0644);622MODULE_PARM_DESC(battery_current, "battery current (milliampere)");623 624MODULE_DESCRIPTION("Power supply driver for testing");625MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");626MODULE_LICENSE("GPL");627