power_supply_register注册举例:
/kernel-4.19-lc/drivers/power/supply/mediatek/battery_common.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
struct ac_data { struct power_supply_desc psd; struct power_supply *psy; int AC_ONLINE; }; struct usb_data { struct power_supply_desc psd; struct power_supply *psy; int USB_ONLINE; }; struct battery_data { struct power_supply_desc psd; struct power_supply *psy; int BAT_STATUS; int BAT_HEALTH; int BAT_PRESENT; int BAT_TECHNOLOGY; int BAT_CAPACITY; /* Add for Battery Service */ int BAT_batt_vol; int BAT_batt_temp; int BAT_CURRENT_NOW; }; |
\kernel-4.19-lc\drivers\power\supply\mediatek\battery_common.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
static enum power_supply_property ac_props[] = { POWER_SUPPLY_PROP_ONLINE, }; static enum power_supply_property usb_props[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_CHARGE_COUNTER }; static enum power_supply_property battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CAPACITY, /*charging current*/ POWER_SUPPLY_PROP_CURRENT_NOW, /*battery voltage*/ POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_CURRENT_AVG, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_COUNTER, /*bettery temperature*/ POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN }; /* ac_data initialization */ static struct ac_data ac_main = { .psd = { .name = "ac", .type = POWER_SUPPLY_TYPE_MAINS, .properties = ac_props, .num_properties = ARRAY_SIZE(ac_props), .get_property = ac_get_property, }, .AC_ONLINE = 0, }; /* usb_data initialization */ static struct usb_data usb_main = { .psd = { .name = "usb", .type = POWER_SUPPLY_TYPE_USB, .properties = usb_props, .num_properties = ARRAY_SIZE(usb_props), .get_property = usb_get_property, }, .USB_ONLINE = 0, }; /* battery_data initialization */ static struct battery_data battery_main = { .psd = { .name = "battery", .type = POWER_SUPPLY_TYPE_BATTERY, .properties = battery_props, .num_properties = ARRAY_SIZE(battery_props), .get_property = battery_get_property, }, .BAT_STATUS = POWER_SUPPLY_STATUS_DISCHARGING, .BAT_HEALTH = POWER_SUPPLY_HEALTH_GOOD, .BAT_PRESENT = 1, .BAT_TECHNOLOGY = POWER_SUPPLY_TECHNOLOGY_LION, .BAT_CAPACITY = 50, .BAT_batt_vol = 0, .BAT_batt_temp = 0, }; |
\kernel-4.19-lc\drivers\power\supply\mediatek\battery_common.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
static int battery_probe(struct platform_device *dev) { ... ... ac_main.psy = power_supply_register(&(dev->dev), &ac_main.psd, NULL); usb_main.psy = power_supply_register(&(dev->dev), &usb_main.psd, NULL); battery_main.psy = power_supply_register(&(dev->dev), &battery_main.psd, NULL); if (IS_ERR(battery_main.psy)) { battery_log(BAT_LOG_CRTI, "[BAT_probe] power_supply_register Battery Fail !!\n"); return ret; } ... ... } |
====================================================================================================
power_supply_register注册流程详解:
/kernel-4.19-lc/drivers/power/supply/power_supply_core.c
1 2 3 4 5 6 7 8 9 10 |
static struct power_supply *__must_check __power_supply_register(struct device *parent, const struct power_supply_desc *desc, const struct power_supply_config *cfg, bool ws) struct device *dev; struct power_supply *psy; dev->class = power_supply_class; ... ... INIT_WORK(&psy->changed_work, power_supply_changed_work); INIT_DELAYED_WORK(&psy->deferred_register_work, power_supply_deferred_register_work); rc = device_add(dev); ... ... } |
/kernel-4.14/drivers/power/supply/power_supply_sysfs.c
#define POWER_SUPPLY_ATTR(_name) \
{ \
.attr = { .name = #_name }, \
.show = power_supply_show_property, \
.store = power_supply_store_property, \
}
/kernel-4.14/drivers/power/supply/power_supply_sysfs.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
/* Must be in the same order as POWER_SUPPLY_PROP_* */ static struct device_attribute power_supply_attrs[] = { /* Properties of type `int' */ POWER_SUPPLY_ATTR(status), POWER_SUPPLY_ATTR(charge_type), POWER_SUPPLY_ATTR(health), POWER_SUPPLY_ATTR(present), POWER_SUPPLY_ATTR(online), POWER_SUPPLY_ATTR(authentic), POWER_SUPPLY_ATTR(technology), POWER_SUPPLY_ATTR(cycle_count), POWER_SUPPLY_ATTR(voltage_max), POWER_SUPPLY_ATTR(voltage_min), POWER_SUPPLY_ATTR(voltage_max_design), POWER_SUPPLY_ATTR(voltage_min_design), POWER_SUPPLY_ATTR(voltage_now), POWER_SUPPLY_ATTR(voltage_avg), POWER_SUPPLY_ATTR(voltage_ocv), POWER_SUPPLY_ATTR(voltage_boot), POWER_SUPPLY_ATTR(current_max), POWER_SUPPLY_ATTR(current_now), POWER_SUPPLY_ATTR(current_avg), POWER_SUPPLY_ATTR(current_boot), POWER_SUPPLY_ATTR(power_now), POWER_SUPPLY_ATTR(power_avg), POWER_SUPPLY_ATTR(charge_full_design), POWER_SUPPLY_ATTR(charge_empty_design), POWER_SUPPLY_ATTR(charge_full), POWER_SUPPLY_ATTR(charge_empty), POWER_SUPPLY_ATTR(charge_now), POWER_SUPPLY_ATTR(charge_avg), POWER_SUPPLY_ATTR(charge_counter), POWER_SUPPLY_ATTR(constant_charge_current), POWER_SUPPLY_ATTR(constant_charge_current_max), POWER_SUPPLY_ATTR(constant_charge_voltage), POWER_SUPPLY_ATTR(constant_charge_voltage_max), POWER_SUPPLY_ATTR(charge_control_limit), POWER_SUPPLY_ATTR(charge_control_limit_max), POWER_SUPPLY_ATTR(input_current_limit), POWER_SUPPLY_ATTR(energy_full_design), POWER_SUPPLY_ATTR(energy_empty_design), POWER_SUPPLY_ATTR(energy_full), POWER_SUPPLY_ATTR(energy_empty), POWER_SUPPLY_ATTR(energy_now), POWER_SUPPLY_ATTR(energy_avg), POWER_SUPPLY_ATTR(capacity), POWER_SUPPLY_ATTR(capacity_alert_min), POWER_SUPPLY_ATTR(capacity_alert_max), POWER_SUPPLY_ATTR(capacity_level), POWER_SUPPLY_ATTR(temp), POWER_SUPPLY_ATTR(temp_max), POWER_SUPPLY_ATTR(temp_min), POWER_SUPPLY_ATTR(temp_alert_min), POWER_SUPPLY_ATTR(temp_alert_max), POWER_SUPPLY_ATTR(temp_ambient), POWER_SUPPLY_ATTR(temp_ambient_alert_min), POWER_SUPPLY_ATTR(temp_ambient_alert_max), POWER_SUPPLY_ATTR(time_to_empty_now), POWER_SUPPLY_ATTR(time_to_empty_avg), POWER_SUPPLY_ATTR(time_to_full_now), POWER_SUPPLY_ATTR(time_to_full_avg), POWER_SUPPLY_ATTR(type), POWER_SUPPLY_ATTR(scope), POWER_SUPPLY_ATTR(precharge_current), POWER_SUPPLY_ATTR(charge_term_current), POWER_SUPPLY_ATTR(calibrate), /* Local extensions */ POWER_SUPPLY_ATTR(usb_hc), POWER_SUPPLY_ATTR(usb_otg), POWER_SUPPLY_ATTR(charge_enabled), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ POWER_SUPPLY_ATTR(model_name), POWER_SUPPLY_ATTR(manufacturer), POWER_SUPPLY_ATTR(serial_number), }; |
struct device_attribute power_supply_attrs[]和enum power_supply_property 一一对应,
power_supply_register会根据具体的properties(比如enum power_supply_property battery_props)创建对应的attrs
batterymonitor.cpp读取对应的节点时,会调用power_supply_show_property(struct device *dev, struct device_attribute *attr, char *buf)
形参struct device_attribute *attr就是对应property(比如POWER_SUPPLY_PROP_STATUS)所对应的指针,
enum power_supply_property psp = attr - power_supply_attrs; //计算指针的偏移,得出是第几个property,battery_common.c中的battery_get_property()可以依此执行不同的case
/kernel-4.19-lc/include/linux/power_supply.h
enum power_supply_property {
/* Properties of type `int' */
POWER_SUPPLY_PROP_STATUS = 0,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_AUTHENTIC,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MIN,
... ...
};
/kernel-4.19-lc/drivers/power/supply/power_supply_sysfs.c
static struct attribute_group power_supply_attr_group = {
.attrs = __power_supply_attrs, //struct attribute **attrs;
.is_visible = power_supply_attr_is_visible, //umode_t (*is_visible)(struct kobject *, struct attribute *, int);
};
static const struct attribute_group *power_supply_attr_groups[] = {
&power_supply_attr_group,
NULL,
};
/kernel-4.19-lc/drivers/power/supply/power_supply_core.c
static int __init power_supply_class_init(void) { power_supply_class = class_create(THIS_MODULE, "power_supply"); power_supply_class->dev_uevent = power_supply_uevent; power_supply_init_attrs(&power_supply_dev_type);
->dev_type->groups = power_supply_attr_groups; //定义了所有属性的power_supply_*
->for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
->__power_supply_attrs[i] = &power_supply_attrs[i].attr;
return 0;
}
/kernel-4.19-lc/drivers/base/core.c
static const struct kset_uevent_ops device_uevent_ops = {
.filter = dev_uevent_filter,
.name = dev_uevent_name,
.uevent = dev_uevent,
};
struct power_supply *__must_check power_supply_register(struct device *parent, const struct power_supply_desc *desc, const struct power_supply_config *cfg)
static struct power_supply *__must_check __power_supply_register(struct device *parent, const struct power_supply_desc *desc, const struct power_supply_config *cfg, bool ws)
->struct power_supply *psy;
->psy = kzalloc(sizeof(*psy), GFP_KERNEL);
->dev = &psy->dev;
->device_initialize(dev);
->dev->class = power_supply_class;
->dev->type = &power_supply_dev_type;
->dev->parent = parent;
->dev->release = power_supply_dev_release;
->dev_set_drvdata(dev, psy);
->dev->driver_data = data; //psy
->psy->desc = desc;
->device_add(dev);
->device_create_file(dev, &dev_attr_uevent);
->device_add_attrs(dev);
->struct class *class = dev->class;
->const struct device_type *type = dev->type;
->if (class) {
->device_add_groups(dev, class->dev_groups);
->sysfs_create_groups(&dev->kobj, groups);
->if (!groups) //power_supply_class->groups 为空,所以直接return
return 0;
->if (type) {
->device_add_groups(dev, type->groups); //power_supply_dev_type->groups
->sysfs_create_groups(&dev->kobj, groups); //power_supply_attr_groups
->for (i = 0; groups[i]; i++) { //只有1个
->sysfs_create_group(kobj, groups[i]);
->internal_create_group(kobj, 0, grp);
->create_files(kn, kobj, uid, gid, grp, update);
->if (grp->attrs) {
->for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { //power_supply_attrs
->umode_t mode = (*attr)->mode; //遍历power_supply_attrs中的i
->mode = grp->is_visible(kobj, *attr, i); //attr没有用
->struct device *dev = container_of(kobj, struct device, kobj);
->struct power_supply *psy = dev_get_drvdata(dev);
->for (i = 0; i < psy->desc->num_properties; i++) { //查找具体的psy中是否存在枚举i
->int property = psy->desc->properties[i];
->if (property == attrno) { //i
->return mode;
->if (!mode) //如果不存在,则调过
continue;
->sysfs_create_file_ns(kobj, attr, NULL); //如果存在,则创建相应的sysfs
->device_add_groups(dev, dev->groups);
device_add最终会跑到create_files,到sys对应的目录下创建文件
dev->class = power_supply_class;
device属于power_supply_class下的设备,遍历grp里的所有属性,如果device的属性is_visible(能返回匹配的属性枚举mode),便调用sysfs_add_file_mode_ns()创建相应的sysfs文件
/kernel-4.19-lc/fs/sysfs/group.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
static int create_files(struct kernfs_node *parent, struct kobject *kobj, kuid_t uid, kgid_t gid, const struct attribute_group *grp, int update) { struct attribute *const *attr; struct bin_attribute *const *bin_attr; int error = 0, i; if (grp->attrs) { for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { umode_t mode = (*attr)->mode; /* * In update mode, we're changing the permissions or * visibility. Do this by first removing then * re-adding (if required) the file. */ if (update) kernfs_remove_by_name(parent, (*attr)->name); if (grp->is_visible) { mode = grp->is_visible(kobj, *attr, i); if (!mode) continue; } WARN(mode & ~(SYSFS_PREALLOC | 0664), "Attribute %s: Invalid permissions 0%o\n", (*attr)->name, mode); mode &= SYSFS_PREALLOC | 0664; error = sysfs_add_file_mode_ns(parent, *attr, false, mode, uid, gid, NULL); if (unlikely(error)) break; } if (error) { remove_files(parent, grp); goto exit; } } if (grp->bin_attrs) { for (i = 0, bin_attr = grp->bin_attrs; *bin_attr; i++, bin_attr++) { umode_t mode = (*bin_attr)->attr.mode; if (update) kernfs_remove_by_name(parent, (*bin_attr)->attr.name); if (grp->is_bin_visible) { mode = grp->is_bin_visible(kobj, *bin_attr, i); if (!mode) continue; } WARN(mode & ~(SYSFS_PREALLOC | 0664), "Attribute %s: Invalid permissions 0%o\n", (*bin_attr)->attr.name, mode); mode &= SYSFS_PREALLOC | 0664; error = sysfs_add_file_mode_ns(parent, &(*bin_attr)->attr, true, mode, uid, gid, NULL); if (error) break; } if (error) remove_files(parent, grp); } exit: return error; } |