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 usb_online = 1; 26static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING; 27static int battery_health = POWER_SUPPLY_HEALTH_GOOD; 28static int battery_present = 1; /* true */ 29static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; 30static int battery_capacity = 50; 31static int battery_voltage = 3300; 32 33static bool module_initialized; 34 35static int test_power_get_ac_property(struct power_supply *psy, 36 enum power_supply_property psp, 37 union power_supply_propval *val) 38{ 39 switch (psp) { 40 case POWER_SUPPLY_PROP_ONLINE: 41 val->intval = ac_online; 42 break; 43 default: 44 return -EINVAL; 45 } 46 return 0; 47} 48 49static int test_power_get_usb_property(struct power_supply *psy, 50 enum power_supply_property psp, 51 union power_supply_propval *val) 52{ 53 switch (psp) { 54 case POWER_SUPPLY_PROP_ONLINE: 55 val->intval = usb_online; 56 break; 57 default: 58 return -EINVAL; 59 } 60 return 0; 61} 62 63static int test_power_get_battery_property(struct power_supply *psy, 64 enum power_supply_property psp, 65 union power_supply_propval *val) 66{ 67 switch (psp) { 68 case POWER_SUPPLY_PROP_MODEL_NAME: 69 val->strval = "Test battery"; 70 break; 71 case POWER_SUPPLY_PROP_MANUFACTURER: 72 val->strval = "Linux"; 73 break; 74 case POWER_SUPPLY_PROP_SERIAL_NUMBER: 75 val->strval = UTS_RELEASE; 76 break; 77 case POWER_SUPPLY_PROP_STATUS: 78 val->intval = battery_status; 79 break; 80 case POWER_SUPPLY_PROP_CHARGE_TYPE: 81 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 82 break; 83 case POWER_SUPPLY_PROP_HEALTH: 84 val->intval = battery_health; 85 break; 86 case POWER_SUPPLY_PROP_PRESENT: 87 val->intval = battery_present; 88 break; 89 case POWER_SUPPLY_PROP_TECHNOLOGY: 90 val->intval = battery_technology; 91 break; 92 case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 93 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 94 break; 95 case POWER_SUPPLY_PROP_CAPACITY: 96 case POWER_SUPPLY_PROP_CHARGE_NOW: 97 val->intval = battery_capacity; 98 break; 99 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 100 case POWER_SUPPLY_PROP_CHARGE_FULL: 101 val->intval = 100; 102 break; 103 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 104 case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: 105 val->intval = 3600; 106 break; 107 case POWER_SUPPLY_PROP_TEMP: 108 val->intval = 26; 109 break; 110 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 111 val->intval = battery_voltage; 112 break; 113 default: 114 pr_info("%s: some properties deliberately report errors.\n", 115 __func__); 116 return -EINVAL; 117 } 118 return 0; 119} 120 121static enum power_supply_property test_power_ac_props[] = { 122 POWER_SUPPLY_PROP_ONLINE, 123}; 124 125static enum power_supply_property test_power_battery_props[] = { 126 POWER_SUPPLY_PROP_STATUS, 127 POWER_SUPPLY_PROP_CHARGE_TYPE, 128 POWER_SUPPLY_PROP_HEALTH, 129 POWER_SUPPLY_PROP_PRESENT, 130 POWER_SUPPLY_PROP_TECHNOLOGY, 131 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 132 POWER_SUPPLY_PROP_CHARGE_FULL, 133 POWER_SUPPLY_PROP_CHARGE_NOW, 134 POWER_SUPPLY_PROP_CAPACITY, 135 POWER_SUPPLY_PROP_CAPACITY_LEVEL, 136 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 137 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 138 POWER_SUPPLY_PROP_MODEL_NAME, 139 POWER_SUPPLY_PROP_MANUFACTURER, 140 POWER_SUPPLY_PROP_SERIAL_NUMBER, 141 POWER_SUPPLY_PROP_TEMP, 142 POWER_SUPPLY_PROP_VOLTAGE_NOW, 143}; 144 145static char *test_power_ac_supplied_to[] = { 146 "test_battery", 147}; 148 149static struct power_supply test_power_supplies[] = { 150 { 151 .name = "test_ac", 152 .type = POWER_SUPPLY_TYPE_MAINS, 153 .supplied_to = test_power_ac_supplied_to, 154 .num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to), 155 .properties = test_power_ac_props, 156 .num_properties = ARRAY_SIZE(test_power_ac_props), 157 .get_property = test_power_get_ac_property, 158 }, { 159 .name = "test_battery", 160 .type = POWER_SUPPLY_TYPE_BATTERY, 161 .properties = test_power_battery_props, 162 .num_properties = ARRAY_SIZE(test_power_battery_props), 163 .get_property = test_power_get_battery_property, 164 }, { 165 .name = "test_usb", 166 .type = POWER_SUPPLY_TYPE_USB, 167 .supplied_to = test_power_ac_supplied_to, 168 .num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to), 169 .properties = test_power_ac_props, 170 .num_properties = ARRAY_SIZE(test_power_ac_props), 171 .get_property = test_power_get_usb_property, 172 }, 173}; 174 175 176static int __init test_power_init(void) 177{ 178 int i; 179 int ret; 180 181 for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) { 182 ret = power_supply_register(NULL, &test_power_supplies[i]); 183 if (ret) { 184 pr_err("%s: failed to register %s\n", __func__, 185 test_power_supplies[i].name); 186 goto failed; 187 } 188 } 189 190 module_initialized = true; 191 return 0; 192failed: 193 while (--i >= 0) 194 power_supply_unregister(&test_power_supplies[i]); 195 return ret; 196} 197module_init(test_power_init); 198 199static void __exit test_power_exit(void) 200{ 201 int i; 202 203 /* Let's see how we handle changes... */ 204 ac_online = 0; 205 usb_online = 0; 206 battery_status = POWER_SUPPLY_STATUS_DISCHARGING; 207 for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) 208 power_supply_changed(&test_power_supplies[i]); 209 pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n", 210 __func__); 211 ssleep(10); 212 213 for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) 214 power_supply_unregister(&test_power_supplies[i]); 215 216 module_initialized = false; 217} 218module_exit(test_power_exit); 219 220 221 222#define MAX_KEYLENGTH 256 223struct battery_property_map { 224 int value; 225 char const *key; 226}; 227 228static struct battery_property_map map_ac_online[] = { 229 { 0, "off" }, 230 { 1, "on" }, 231 { -1, NULL }, 232}; 233 234static struct battery_property_map map_status[] = { 235 { POWER_SUPPLY_STATUS_CHARGING, "charging" }, 236 { POWER_SUPPLY_STATUS_DISCHARGING, "discharging" }, 237 { POWER_SUPPLY_STATUS_NOT_CHARGING, "not-charging" }, 238 { POWER_SUPPLY_STATUS_FULL, "full" }, 239 { -1, NULL }, 240}; 241 242static struct battery_property_map map_health[] = { 243 { POWER_SUPPLY_HEALTH_GOOD, "good" }, 244 { POWER_SUPPLY_HEALTH_OVERHEAT, "overheat" }, 245 { POWER_SUPPLY_HEALTH_DEAD, "dead" }, 246 { POWER_SUPPLY_HEALTH_OVERVOLTAGE, "overvoltage" }, 247 { POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, "failure" }, 248 { -1, NULL }, 249}; 250 251static struct battery_property_map map_present[] = { 252 { 0, "false" }, 253 { 1, "true" }, 254 { -1, NULL }, 255}; 256 257static struct battery_property_map map_technology[] = { 258 { POWER_SUPPLY_TECHNOLOGY_NiMH, "NiMH" }, 259 { POWER_SUPPLY_TECHNOLOGY_LION, "LION" }, 260 { POWER_SUPPLY_TECHNOLOGY_LIPO, "LIPO" }, 261 { POWER_SUPPLY_TECHNOLOGY_LiFe, "LiFe" }, 262 { POWER_SUPPLY_TECHNOLOGY_NiCd, "NiCd" }, 263 { POWER_SUPPLY_TECHNOLOGY_LiMn, "LiMn" }, 264 { -1, NULL }, 265}; 266 267 268static int map_get_value(struct battery_property_map *map, const char *key, 269 int def_val) 270{ 271 char buf[MAX_KEYLENGTH]; 272 int cr; 273 274 strncpy(buf, key, MAX_KEYLENGTH); 275 buf[MAX_KEYLENGTH-1] = '\0'; 276 277 cr = strnlen(buf, MAX_KEYLENGTH) - 1; 278 if (buf[cr] == '\n') 279 buf[cr] = '\0'; 280 281 while (map->key) { 282 if (strncasecmp(map->key, buf, MAX_KEYLENGTH) == 0) 283 return map->value; 284 map++; 285 } 286 287 return def_val; 288} 289 290 291static const char *map_get_key(struct battery_property_map *map, int value, 292 const char *def_key) 293{ 294 while (map->key) { 295 if (map->value == value) 296 return map->key; 297 map++; 298 } 299 300 return def_key; 301} 302 303static inline void signal_power_supply_changed(struct power_supply *psy) 304{ 305 if (module_initialized) 306 power_supply_changed(psy); 307} 308 309static int param_set_ac_online(const char *key, const struct kernel_param *kp) 310{ 311 ac_online = map_get_value(map_ac_online, key, ac_online); 312 signal_power_supply_changed(&test_power_supplies[0]); 313 return 0; 314} 315 316static int param_get_ac_online(char *buffer, const struct kernel_param *kp) 317{ 318 strcpy(buffer, map_get_key(map_ac_online, ac_online, "unknown")); 319 return strlen(buffer); 320} 321 322static int param_set_usb_online(const char *key, const struct kernel_param *kp) 323{ 324 usb_online = map_get_value(map_ac_online, key, usb_online); 325 signal_power_supply_changed(&test_power_supplies[2]); 326 return 0; 327} 328 329static int param_get_usb_online(char *buffer, const struct kernel_param *kp) 330{ 331 strcpy(buffer, map_get_key(map_ac_online, usb_online, "unknown")); 332 return strlen(buffer); 333} 334 335static int param_set_battery_status(const char *key, 336 const struct kernel_param *kp) 337{ 338 battery_status = map_get_value(map_status, key, battery_status); 339 signal_power_supply_changed(&test_power_supplies[1]); 340 return 0; 341} 342 343static int param_get_battery_status(char *buffer, const struct kernel_param *kp) 344{ 345 strcpy(buffer, map_get_key(map_status, battery_status, "unknown")); 346 return strlen(buffer); 347} 348 349static int param_set_battery_health(const char *key, 350 const struct kernel_param *kp) 351{ 352 battery_health = map_get_value(map_health, key, battery_health); 353 signal_power_supply_changed(&test_power_supplies[1]); 354 return 0; 355} 356 357static int param_get_battery_health(char *buffer, const struct kernel_param *kp) 358{ 359 strcpy(buffer, map_get_key(map_health, battery_health, "unknown")); 360 return strlen(buffer); 361} 362 363static int param_set_battery_present(const char *key, 364 const struct kernel_param *kp) 365{ 366 battery_present = map_get_value(map_present, key, battery_present); 367 signal_power_supply_changed(&test_power_supplies[0]); 368 return 0; 369} 370 371static int param_get_battery_present(char *buffer, 372 const struct kernel_param *kp) 373{ 374 strcpy(buffer, map_get_key(map_present, battery_present, "unknown")); 375 return strlen(buffer); 376} 377 378static int param_set_battery_technology(const char *key, 379 const struct kernel_param *kp) 380{ 381 battery_technology = map_get_value(map_technology, key, 382 battery_technology); 383 signal_power_supply_changed(&test_power_supplies[1]); 384 return 0; 385} 386 387static int param_get_battery_technology(char *buffer, 388 const struct kernel_param *kp) 389{ 390 strcpy(buffer, 391 map_get_key(map_technology, battery_technology, "unknown")); 392 return strlen(buffer); 393} 394 395static int param_set_battery_capacity(const char *key, 396 const struct kernel_param *kp) 397{ 398 int tmp; 399 400 if (1 != sscanf(key, "%d", &tmp)) 401 return -EINVAL; 402 403 battery_capacity = tmp; 404 signal_power_supply_changed(&test_power_supplies[1]); 405 return 0; 406} 407 408#define param_get_battery_capacity param_get_int 409 410static int param_set_battery_voltage(const char *key, 411 const struct kernel_param *kp) 412{ 413 int tmp; 414 415 if (1 != sscanf(key, "%d", &tmp)) 416 return -EINVAL; 417 418 battery_voltage = tmp; 419 signal_power_supply_changed(&test_power_supplies[1]); 420 return 0; 421} 422 423#define param_get_battery_voltage param_get_int 424 425static struct kernel_param_ops param_ops_ac_online = { 426 .set = param_set_ac_online, 427 .get = param_get_ac_online, 428}; 429 430static struct kernel_param_ops param_ops_usb_online = { 431 .set = param_set_usb_online, 432 .get = param_get_usb_online, 433}; 434 435static struct kernel_param_ops param_ops_battery_status = { 436 .set = param_set_battery_status, 437 .get = param_get_battery_status, 438}; 439 440static struct kernel_param_ops param_ops_battery_present = { 441 .set = param_set_battery_present, 442 .get = param_get_battery_present, 443}; 444 445static struct kernel_param_ops param_ops_battery_technology = { 446 .set = param_set_battery_technology, 447 .get = param_get_battery_technology, 448}; 449 450static struct kernel_param_ops param_ops_battery_health = { 451 .set = param_set_battery_health, 452 .get = param_get_battery_health, 453}; 454 455static struct kernel_param_ops param_ops_battery_capacity = { 456 .set = param_set_battery_capacity, 457 .get = param_get_battery_capacity, 458}; 459 460static struct kernel_param_ops param_ops_battery_voltage = { 461 .set = param_set_battery_voltage, 462 .get = param_get_battery_voltage, 463}; 464 465#define param_check_ac_online(name, p) __param_check(name, p, void); 466#define param_check_usb_online(name, p) __param_check(name, p, void); 467#define param_check_battery_status(name, p) __param_check(name, p, void); 468#define param_check_battery_present(name, p) __param_check(name, p, void); 469#define param_check_battery_technology(name, p) __param_check(name, p, void); 470#define param_check_battery_health(name, p) __param_check(name, p, void); 471#define param_check_battery_capacity(name, p) __param_check(name, p, void); 472#define param_check_battery_voltage(name, p) __param_check(name, p, void); 473 474 475module_param(ac_online, ac_online, 0644); 476MODULE_PARM_DESC(ac_online, "AC charging state <on|off>"); 477 478module_param(usb_online, usb_online, 0644); 479MODULE_PARM_DESC(usb_online, "USB charging state <on|off>"); 480 481module_param(battery_status, battery_status, 0644); 482MODULE_PARM_DESC(battery_status, 483 "battery status <charging|discharging|not-charging|full>"); 484 485module_param(battery_present, battery_present, 0644); 486MODULE_PARM_DESC(battery_present, 487 "battery presence state <good|overheat|dead|overvoltage|failure>"); 488 489module_param(battery_technology, battery_technology, 0644); 490MODULE_PARM_DESC(battery_technology, 491 "battery technology <NiMH|LION|LIPO|LiFe|NiCd|LiMn>"); 492 493module_param(battery_health, battery_health, 0644); 494MODULE_PARM_DESC(battery_health, 495 "battery health state <good|overheat|dead|overvoltage|failure>"); 496 497module_param(battery_capacity, battery_capacity, 0644); 498MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)"); 499 500module_param(battery_voltage, battery_voltage, 0644); 501MODULE_PARM_DESC(battery_voltage, "battery voltage (millivolts)"); 502 503MODULE_DESCRIPTION("Power supply driver for testing"); 504MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); 505MODULE_LICENSE("GPL"); 506