power_supply_changed


 
/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
(220106_16:10:50.967)[    4.560314] <3>.(3)[64:kworker/3:1]Isaac [battery_get_property] enter
(220106_16:10:50.967)[    4.561125] <3>-(3)[64:kworker/3:1]CPU: 3 PID: 64 Comm: kworker/3:1 Not tainted 4.19.127 #5
(220106_16:10:50.967)[    4.562161] <3>-(3)[64:kworker/3:1]Hardware name: Generic DT based system
(220106_16:10:50.967)[    4.563015] <3>-(3)[64:kworker/3:1]Workqueue: events power_supply_changed_work
(220106_16:10:50.967)[    4.563913] <3>-(3)[64:kworker/3:1]Backtrace:
(220106_16:10:50.967)[    4.564476] <3>-(3)[64:kworker/3:1][<c010ca98>] (dump_backtrace) from [<c010ca94>] (show_stack+0x14/0x18)
(220106_16:10:50.968)[    4.565665] <3>-(3)[64:kworker/3:1] r10:c4140420 r6:0000001c r5:c13ced60 r4:60000013
(220106_16:10:50.968)[    4.566634] <3>-(3)[64:kworker/3:1][<c010ca80>] (show_stack) from [<c0d7ac14>] (dump_stack+0x8c/0xb8)
(220106_16:10:50.968)[    4.567783] <3>-(3)[64:kworker/3:1][<c0d7ab88>] (dump_stack) from [<c09446f0>] (battery_get_property+0x24/0x238)
(220106_16:10:50.968)[    4.569060] <3>-(3)[64:kworker/3:1] r5:c4140420 r4:e4f11e58
                                                    return psy->desc->get_property(psy, psp, val);
(220106_16:10:50.968)[    4.569761] <3>-(3)[64:kworker/3:1][<c09446f0>] (battery_get_property) from [<c093c744>] (power_supply_get_property+0x20/0x38)
(220106_16:10:50.968)[    4.571180] <3>-(3)[64:kworker/3:1][<c093c724>] (power_supply_get_property) from [<c093d724>] (power_supply_show_property+0xa0/0x348)
(220106_16:10:50.968)[    4.572689] <3>-(3)[64:kworker/3:1][<c093d684>] (power_supply_show_property) from [<c093d558>] (power_supply_uevent+0xc4/0x1f0)
                                          dev->bus->uevent(dev, env)/dev->class->dev_uevent(dev, env);/dev->type->uevent(dev, env)
(220106_16:10:50.968)[    4.574118] <3>-(3)[64:kworker/3:1] r10:00000000 r9:c4140400 r8:c4146000 r7:c139e1f8 r6:0000000a r5:c4140420
(220106_16:10:50.968)[    4.575341] <3>-(3)[64:kworker/3:1] r4:c0f4abf8                    struct device *dev = kobj_to_dev(kobj);
(220106_16:10:50.968)[    4.575922] <3>-(3)[64:kworker/3:1][<c093d558>] (power_supply_uevent) from [<c06148d0>] (dev_uevent+0x1a0/0x1d8)
                                                   uevent_ops->uevent(kset, kobj, env);
