linux/drivers/power/test_power.c
<<
>>
Prefs
   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