2026-01-21 23:15:54 +08:00

765 lines
21 KiB
C

#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/string.h>
#include <linux/module.h> // 模块相关
#include <linux/slab.h>
#include <linux/kobject.h>
struct virtual_battery_data {
struct power_supply *psy;
int voltage_now;
int current_now;
int capacity;
int energy_full_design;
int energy_full;
int energy_now;
int status;
int temperature;
int online;
int power_now;
int charge_counter;
};
struct virtual_adapter_data {
struct power_supply *psy;
int online;
int type;
};
// 主数据结构,包含两个子结构
struct virtual_main_data {
struct virtual_battery_data battery_data;
struct virtual_adapter_data adapter_data;
};
static enum power_supply_property virtual_battery_props[] = {
POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
POWER_SUPPLY_PROP_ENERGY_FULL, POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_POWER_NOW,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
};
static enum power_supply_property virtual_adapter_props[] = {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_TYPE, // 类型为AC
};
//static struct power_supply *virtual_battery;
//static struct kobject *battery_kobj;
// Sysfs 属性操作
//static ssize_t charge_counter_show(struct kobject *kobj,
// struct kobj_attribute *attr, char *buf)
/*
static ssize_t charge_counter_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
return sprintf(buf, "%d\n", data->charge_counter);
}
static ssize_t charge_counter_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
int ret;
ret = kstrtouint(buf, 10, &data->charge_counter);
if (ret < 0)
return ret;
// 限制范围 0-100
data->charge_counter = clamp_val(data->charge_counter, 0, 24000000);
// 通知电源子系统更新
power_supply_changed(psy);
return count;
}
static ssize_t voltage_now_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
return sprintf(buf, "%d\n", data->voltage_now);
}
static ssize_t voltage_now_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
int ret;
ret = kstrtouint(buf, 10, &data->voltage_now);
if (ret < 0)
return ret;
// 限制范围 0-100
data->voltage_now = clamp_val(data->voltage_now, 0, 24000000);
data->power_now = (data->current_now * data->voltage_now)/1000000;
// 通知电源子系统更新
power_supply_changed(psy);
return count;
}
static ssize_t energy_now_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
return sprintf(buf, "%d\n", data->energy_now);
}
static ssize_t energy_now_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
int ret;
ret = kstrtouint(buf, 10, &data->energy_now);
if (ret < 0)
return ret;
// 限制范围 0-100
data->energy_now = clamp_val(data->energy_now, 0, 2000000000);
// 通知电源子系统更新
power_supply_changed(psy);
return count;
}
static ssize_t energy_full_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
return sprintf(buf, "%d\n", data->energy_full);
}
static ssize_t energy_full_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
int ret;
ret = kstrtouint(buf, 10, &data->energy_full);
if (ret < 0)
return ret;
// 限制范围 0-100
data->energy_full = clamp_val(data->energy_full, 0, 2000000000);
// 通知电源子系统更新
power_supply_changed(psy);
return count;
}
static ssize_t energy_full_design_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
return sprintf(buf, "%d\n", data->energy_full_design);
}
#if 0
static ssize_t energy_full_design_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_data *data = power_supply_get_drvdata(psy);
int ret;
ret = kstrtouint(buf, 10, &data->energy_full_design);
if (ret < 0)
return ret;
// 限制范围 0-100
data->energy_full_design =
clamp_val(data->energy_full_design, 0, 2000000000);
// 通知电源子系统更新
power_supply_changed(data);
return count;
}
#endif
static ssize_t current_now_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
return sprintf(buf, "%d\n", data->current_now);
}
static ssize_t current_now_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
int ret;
ret = kstrtouint(buf, 10, &data->current_now);
if (ret < 0)
return ret;
// 限制范围 0-100
data->current_now = clamp_val(data->current_now, 0, 3000000);
data->power_now = (data->current_now * data->voltage_now)/1000000;
// 通知电源子系统更新
power_supply_changed(psy);
return count;
}
static ssize_t capacity_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
return sprintf(buf, "%d\n", data->capacity);
}
static ssize_t capacity_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
int ret;
ret = kstrtouint(buf, 10, &data->capacity);
if (ret < 0)
return ret;
// 限制范围 0-100
data->capacity = clamp_val(data->capacity, 0, 100);
// 通知电源子系统更新
power_supply_changed(psy);
return count;
}
static ssize_t power_now_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
return sprintf(buf, "%d\n", data->power_now);
}
static ssize_t power_now_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_data *data = power_supply_get_drvdata(psy);
int ret;
ret = kstrtouint(buf, 10, &data->power_now);
if (ret < 0)
return ret;
// 限制范围 0-100
data->capacity = clamp_val(data->power_now, 0, 20000000);
// 通知电源子系统更新
power_supply_changed(data);
return count;
}
static ssize_t status_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
const char *status_str;
switch (data->status) {
case POWER_SUPPLY_STATUS_CHARGING:
status_str = "Charging";
break;
case POWER_SUPPLY_STATUS_DISCHARGING:
status_str = "Discharging";
break;
case POWER_SUPPLY_STATUS_FULL:
status_str = "Full";
break;
case POWER_SUPPLY_STATUS_NOT_CHARGING:
status_str = "Not Charging";
break;
default:
status_str = "Unknown";
}
return sprintf(buf, "%s\n", status_str);
}
static ssize_t status_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
if (sysfs_streq(buf, "Charging")) {
data->status = POWER_SUPPLY_STATUS_CHARGING;
} else if (sysfs_streq(buf, "Discharging")) {
data->status = POWER_SUPPLY_STATUS_DISCHARGING;
} else if (sysfs_streq(buf, "Full")) {
data->status = POWER_SUPPLY_STATUS_FULL;
} else if (sysfs_streq(buf, "Not Charging")) {
data->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
} else {
return -EINVAL;
}
power_supply_changed(psy);
return count;
}
*/
// 定义 sysfs 属性
/*
static struct kobj_attribute capacity_attr =
__ATTR(capacity, 0664, capacity_show, capacity_store);
static struct kobj_attribute status_attr =
__ATTR(status, 0664, status_show, status_store);
static struct kobj_attribute current_attr =
__ATTR(current_now, 0664, current_show, current_store);
static struct kobj_attribute energy_full_design_attr =
__ATTR(energy_full_design, 0664, energy_full_design_show,
energy_full_design_store);
static struct kobj_attribute energy_full_attr =
__ATTR(energy_full, 0664, energy_full_show, energy_full_store);
static struct kobj_attribute energy_attr =
__ATTR(energy_now, 0664, energy_show, energy_store);
static struct kobj_attribute voltage_attr =
__ATTR(voltage, 0664, voltage_show, voltage_store);
static struct kobj_attribute charge_counter_attr =
__ATTR(charge_counter, 0664, charge_counter_show, charge_counter_store);
static struct attribute *battery_attrs[] = {
&capacity_attr.attr,
&status_attr.attr,
&current_attr.attr,
&energy_full_design_attr.attr,
&energy_full_attr.attr,
&energy_attr.attr,
&voltage_attr.attr,
&charge_counter_attr.attr,
NULL,
};
static struct attribute_group battery_attr_group = {
.attrs = battery_attrs,
};
static DEVICE_ATTR_RW(capacity);
static DEVICE_ATTR_RW(status);
static DEVICE_ATTR_RW(current_now);
static DEVICE_ATTR_RW(voltage_now);
static DEVICE_ATTR_RO(energy_full_design);
static DEVICE_ATTR_RW(energy_full);
static DEVICE_ATTR_RW(energy_now);
static DEVICE_ATTR_RW(charge_counter);
static DEVICE_ATTR_RO(power_now);
static struct attribute *virtual_battery_attrs[] = {
&dev_attr_capacity.attr,
&dev_attr_status.attr,
&dev_attr_current_now.attr,
&dev_attr_voltage_now.attr,
&dev_attr_energy_full_design.attr,
&dev_attr_energy_full.attr,
&dev_attr_energy_now.attr,
&dev_attr_charge_counter.attr,
&dev_attr_power_now.attr,
NULL,
};
ATTRIBUTE_GROUPS(virtual_battery);
// 导出到用户空间的sysfs接口
static ssize_t online_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_adapter_data *data = power_supply_get_drvdata(psy);
int online;
if (kstrtoint(buf, 10, &online))
return -EINVAL;
data->online = !!online;
power_supply_changed(psy);
return count;
}
static ssize_t online_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct virtual_adapter_data *data = power_supply_get_drvdata(psy);
return sprintf(buf, "%d\n", data->online);
}
static DEVICE_ATTR_RW(online);
static struct attribute *virtual_adapter_attrs[] = {
&dev_attr_online.attr,
NULL,
};
ATTRIBUTE_GROUPS(virtual_adapter);
*/
static int virtual_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = data->voltage_now;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
if (data->status == POWER_SUPPLY_STATUS_CHARGING)
val->intval = data->current_now;
else {
val->intval = -(data->current_now);
}
break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = data->capacity;
break;
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
val->intval = data->energy_full_design;
break;
case POWER_SUPPLY_PROP_ENERGY_FULL:
val->intval = data->energy_full;
break;
case POWER_SUPPLY_PROP_ENERGY_NOW:
val->intval = data->capacity/100*data->energy_full;
break;
case POWER_SUPPLY_PROP_STATUS:
val->intval = data->status;
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval = data->temperature * 10; // 内核温度单位为 0.1°C
break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
val->intval = data->charge_counter;
break;
case POWER_SUPPLY_PROP_HEALTH:
val->intval = POWER_SUPPLY_HEALTH_GOOD;
break;
case POWER_SUPPLY_PROP_POWER_NOW:
val->intval = data->power_now;
break;
default:
return -EINVAL;
}
return 0;
}
static int virtual_battery_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct virtual_battery_data *data = power_supply_get_drvdata(psy);
int64_t power;
switch (psp) {
case POWER_SUPPLY_PROP_CAPACITY:
// 验证值范围
if (val->intval < 0 || val->intval > 100) {
dev_err(&psy->dev, "Invalid capacity value: %d\n",
val->intval);
return -EINVAL;
}
data->capacity = val->intval;
break;
case POWER_SUPPLY_PROP_STATUS:
if (val->intval < POWER_SUPPLY_STATUS_UNKNOWN ||
val->intval > POWER_SUPPLY_STATUS_FULL) {
dev_err(&psy->dev, "Invalid status value: %d\n",
val->intval);
return -EINVAL;
}
data->status = val->intval;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
// 验证电压值(单位:微伏)
if (val->intval < 0 || val->intval > 13000000) { // 0-13V
dev_err(&psy->dev, "Invalid voltage: %d µV\n",
val->intval);
return -EINVAL;
}
data->voltage_now = val->intval;
power = (int64_t)data->voltage_now * abs(data->current_now);
data->power_now = (int)(power / 1000000);
dev_dbg(
&psy->dev,
"voltage_now: %d µV,current: %d µA,power:%lld,power_now:%d\n",
data->voltage_now, data->current_now, power,
data->power_now);
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
// 电流可以是正(充电)或负(放电)
if (val->intval < -5000000 ||
val->intval > 5000000) { // -5A to 5A
dev_err(&psy->dev, "Invalid current: %d µA\n",
val->intval);
return -EINVAL;
}
data->current_now = val->intval;
power = (int64_t)data->voltage_now * abs(data->current_now);
data->power_now = (int)(power / 1000000);
dev_dbg(
&psy->dev,
"voltage_now: %d µV,current: %d µA,power:%lld,power_now:%d\n",
data->voltage_now, data->current_now, power,
data->power_now);
break;
case POWER_SUPPLY_PROP_TEMP:
// 温度单位是 0.1°C
if (val->intval < -200 ||
val->intval > 1000) { // -20°C 到 100°C
return -EINVAL;
}
data->temperature = val->intval;
break;
case POWER_SUPPLY_PROP_ENERGY_NOW:
if (val->intval < 0) {
dev_err(&psy->dev, "Invalid energy: %d µWh\n",
val->intval);
return -EINVAL;
}
data->energy_now = val->intval;
break;
default:
// 对于不支持写的属性返回错误
dev_dbg(&psy->dev, "Property %d is read-only\n", psp);
return -EINVAL;
}
// 通知属性已更改
power_supply_changed(psy);
return 0;
}
static int virtual_battery_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
// 指定哪些属性可写
switch (psp) {
case POWER_SUPPLY_PROP_CAPACITY:
case POWER_SUPPLY_PROP_STATUS:
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
case POWER_SUPPLY_PROP_CURRENT_NOW:
case POWER_SUPPLY_PROP_ENERGY_NOW:
case POWER_SUPPLY_PROP_TEMP:
return 1; // 可写
default:
return 0; // 只读
}
}
static int virtual_adapter_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct virtual_adapter_data *data = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
val->intval = data->online;
break;
case POWER_SUPPLY_PROP_TYPE:
val->intval = POWER_SUPPLY_TYPE_MAINS; // 交流电源
break;
default:
return -EINVAL;
}
return 0;
}
static int virtual_adapter_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct virtual_adapter_data *data = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
data->online = val->intval ? 1 : 0;
break;
default:
dev_dbg(&psy->dev, "Adapter property %d is read-only\n", psp);
return -EINVAL;
}
// 通知适配器状态变化
power_supply_changed(psy);
return 0;
}
static int virtual_adapter_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
// 指定哪些属性可写
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
return 1; // 可写
default:
return 0; // 只读
}
}
static const struct power_supply_desc virtual_battery_desc = {
.name = "virtual_battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = virtual_battery_props,
.num_properties = ARRAY_SIZE(virtual_battery_props),
.get_property = virtual_battery_get_property,
.set_property = virtual_battery_set_property,
.property_is_writeable = virtual_battery_property_is_writeable,
};
static const struct power_supply_desc virtual_adapter_desc = {
.name = "virtual_adapter",
.type = POWER_SUPPLY_TYPE_MAINS,
.properties = virtual_adapter_props,
.num_properties = ARRAY_SIZE(virtual_adapter_props),
.get_property = virtual_adapter_get_property,
.set_property = virtual_adapter_set_property,
.property_is_writeable = virtual_adapter_property_is_writeable,
};
static int virtual_battery_probe(struct platform_device *pdev)
{
struct virtual_main_data *main_data;
struct power_supply_config psy_cfg = {};
main_data = devm_kzalloc(&pdev->dev, sizeof(*main_data), GFP_KERNEL);
if (!main_data)
return -ENOMEM;
of_property_read_u32(pdev->dev.of_node, "temperature-celsius",
&main_data->battery_data.temperature);
of_property_read_u32(pdev->dev.of_node,
"energy-full-design-microwatt-hours",
&main_data->battery_data.energy_full_design);
of_property_read_u32(pdev->dev.of_node,
"energy-full-microwatt-hours",
&main_data->battery_data.energy_full);
of_property_read_u32(pdev->dev.of_node, "capacity-now",
&main_data->battery_data.capacity);
main_data->battery_data.charge_counter = 0;
main_data->battery_data.current_now = 0;
main_data->battery_data.voltage_now = 12600000;
main_data->battery_data.energy_now = 15000000;
main_data->battery_data.power_now = 0;
main_data->battery_data.status = POWER_SUPPLY_STATUS_DISCHARGING;
psy_cfg.drv_data = &main_data->battery_data;
//psy_cfg.attr_grp = virtual_battery_groups;
main_data->battery_data.psy = devm_power_supply_register(
&pdev->dev, &virtual_battery_desc, &psy_cfg);
if (IS_ERR(main_data->battery_data.psy)) {
dev_err(&pdev->dev,
"Failed to register battery power supply\n");
return PTR_ERR(main_data->battery_data.psy);
}
main_data->adapter_data.online = 0;
psy_cfg.drv_data = &main_data->adapter_data;
//psy_cfg.attr_grp = virtual_adapter_groups;
main_data->adapter_data.psy = devm_power_supply_register(
&pdev->dev, &virtual_adapter_desc, &psy_cfg);
if (IS_ERR(main_data->adapter_data.psy)) {
dev_err(&pdev->dev,
"Failed to register adapter power supply\n");
return PTR_ERR(main_data->adapter_data.psy);
}
platform_set_drvdata(pdev, main_data);
/*
// 创建 sysfs 接口
battery_kobj =
kobject_create_and_add("virtual_battery", kernel_kobj->parent);
if (!battery_kobj) {
power_supply_unregister(virtual_battery);
return -ENOMEM;
}
ret = sysfs_create_group(battery_kobj, &battery_attr_group);
if (ret) {
kobject_put(battery_kobj);
power_supply_unregister(virtual_battery);
}
*/
dev_info(&pdev->dev, "Virtual battery probed successfully\n");
return 0;
}
static int virtual_battery_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "Virtual battery removed\n");
//sysfs_remove_group(battery_kobj, &battery_attr_group);
//kobject_put(battery_kobj);
return 0;
}
static const struct of_device_id virtual_battery_of_match[] = {
{ .compatible = "my-vendor,virtual-battery" },
{},
};
MODULE_DEVICE_TABLE(of, virtual_battery_of_match);
static struct platform_driver virtual_battery_driver = {
.probe = virtual_battery_probe,
.remove = virtual_battery_remove,
.driver = {
.name = "virtual_battery",
.of_match_table = virtual_battery_of_match,
},
};
module_platform_driver(virtual_battery_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ardu");
MODULE_DESCRIPTION("Virtual Battery Driver");
MODULE_VERSION("1.0");