(220106_16:10:50.968)[    4.577204] <3>-(3)[64:kworker/3:1][<c06148d0>] (dev_uevent) from [<c0d811e0>] (kobject_uevent_env+0x340/0x578)
(220106_16:10:50.968)[    4.578477] <3>-(3)[64:kworker/3:1][<c0d80ea0>] (kobject_uevent_env) from [<c0d81524>] (kobject_uevent+0x10/0x14) return kobject_uevent_env(kobj, action, NULL);
(220106_16:10:50.968)[    4.579761] <3>-(3)[64:kworker/3:1] r10:00000000 r9:e5ede000 r8:e5ed9bc0 r7:c4140400 r6:80000013 r5:c4140660
(220106_16:10:50.968)[    4.580990] <3>-(3)[64:kworker/3:1] r4:c41406e0
(220106_16:10:50.968)[    4.581558] <3>-(3)[64:kworker/3:1][<c0d81514>] (kobject_uevent) from [<c093d0e8>] (power_supply_changed_work+0x88/0xb8)
(220106_16:10:50.968)[    4.582914] <3>-(3)[64:kworker/3:1][<c093d0e8>] (power_supply_changed_work) from [<c0146ad0>] (process_one_work+0x24c/0x510)
(220106_16:10:50.968)[    4.584310] <3>-(3)[64:kworker/3:1][<c0146884>] (process_one_work) from [<c01470bc>] (worker_thread+0x2cc/0x55c)
(220106_16:10:51.041)[    4.585579] <3>-(3)[64:kworker/3:1] r10:e5ed9bc0 r9:e5ed9bd8 r8:c131a200 r7:00000008 r6:e4e95494 r5:e5ed9bc0
(220106_16:10:51.068)[    4.586810] <3>-(3)[64:kworker/3:1] r4:e4e95480       //kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread")->BAT_thread()->battery_update()->power_supply_change(struct power_supply *)
(220106_16:10:51.068)[    4.587378] <3>-(3)[64:kworker/3:1][<c01470bc>] (worker_thread) from [<c014b8e4>] (kthread+0x160/0x164)
(220106_16:10:51.068)[    4.588562] <3>-(3)[64:kworker/3:1][<c014b8e4>] (kthread) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
(220106_16:10:51.068)[    4.589708] <3>-(3)[64:kworker/3:1]Exception stack(0xe4f11f9c to 0xe4f11fe4)
(220106_16:10:51.068)[    4.590586] <3>-(3)[64:kworker/3:1]1f80:                                                                c014b8e4
(220106_16:10:51.068)[    4.591858] <3>-(3)[64:kworker/3:1]1fa0: 00000000 c0146df0 00000000 c01010e8 00000000 00000000 00000000 00000000
(220106_16:10:51.068)[    4.593126] <3>-(3)[64:kworker/3:1]1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
(220106_16:10:51.068)[    4.594403] <3>-(3)[64:kworker/3:1]1fe0: 00000000
/kernel-4.19-lc/include/linux/kobject.h
struct kobj_uevent_env {
	char *argv[3];
	char *envp[UEVENT_NUM_ENVP];
	int envp_idx;
	char buf[UEVENT_BUFFER_SIZE];
	int buflen;
};
/kernel-4.19-lc/lib/kobject_uevent.c
#ifdef CONFIG_NET
static LIST_HEAD(uevent_sock_list);
#endif
/kernel-4.19-lc/include/linux/types.h
 
   
struct list_head {  struct list_head *next, *prev; };
展开就是 struct list_head uevent_sock_list = { &(uevent_sock_list), &(uevent_sock_list) }
从dump_stack()可以看出,驱动调用power_supply_changed(struct power_supply *)通知用户空间:
kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[])
 ->struct kobj_uevent_env *env;
 ->const char *action_string = kobject_actions[action];
 ->uevent_ops->uevent(kset, kobj, env);
  ->dev_uevent
   ->dev->class->dev_uevent(dev, env)
    ->power_supply_uevent
     ->char *prop_buf;
     ->add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->desc->name); //"battery"/"ac"/"usb"
     ->for (j = 0; j < psy->desc->num_properties; j++) {
      ->attr = &power_supply_attrs[psy->desc->properties[j]];
      ->power_supply_show_property(dev, attr, prop_buf);
       ->union power_supply_propval value;
       ->power_supply_get_property(psy, psp, &value);
        ->psy->desc->get_property(psy, psp, val);
         ->battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
      ->add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); //将环境变量copy到env指针中
       ->va_start(args, format);
       ->len = vsnprintf(&env->buf[env->buflen], sizeof(env->buf) - env->buflen, format, args); //将字符串保存在env->buf[]中
       ->va_end(args);
  /* we will send an event, so request a new sequence number */
 ->add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum); //增加uevent发送的计数
 ->kobject_uevent_net_broadcast(kobj, env, action_string, devpath);
  ->uevent_net_broadcast_untagged(env, action_string, devpath);
   ->struct sk_buff *skb = NULL;
   ->struct uevent_sock *ue_sk;
   /* send netlink message */
   ->list_for_each_entry(ue_sk, &uevent_sock_list, list) {
    ->struct sock *uevent_sock = ue_sk->sk;
    ->if (!netlink_has_listeners(uevent_sock, 1))
     ->continue;
    ->skb = alloc_uevent_skb(env, action_string, devpath); //分配网络缓存
     ->skb_put_data(skb, env->buf, env->buflen);  //将env->buf[]的数据copy到skb
    ->netlink_broadcast(uevent_sock, skb_get(skb), 0, 1,  GFP_KERNEL); //发送uevent到userspace
     ->netlink_broadcast_filtered(ssk, skb, portid, group, allocation, NULL, NULL);
 /kernel-4.19-lc/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
int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
{
    struct power_supply *psy = dev_get_drvdata(dev);
    int ret = 0, j;
    char *prop_buf;
    char *attrname;

    if (!psy || !psy->desc) {
        dev_dbg(dev, "No power supply yet\n");
        return ret;
    }

    ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->desc->name);
    if (ret)
        return ret;

    prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
    if (!prop_buf)
        return -ENOMEM;

    for (j = 0; j < psy->desc->num_properties; j++) {
        struct device_attribute *attr;
        char *line;
                                                                    //power_supply_attrs[]保存着所有的attr
        attr = &power_supply_attrs[psy->desc->properties[j]];  //每个属性所对应的struct device_attribute

        if (!attr->attr.name) {
            dev_info(dev, "%s:%d FAKE attr.name=NULL skip\n",
                __FILE__, __LINE__);
            continue;
        }

        ret = power_supply_show_property(dev, attr, prop_buf);
        if (ret == -ENODEV || ret == -ENODATA) {
            /* When a battery is absent, we expect -ENODEV. Don't abort;
               send the uevent with at least the the PRESENT=0 property */

            ret = 0;
            continue;
        }

        if (ret < 0)
            goto out;

        line = strchr(prop_buf'\n');
        if (line)
            *line = 0;

        attrname = kstruprdup(attr->attr.name, GFP_KERNEL);  //把属性名字转成大写,比如"status"->"STATUS"
        if (!attrname) {
            ret = -ENOMEM;
            goto out;
        }
        //以格式化字符的形式,将环境变量copy到env指针中,adb cat /sys/class/power_supply/battery/uevent就能看到
        ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s"attrnameprop_buf);
        kfree(attrname);  //kstruprdup会调用kmalloc,所以需要搭配free使用
        if (ret)
            goto out;
    }
out:
    free_page((unsigned long)prop_buf);
    return ret;
}
/kernel-4.19-lc/include/linux/power_supply.h
 
  
union power_supply_propval {  int intval;  const char *strval;  int64_t int64val; };
/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, \ } static struct device_attribute power_supply_attrs[];  static const char * const power_supply_type_text[] = { "Unknown", "Battery", "UPS", "Mains", "USB", "USB_DCP", "USB_CDP", "USB_ACA", "USB_C", "USB_PD", "USB_PD_DRP", "BrickID", "USB_HVDCP", "USB_HVDCP_3", "USB_HVDCP_3P5", "Wireless", "USB_FLOAT", "BMS", "Parallel", "Main", "USB_C_UFP", "USB_C_DFP", "Charge_Pump", }; static const char * const power_supply_usb_type_text[] = { "Unknown", "SDP", "DCP", "CDP", "ACA", "C", "PD", "PD_DRP", "PD_PPS", "BrickID" }; static const char * const power_supply_status_text[] = { "Unknown", "Charging", "Discharging", "Not charging", "Full" }; static const char * const power_supply_charge_type_text[] = { "Unknown", "N/A", "Trickle", "Fast", "Taper" }; static const char * const power_supply_health_text[] = { "Unknown", "Good", "Overheat", "Dead", "Over voltage", "Unspecified failure", "Cold", "Watchdog timer expire", "Safety timer expire", "Over current", "Warm", "Cool", "Hot" }; static const char * const power_supply_technology_text[] = { "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd", "LiMn" }; static const char * const power_supply_capacity_level_text[] = { "Unknown", "Critical", "Low", "Normal", "High", "Full" }; static const char * const power_supply_scope_text[] = { "Unknown", "System", "Device" }; static const char * const power_supply_usbc_text[] = { "Nothing attached", "Sink attached", "Powered cable w/ sink", "Debug Accessory", "Audio Adapter", "Powered cable w/o sink", "Source attached (default current)", "Source attached (medium current)", "Source attached (high current)", "Debug Accessory Mode (default current)", "Debug Accessory Mode (medium current)", "Debug Accessory Mode (high current)", "Non compliant", "Non compliant (Rp-Default/Rp-Default)", "Non compliant (Rp-1.5A/Rp-1.5A)", "Non compliant (Rp-3A/Rp-3A)" }; static const char * const power_supply_usbc_pr_text[] = { "none", "dual power role", "sink", "source" }; static const char * const power_supply_typec_src_rp_text[] = { "Rp-Default", "Rp-1.5A", "Rp-3A" };
/kernel-4.19-lc/include/linux/power_supply.h
底层驱动所用的枚举和上面的字符串一一对应,比如power_supply_status_text[]:
比如power_supply_capacity_level_text[]:
... ...

