Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.1-rc9 419 lines 11 kB view raw
1/* 2 * Power supply driver for testing. 3 * 4 * Copyright 2010 Anton Vorontsov <cbouatmailru@gmail.com> 5 * 6 * Dynamic module parameter code from the Virtual Battery Driver 7 * Copyright (C) 2008 Pylone, Inc. 8 * By: Masashi YOKOTA <yokota@pylone.jp> 9 * Originally found here: 10 * http://downloads.pylone.jp/src/virtual_battery/virtual_battery-0.0.1.tar.bz2 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License version 2 as 14 * published by the Free Software Foundation. 15 */ 16 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/power_supply.h> 20#include <linux/errno.h> 21#include <linux/delay.h> 22#include <linux/vermagic.h> 23 24static int ac_online = 1; 25static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING; 26static int battery_health = POWER_SUPPLY_HEALTH_GOOD; 27static int battery_present = 1; /* true */ 28static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; 29static int battery_capacity = 50; 30 31static int test_power_get_ac_property(struct power_supply *psy, 32 enum power_supply_property psp, 33 union power_supply_propval *val) 34{ 35 switch (psp) { 36 case POWER_SUPPLY_PROP_ONLINE: 37 val->intval = ac_online; 38 break; 39 default: 40 return -EINVAL; 41 } 42 return 0; 43} 44 45static int test_power_get_battery_property(struct power_supply *psy, 46 enum power_supply_property psp, 47 union power_supply_propval *val) 48{ 49 switch (psp) { 50 case POWER_SUPPLY_PROP_MODEL_NAME: 51 val->strval = "Test battery"; 52 break; 53 case POWER_SUPPLY_PROP_MANUFACTURER: 54 val->strval = "Linux"; 55 break; 56 case POWER_SUPPLY_PROP_SERIAL_NUMBER: 57 val->strval = UTS_RELEASE; 58 break; 59 case POWER_SUPPLY_PROP_STATUS: 60 val->intval = battery_status; 61 break; 62 case POWER_SUPPLY_PROP_CHARGE_TYPE: 63 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 64 break; 65 case POWER_SUPPLY_PROP_HEALTH: 66 val->intval = battery_health; 67 break; 68 case POWER_SUPPLY_PROP_PRESENT: 69 val->intval = battery_present; 70 break; 71 case POWER_SUPPLY_PROP_TECHNOLOGY: 72 val->intval = battery_technology; 73 break; 74 case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 75 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 76 break; 77 case POWER_SUPPLY_PROP_CAPACITY: 78 case POWER_SUPPLY_PROP_CHARGE_NOW: 79 val->intval = battery_capacity; 80 break; 81 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 82 case POWER_SUPPLY_PROP_CHARGE_FULL: 83 val->intval = 100; 84 break; 85 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 86 case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: 87 val->intval = 3600; 88 break; 89 default: 90 pr_info("%s: some properties deliberately report errors.\n", 91 __func__); 92 return -EINVAL; 93 } 94 return 0; 95} 96 97static enum power_supply_property test_power_ac_props[] = { 98 POWER_SUPPLY_PROP_ONLINE, 99}; 100 101static enum power_supply_property test_power_battery_props[] = { 102 POWER_SUPPLY_PROP_STATUS, 103 POWER_SUPPLY_PROP_CHARGE_TYPE, 104 POWER_SUPPLY_PROP_HEALTH, 105 POWER_SUPPLY_PROP_PRESENT, 106 POWER_SUPPLY_PROP_TECHNOLOGY, 107 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 108 POWER_SUPPLY_PROP_CHARGE_FULL, 109 POWER_SUPPLY_PROP_CHARGE_NOW, 110 POWER_SUPPLY_PROP_CAPACITY, 111 POWER_SUPPLY_PROP_CAPACITY_LEVEL, 112 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 113 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 114 POWER_SUPPLY_PROP_MODEL_NAME, 115 POWER_SUPPLY_PROP_MANUFACTURER, 116 POWER_SUPPLY_PROP_SERIAL_NUMBER, 117}; 118 119static char *test_power_ac_supplied_to[] = { 120 "test_battery", 121}; 122 123static struct power_supply test_power_supplies[] = { 124 { 125 .name = "test_ac", 126 .type = POWER_SUPPLY_TYPE_MAINS, 127 .supplied_to = test_power_ac_supplied_to, 128 .num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to), 129 .properties = test_power_ac_props, 130 .num_properties = ARRAY_SIZE(test_power_ac_props), 131 .get_property = test_power_get_ac_property, 132 }, { 133 .name = "test_battery", 134 .type = POWER_SUPPLY_TYPE_BATTERY, 135 .properties = test_power_battery_props, 136 .num_properties = ARRAY_SIZE(test_power_battery_props), 137 .get_property = test_power_get_battery_property, 138 }, 139}; 140 141 142static int __init test_power_init(void) 143{ 144 int i; 145 int ret; 146 147 for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) { 148 ret = power_supply_register(NULL, &test_power_supplies[i]); 149 if (ret) { 150 pr_err("%s: failed to register %s\n", __func__, 151 test_power_supplies[i].name); 152 goto failed; 153 } 154 } 155 156 return 0; 157failed: 158 while (--i >= 0) 159 power_supply_unregister(&test_power_supplies[i]); 160 return ret; 161} 162module_init(test_power_init); 163 164static void __exit test_power_exit(void) 165{ 166 int i; 167 168 /* Let's see how we handle changes... */ 169 ac_online = 0; 170 battery_status = POWER_SUPPLY_STATUS_DISCHARGING; 171 for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) 172 power_supply_changed(&test_power_supplies[i]); 173 pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n", 174 __func__); 175 ssleep(10); 176 177 for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) 178 power_supply_unregister(&test_power_supplies[i]); 179} 180module_exit(test_power_exit); 181 182 183 184#define MAX_KEYLENGTH 256 185struct battery_property_map { 186 int value; 187 char const *key; 188}; 189 190static struct battery_property_map map_ac_online[] = { 191 { 0, "on" }, 192 { 1, "off" }, 193 { -1, NULL }, 194}; 195 196static struct battery_property_map map_status[] = { 197 { POWER_SUPPLY_STATUS_CHARGING, "charging" }, 198 { POWER_SUPPLY_STATUS_DISCHARGING, "discharging" }, 199 { POWER_SUPPLY_STATUS_NOT_CHARGING, "not-charging" }, 200 { POWER_SUPPLY_STATUS_FULL, "full" }, 201 { -1, NULL }, 202}; 203 204static struct battery_property_map map_health[] = { 205 { POWER_SUPPLY_HEALTH_GOOD, "good" }, 206 { POWER_SUPPLY_HEALTH_OVERHEAT, "overheat" }, 207 { POWER_SUPPLY_HEALTH_DEAD, "dead" }, 208 { POWER_SUPPLY_HEALTH_OVERVOLTAGE, "overvoltage" }, 209 { POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, "failure" }, 210 { -1, NULL }, 211}; 212 213static struct battery_property_map map_present[] = { 214 { 0, "false" }, 215 { 1, "true" }, 216 { -1, NULL }, 217}; 218 219static struct battery_property_map map_technology[] = { 220 { POWER_SUPPLY_TECHNOLOGY_NiMH, "NiMH" }, 221 { POWER_SUPPLY_TECHNOLOGY_LION, "LION" }, 222 { POWER_SUPPLY_TECHNOLOGY_LIPO, "LIPO" }, 223 { POWER_SUPPLY_TECHNOLOGY_LiFe, "LiFe" }, 224 { POWER_SUPPLY_TECHNOLOGY_NiCd, "NiCd" }, 225 { POWER_SUPPLY_TECHNOLOGY_LiMn, "LiMn" }, 226 { -1, NULL }, 227}; 228 229 230static int map_get_value(struct battery_property_map *map, const char *key, 231 int def_val) 232{ 233 char buf[MAX_KEYLENGTH]; 234 int cr; 235 236 strncpy(buf, key, MAX_KEYLENGTH); 237 buf[MAX_KEYLENGTH-1] = '\0'; 238 239 cr = strnlen(buf, MAX_KEYLENGTH) - 1; 240 if (buf[cr] == '\n') 241 buf[cr] = '\0'; 242 243 while (map->key) { 244 if (strncasecmp(map->key, buf, MAX_KEYLENGTH) == 0) 245 return map->value; 246 map++; 247 } 248 249 return def_val; 250} 251 252 253static const char *map_get_key(struct battery_property_map *map, int value, 254 const char *def_key) 255{ 256 while (map->key) { 257 if (map->value == value) 258 return map->key; 259 map++; 260 } 261 262 return def_key; 263} 264 265static int param_set_ac_online(const char *key, const struct kernel_param *kp) 266{ 267 ac_online = map_get_value(map_ac_online, key, ac_online); 268 power_supply_changed(&test_power_supplies[0]); 269 return 0; 270} 271 272static int param_get_ac_online(char *buffer, const struct kernel_param *kp) 273{ 274 strcpy(buffer, map_get_key(map_ac_online, ac_online, "unknown")); 275 return strlen(buffer); 276} 277 278static int param_set_battery_status(const char *key, 279 const struct kernel_param *kp) 280{ 281 battery_status = map_get_value(map_status, key, battery_status); 282 power_supply_changed(&test_power_supplies[1]); 283 return 0; 284} 285 286static int param_get_battery_status(char *buffer, const struct kernel_param *kp) 287{ 288 strcpy(buffer, map_get_key(map_status, battery_status, "unknown")); 289 return strlen(buffer); 290} 291 292static int param_set_battery_health(const char *key, 293 const struct kernel_param *kp) 294{ 295 battery_health = map_get_value(map_health, key, battery_health); 296 power_supply_changed(&test_power_supplies[1]); 297 return 0; 298} 299 300static int param_get_battery_health(char *buffer, const struct kernel_param *kp) 301{ 302 strcpy(buffer, map_get_key(map_health, battery_health, "unknown")); 303 return strlen(buffer); 304} 305 306static int param_set_battery_present(const char *key, 307 const struct kernel_param *kp) 308{ 309 battery_present = map_get_value(map_present, key, battery_present); 310 power_supply_changed(&test_power_supplies[0]); 311 return 0; 312} 313 314static int param_get_battery_present(char *buffer, 315 const struct kernel_param *kp) 316{ 317 strcpy(buffer, map_get_key(map_present, battery_present, "unknown")); 318 return strlen(buffer); 319} 320 321static int param_set_battery_technology(const char *key, 322 const struct kernel_param *kp) 323{ 324 battery_technology = map_get_value(map_technology, key, 325 battery_technology); 326 power_supply_changed(&test_power_supplies[1]); 327 return 0; 328} 329 330static int param_get_battery_technology(char *buffer, 331 const struct kernel_param *kp) 332{ 333 strcpy(buffer, 334 map_get_key(map_technology, battery_technology, "unknown")); 335 return strlen(buffer); 336} 337 338static int param_set_battery_capacity(const char *key, 339 const struct kernel_param *kp) 340{ 341 int tmp; 342 343 if (1 != sscanf(key, "%d", &tmp)) 344 return -EINVAL; 345 346 battery_capacity = tmp; 347 power_supply_changed(&test_power_supplies[1]); 348 return 0; 349} 350 351#define param_get_battery_capacity param_get_int 352 353 354 355static struct kernel_param_ops param_ops_ac_online = { 356 .set = param_set_ac_online, 357 .get = param_get_ac_online, 358}; 359 360static struct kernel_param_ops param_ops_battery_status = { 361 .set = param_set_battery_status, 362 .get = param_get_battery_status, 363}; 364 365static struct kernel_param_ops param_ops_battery_present = { 366 .set = param_set_battery_present, 367 .get = param_get_battery_present, 368}; 369 370static struct kernel_param_ops param_ops_battery_technology = { 371 .set = param_set_battery_technology, 372 .get = param_get_battery_technology, 373}; 374 375static struct kernel_param_ops param_ops_battery_health = { 376 .set = param_set_battery_health, 377 .get = param_get_battery_health, 378}; 379 380static struct kernel_param_ops param_ops_battery_capacity = { 381 .set = param_set_battery_capacity, 382 .get = param_get_battery_capacity, 383}; 384 385 386#define param_check_ac_online(name, p) __param_check(name, p, void); 387#define param_check_battery_status(name, p) __param_check(name, p, void); 388#define param_check_battery_present(name, p) __param_check(name, p, void); 389#define param_check_battery_technology(name, p) __param_check(name, p, void); 390#define param_check_battery_health(name, p) __param_check(name, p, void); 391#define param_check_battery_capacity(name, p) __param_check(name, p, void); 392 393 394module_param(ac_online, ac_online, 0644); 395MODULE_PARM_DESC(ac_online, "AC charging state <on|off>"); 396 397module_param(battery_status, battery_status, 0644); 398MODULE_PARM_DESC(battery_status, 399 "battery status <charging|discharging|not-charging|full>"); 400 401module_param(battery_present, battery_present, 0644); 402MODULE_PARM_DESC(battery_present, 403 "battery presence state <good|overheat|dead|overvoltage|failure>"); 404 405module_param(battery_technology, battery_technology, 0644); 406MODULE_PARM_DESC(battery_technology, 407 "battery technology <NiMH|LION|LIPO|LiFe|NiCd|LiMn>"); 408 409module_param(battery_health, battery_health, 0644); 410MODULE_PARM_DESC(battery_health, 411 "battery health state <good|overheat|dead|overvoltage|failure>"); 412 413module_param(battery_capacity, battery_capacity, 0644); 414MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)"); 415 416 417MODULE_DESCRIPTION("Power supply driver for testing"); 418MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); 419MODULE_LICENSE("GPL");