/* * Copyright (c) 2026 Vincent Schweiger * * Fake Battery driver for Linux. * * The main purpose is to emulate a battery for battery-less systems like desktops. */ /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include #include #define VERSION_STR "0.1.1" static struct power_supply *fake_battery; static struct power_supply_desc battery_desc; static enum power_supply_property fake_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_SERIAL_NUMBER, }; static int fake_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = POWER_SUPPLY_STATUS_FULL; break; case POWER_SUPPLY_PROP_HEALTH: val->intval = POWER_SUPPLY_HEALTH_GOOD; break; case POWER_SUPPLY_PROP_PRESENT: val->intval = 1; break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; break; case POWER_SUPPLY_PROP_CAPACITY: val->intval = 100; break; case POWER_SUPPLY_PROP_CAPACITY_LEVEL: val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: val->intval = 5000000; /* 5000 mAh */ break; case POWER_SUPPLY_PROP_CHARGE_FULL: val->intval = 5000000; /* 5000 mAh */ break; case POWER_SUPPLY_PROP_CHARGE_NOW: val->intval = 5000000; /* 5000 mAh (fully charged) */ break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = 4200000; /* 4.2V */ break; case POWER_SUPPLY_PROP_CURRENT_NOW: val->intval = 0; /* Not charging */ break; case POWER_SUPPLY_PROP_TEMP: val->intval = 253; /* 25°C in 0.1°C units */ break; case POWER_SUPPLY_PROP_MODEL_NAME: val->strval = "Fake Battery v" VERSION_STR; break; case POWER_SUPPLY_PROP_MANUFACTURER: val->strval = "Thin Air"; break; case POWER_SUPPLY_PROP_SERIAL_NUMBER: val->strval = "deadbeef"; break; default: return -EINVAL; } return 0; } static int __init fake_battery_init(void) { int ret; pr_debug("loading fake battery module\n"); // Initialize the power supply descriptor battery_desc.name = "fake-battery"; battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; battery_desc.properties = fake_battery_props; battery_desc.num_properties = ARRAY_SIZE(fake_battery_props); battery_desc.get_property = fake_battery_get_property; // Register the power supply fake_battery = power_supply_register(NULL, &battery_desc, NULL); if (IS_ERR(fake_battery)) { ret = PTR_ERR(fake_battery); pr_err("failed to register power supply: %d\n", ret); return ret; } pr_debug("fake battery registered successfully\n"); return 0; } static void __exit fake_battery_exit(void) { pr_debug("unloading fake battery module\n"); if (fake_battery) power_supply_unregister(fake_battery); } module_init(fake_battery_init); module_exit(fake_battery_exit); MODULE_AUTHOR("Vincent Schweiger"); MODULE_DESCRIPTION("Fake battery module that reports a fully charged battery"); MODULE_VERSION(VERSION_STR); MODULE_LICENSE("GPL");