另外,说明一下,frameworks用的enum为:
enum {
    BATTERY_STATUS_UNKNOWN = 1,
    BATTERY_STATUS_CHARGING = 2,
    BATTERY_STATUS_DISCHARGING = 3,
    BATTERY_STATUS_NOT_CHARGING = 4,
    BATTERY_STATUS_FULL = 5,
};

 /kernel-4.19-lc/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
static ssize_t power_supply_show_property(struct device *dev, struct device_attribute *attr, char *buf) {
    ssize_t ret;
    struct power_supply *psy = dev_get_drvdata(dev);
    enum power_supply_property psp = attr - power_supply_attrs;  //计算指针的偏移,得出是第几个property
    union power_supply_propval value;

    if (psp == POWER_SUPPLY_PROP_TYPE) {
        value.intval = psy->desc->type;
    } else {                                                      //return psy->desc->get_property(psy, psp, val);
        ret = power_supply_get_property(psy, psp, &value);  //从驱动获取相应的属性数据

        if (ret < 0) {
            if (ret == -ENODATA)
                dev_dbg(dev, "driver has no data for `%s' property\n",
                    attr->attr.name);
            else if (ret != -ENODEV && ret != -EAGAIN)
                dev_err_ratelimited(dev,
                    "driver failed to report `%s' property: %zd\n",
                    attr->attr.name, ret);
            return ret;
        }
    }

    switch (psp) {
    case POWER_SUPPLY_PROP_STATUS:
        ret = sprintf(buf, "%s\n", power_supply_status_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_CHARGE_TYPE:
        ret = sprintf(buf, "%s\n", power_supply_charge_type_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_HEALTH:
        ret = sprintf(buf, "%s\n", power_supply_health_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_TECHNOLOGY:
        ret = sprintf(buf, "%s\n", power_supply_technology_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
        ret = sprintf(buf, "%s\n", power_supply_capacity_level_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_TYPE:
    case POWER_SUPPLY_PROP_REAL_TYPE:
        ret = sprintf(buf, "%s\n", power_supply_type_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_USB_TYPE:
        ret = power_supply_show_usb_type(dev, psy->desc->usb_types, psy->desc->num_usb_types, &value, buf);
        break;
    case POWER_SUPPLY_PROP_SCOPE:
        ret = sprintf(buf, "%s\n", power_supply_scope_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_TYPEC_MODE:
        ret = sprintf(buf, "%s\n", power_supply_usbc_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
        ret = sprintf(buf, "%s\n", power_supply_usbc_pr_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_TYPEC_SRC_RP:
        ret = sprintf(buf, "%s\n", power_supply_typec_src_rp_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_DIE_HEALTH:
    case POWER_SUPPLY_PROP_SKIN_HEALTH:
    case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
        ret = sprintf(buf, "%s\n", power_supply_health_text[value.intval]);
        break;
    case POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT:  /* Local extensions of type int64_t */
        ret = sprintf(buf, "%lld\n", value.int64val);
        break;
    case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
        ret = sprintf(buf, "%s\n", value.strval);
        break;
    default:
        ret = sprintf(buf"%d\n"value.intval);  //一般的属性,就直接复制给buf
    }

    return ret;
}
另外,我们可以看到struct device_attribute power_supply_attrs[]中,attr的.show也是power_supply_show_property,
读取相关节点,比如/sys/class/power_supply/battery/capacity,最终调用battery_get_property获取数据:
power_supply_show_property
 ->power_supply_get_property(psy, off, &value);
  ->psy->desc->get_property(psy, psp, val);
   ->battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
/kernel-4.14/drivers/power/supply/power_supply_sysfs.c
 ... ...
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值