Android模拟器学framework和driver之battery & backlight-----1.battery in linux

来源:互联网 发布:口袋妖怪淘宝魔法师 编辑:程序博客网 时间:2024/05/01 00:01

在linux中battery驱动主要是去处理供电方面的东西,大家看下driver在bsp中的路径就可以知道,android模拟器使用的goldfish内核中battery驱动的位置是:

android/common/drivers/power/goldfish_battery.c

目前手机,平板电脑日益普及,在嵌入式领域battery的续航能力也一直制约着手机等嵌入式设备的发展,iphone比android手机做的好多了,希望android可以再处理上下功夫,赶超apple,废话不多说,这里battery主要是处理,电池供电、插上充电器充电、USB供电等事情的发生,还有就是一些电池的信息管理,比如说电量、温度等状态可以使用户知道。

OK,这边我们主要是使用goldfish中的battery驱动来分析一下linux中的power模块是如何工作的。

在这之前我们首先要来看一下power_supply这个device driver 子系统是如何建立的,这边我们涉及到的代码都在/common/drivers/power/下:

power_supply_core.c

power_supply_sysfs.c

goldfish_battery.c

power_supply_core.c是power_supple subsystem的核心函数,在power_supply子系统在linux启动的时候会先调用到里面的饿init函数:

[cpp] view plaincopyprint?
  1. static int __init power_supply_class_init(void)  
  2. {  
  3.     power_supply_class = class_create(THIS_MODULE, "power_supply");  
  4.   
  5.     if (IS_ERR(power_supply_class))  
  6.         return PTR_ERR(power_supply_class);  
  7.   
  8.     power_supply_class->dev_uevent = power_supply_uevent;  
  9.   
  10.     return 0;  
  11. }  
  12.   
  13. subsys_initcall(power_supply_class_init);  

这个函数比较简单首先是在class中创建了一个power_supply的class,启动模拟器后可以看到在sys/class/下会有一个power_supply文件夹生成,然后是

power_supply_class->dev_uevent = power_supply_uevent;这句话把power_supply_uevent挂到power_supply_class的dev_uevent上,这里说明下,就是说power_supply子系统都是使用uevent机制把信息传到user space的,当battery的状态发生改变的时候会向用户空间上报一个uevent,这样的话用户空间就可以知道什么时候去抓信息。

这个power_supply_uevent是个回调函数,被定义在power_supply_sysfs.c中:

[cpp] view plaincopyprint?
  1. int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)  
  2. {  
  3.     struct power_supply *psy = dev_get_drvdata(dev);  
  4.     int ret = 0, j;  
  5.     char *prop_buf;  
  6.     char *attrname;  
  7.   
  8.     dev_dbg(dev, "uevent\n");  
  9.   
  10.     if (!psy || !psy->dev) {  
  11.         dev_dbg(dev, "No power supply yet\n");  
  12.         return ret;  
  13.     }  
  14.   
  15.     dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);  
  16.   
  17.     ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);  
  18.     if (ret)  
  19.         return ret;  
  20.   
  21.     prop_buf = (char *)get_zeroed_page(GFP_KERNEL);  
  22.     if (!prop_buf)  
  23.         return -ENOMEM;  
  24.   
  25.     for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) {  
  26.         struct device_attribute *attr;  
  27.         char *line;  
  28.   
  29.         attr = &power_supply_static_attrs[j];  
  30.   
  31.         ret = power_supply_show_static_attrs(dev, attr, prop_buf);  
  32.         if (ret < 0)  
  33.             goto out;  
  34.   
  35.         line = strchr(prop_buf, '\n');  
  36.         if (line)  
  37.             *line = 0;  
  38.   
  39.         attrname = kstruprdup(attr->attr.name, GFP_KERNEL);  
  40.         if (!attrname) {  
  41.             ret = -ENOMEM;  
  42.             goto out;  
  43.         }  
  44.   
  45.         dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);  
  46.   
  47.         ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);  
  48.         kfree(attrname);  
  49.         if (ret)  
  50.             goto out;  
  51.     }  
  52.   
  53.     dev_dbg(dev, "%zd dynamic props\n", psy->num_properties);  
  54.   
  55.     for (j = 0; j < psy->num_properties; j++) {  
  56.         struct device_attribute *attr;  
  57.         char *line;  
  58.   
  59.         attr = &power_supply_attrs[psy->properties[j]];  
  60.   
  61.         ret = power_supply_show_property(dev, attr, prop_buf);  
  62.         if (ret == -ENODEV) {  
  63.             /* When a battery is absent, we expect -ENODEV. Don't abort; 
  64.                send the uevent with at least the the PRESENT=0 property */  
  65.             ret = 0;  
  66.             continue;  
  67.         }  
  68.   
  69.         if (ret < 0)  
  70.             goto out;  
  71.   
  72.         line = strchr(prop_buf, '\n');  
  73.         if (line)  
  74.             *line = 0;  
  75.   
  76.         attrname = kstruprdup(attr->attr.name, GFP_KERNEL);  
  77.         if (!attrname) {  
  78.             ret = -ENOMEM;  
  79.             goto out;  
  80.         }  
  81.   
  82.         dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);  
  83.   
  84.         ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);  
  85.         kfree(attrname);  
  86.         if (ret)  
  87.             goto out;  
  88.     }  
  89.   
  90. out:  
  91.     free_page((unsigned long)prop_buf);  
  92.   
  93.     return ret;  
  94. }  

稍微有点长,不怕,我们慢慢来分析,这里只是开头,什么都没有应该比较好分析,

我们抓重点,首先是ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);这句话添加了uevent的一些环境变量,这里添加了POWER_SUPPLY_NAME,接着都是些分配内存的代码,还有就是把power_supply_properties中注册的所有属性都添加成环境变量,这样的话当battery的某个属性发生变化的时候都会通报到上层让用户知道。

这里uevent我不做详细介绍,网上资料也一大堆,后面讲到jni层的时候我也会做补充用户层是如何去开启一个socket来抓kernel中的uevent的。

回到我们的power_supply_core.c中,在linux起来的时候只有调用到core中的class_init函数,其他的函数都是为我们的driver服务的,

现在我们来看下我们的goldfish_battery驱动,打开android/common/drivers/power/goldfish_battery.c,一般我喜欢先看init函数,

[cpp] view plaincopyprint?
  1. static int __init goldfish_battery_init(void)  
  2. {  
  3.     return platform_driver_register(&goldfish_battery_device);  
  4. }  

很简单,注册了platform_driver,同学们看到了这个函数第一反应应该是去找device_register函数,以为只有这2个函数匹配了才算在linux系统中注册了platform 设备,那么在哪呢?在我们goldfish的板级文件中有注册device,这边很奇怪,其实我没有找到具体的goldfish-battery的device_register但是在板级文件中有一个pdev_bus的注册

arch/arm/mach-goldfish/pdev_bus.c

[cpp] view plaincopyprint?
  1. static void goldfish_pdev_worker(struct work_struct *work);  
  2.   
  3. static uint32_t pdev_bus_base;  
  4. static uint32_t pdev_bus_irq;  
  5. static LIST_HEAD(pdev_bus_new_devices);  
  6. static LIST_HEAD(pdev_bus_registered_devices);  
  7. static LIST_HEAD(pdev_bus_removed_devices);  
  8. static DECLARE_WORK(pdev_bus_worker, goldfish_pdev_worker);  
  9.   
  10.   
  11. static void goldfish_pdev_worker(struct work_struct *work)  
  12. {  
  13.     int ret;  
  14.     struct pdev_bus_dev *pos, *n;  
  15.   
  16.     list_for_each_entry_safe(pos, n, &pdev_bus_removed_devices, list) {  
  17.         list_del(&pos->list);  
  18.         platform_device_unregister(&pos->pdev);  
  19.         kfree(pos);  
  20.     }  
  21.     list_for_each_entry_safe(pos, n, &pdev_bus_new_devices, list) {  
  22.         list_del(&pos->list);  
  23.         <span style="color: rgb(255, 0, 0); ">ret = platform_device_register(&pos->pdev);</span>  
  24.         if(ret) {  
  25.             printk("goldfish_pdev_worker failed to register device, %s\n", pos->pdev.name);  
  26.         }  
  27.         else {  
  28.             printk("goldfish_pdev_worker registered %s\n", pos->pdev.name);  
  29.         }  
  30.         list_add_tail(&pos->list, &pdev_bus_registered_devices);  
  31.     }  
  32. }  

可以看下上面这个代码中,在工作队列中遍历所有的pdev链表,调用platform_device_register把设备注册进去,之后就会调用到我们的probe函数了。

---------------------------------------------------------------------------------

probe函数主要还是做一些初始化,probe的意思就是探测的意思,就是试着去初始化(我是这么理解的),

[cpp] view plaincopyprint?
  1. static int goldfish_battery_probe(struct platform_device *pdev)  
  2. {  
  3.     int ret;  
  4.     struct resource *r;  
  5.     struct goldfish_battery_data *data;  
  6.   
  7.     data = kzalloc(sizeof(*data), GFP_KERNEL);  
  8.     if (data == NULL) {  
  9.         ret = -ENOMEM;  
  10.         goto err_data_alloc_failed;  
  11.     }  
  12.     spin_lock_init(&data->lock);  
  13.   
  14.     data->battery.properties = goldfish_battery_props;  
  15.     data->battery.num_properties = ARRAY_SIZE(goldfish_battery_props);  
  16.     data->battery.get_property = goldfish_battery_get_property;  
  17.     data->battery.name = "battery";  
  18.     data->battery.type = POWER_SUPPLY_TYPE_BATTERY;  
  19.   
  20.     data->ac.properties = goldfish_ac_props;  
  21.     data->ac.num_properties = ARRAY_SIZE(goldfish_ac_props);  
  22.     data->ac.get_property = goldfish_ac_get_property;  
  23.     data->ac.name = "ac";  
  24.     data->ac.type = POWER_SUPPLY_TYPE_MAINS;  
  25.   
  26.     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  27.     if (r == NULL) {  
  28.         printk(KERN_ERR "%s: platform_get_resource failed\n", pdev->name);  
  29.         ret = -ENODEV;  
  30.         goto err_no_io_base;  
  31.     }  
  32.     data->reg_base = IO_ADDRESS(r->start - IO_START);  
  33.   
  34.     data->irq = platform_get_irq(pdev, 0);  
  35.     if (data->irq < 0) {  
  36.         printk(KERN_ERR "%s: platform_get_irq failed\n", pdev->name);  
  37.         ret = -ENODEV;  
  38.         goto err_no_irq;  
  39.     }  
  40.   
  41.     ret = request_irq(data->irq, goldfish_battery_interrupt, IRQF_SHARED, pdev->name, data);  
  42.     if (ret)  
  43.         goto err_request_irq_failed;  
  44.   
  45.     ret = power_supply_register(&pdev->dev, &data->ac);  
  46.     if (ret)  
  47.         goto err_ac_failed;  
  48.   
  49.     ret = power_supply_register(&pdev->dev, &data->battery);  
  50.     if (ret)  
  51.         goto err_battery_failed;  
  52.   
  53.     platform_set_drvdata(pdev, data);  
  54.     battery_data = data;  
  55.   
  56.     GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);  
  57.     return 0;  
  58.   
  59. err_battery_failed:  
  60.     power_supply_unregister(&data->ac);  
  61. err_ac_failed:  
  62.     free_irq(data->irq, data);  
  63. err_request_irq_failed:  
  64. err_no_irq:  
  65. err_no_io_base:  
  66.     kfree(data);  
  67. err_data_alloc_failed:  
  68.     return ret;  
  69. }  

首先来看几个结构体,其实个人认为,linux驱动给开发人员做的很多就是填充结构体,因为基本框架linux已经实现了,我们要做的是把这个大框架填满,使这个框架有血有肉,这样才能正常工作。

首先是goldfish_battery_data 这个结构体:

[cpp] view plaincopyprint?
  1. struct goldfish_battery_data {  
  2.     uint32_t reg_base;  
  3.     int irq;  
  4.     spinlock_t lock;  
  5.   
  6.     struct power_supply battery;  
  7.     struct power_supply ac;  
  8. };  

这个结构体中我们关注的是power_supply这个结构体,别的没什么好说的,中断啊,寄存器地址啊,自旋锁什么的。

[cpp] view plaincopyprint?
  1. struct power_supply {  
  2.     const char *name;  
  3.     enum power_supply_type type;  
  4.     enum power_supply_property *properties;  
  5.     size_t num_properties;  
  6.   
  7.     char **supplied_to;  
  8.     size_t num_supplicants;  
  9.   
  10.     int (*get_property)(struct power_supply *psy,  
  11.                 enum power_supply_property psp,  
  12.                 union power_supply_propval *val);  
  13.     void (*external_power_changed)(struct power_supply *psy);  
  14.   
  15.     /* For APM emulation, think legacy userspace. */  
  16.     int use_for_apm;  
  17.   
  18.     /* private */  
  19.     struct device *dev;  
  20.     struct work_struct changed_work;  
  21.   
  22. #ifdef CONFIG_LEDS_TRIGGERS   
  23.     struct led_trigger *charging_full_trig;  
  24.     char *charging_full_trig_name;  
  25.     struct led_trigger *charging_trig;  
  26.     char *charging_trig_name;  
  27.     struct led_trigger *full_trig;  
  28.     char *full_trig_name;  
  29.     struct led_trigger *online_trig;  
  30.     char *online_trig_name;  
  31. #endif   
  32. };  

这部分我们对照着probe中的代码一起分析,主要还是填充这个结构体:

[cpp] view plaincopyprint?
  1. data->battery.properties = goldfish_battery_props;  
  2. data->battery.num_properties = ARRAY_SIZE(goldfish_battery_props);  
  3. data->battery.get_property = goldfish_battery_get_property;  
  4. data->battery.name = "battery";  
  5. data->battery.type = POWER_SUPPLY_TYPE_BATTERY;  

首先是对battery的属性信息的填写:

[cpp] view plaincopyprint?
  1. static enum power_supply_property goldfish_battery_props[] = {  
  2.     POWER_SUPPLY_PROP_STATUS,  
  3.     POWER_SUPPLY_PROP_HEALTH,  
  4.     POWER_SUPPLY_PROP_PRESENT,  
  5.     POWER_SUPPLY_PROP_TECHNOLOGY,  
  6.     POWER_SUPPLY_PROP_CAPACITY,  
  7. };  

这边电池的信息由status health present等,我们比较关注的还是电池的电量,capacity,

然后是属性的数目,不多说了,下面第三个参数比较重要 data->battery.get_property = goldfish_battery_get_property;

[cpp] view plaincopyprint?
  1. static int goldfish_battery_get_property(struct power_supply *psy,  
  2.                  enum power_supply_property psp,  
  3.                  union power_supply_propval *val)  
  4. {  
  5.     struct goldfish_battery_data *data = container_of(psy,  
  6.         struct goldfish_battery_data, battery);  
  7.     int ret = 0;  
  8.   
  9.     switch (psp) {  
  10.     case POWER_SUPPLY_PROP_STATUS:  
  11.         //modify charge to discharge  
  12.         //val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_STATUS);  
  13.         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;  
  14.         //-----modify end   
  15.         break;  
  16.     case POWER_SUPPLY_PROP_HEALTH:  
  17.         val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_HEALTH);  
  18.         break;  
  19.     case POWER_SUPPLY_PROP_PRESENT:  
  20.         val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_PRESENT);  
  21.         break;  
  22.     case POWER_SUPPLY_PROP_TECHNOLOGY:  
  23.         val->intval = POWER_SUPPLY_TECHNOLOGY_LION;  
  24.         break;  
  25.     case POWER_SUPPLY_PROP_CAPACITY:  
  26.         //modify capacity from 50 per to 20 per by Jay  
  27.         //val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY);  
  28.         val->intval = global_brightness;  
  29.         //----modify end   
  30.         break;  
  31.     default:  
  32.         ret = -EINVAL;  
  33.         break;  
  34.     }  
  35.   
  36.     return ret;  
  37. }  

驱动中就是通过这个函数去实时得到电池的信息,然后使用uevent传到user space,我们重点讲下这个函数是怎么工作的。

大家注意到这里这个函数的参数,struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val

第一个参数是我们最重要的data struct,第二个参数是属性的类型,选择我们要得到的属性,第三个参数就是这个属性的值是多少,比如说电池电量是百分之多少。

这个函数是被挂在power_supply结构体中的get_property上的,它是在哪被回调呢?我们先在这里打个问号,我们知道这里只是在一些结构体中填充好了我们battery的信息,至于在什么时候回调,什么时候使用,什么时候上传uevent,我们后面会讲到,留意下!!

继续回到probe函数,下面是

[cpp] view plaincopyprint?
  1. data->battery.name = "battery";  
  2. data->battery.type = POWER_SUPPLY_TYPE_BATTERY;  

名字和类型的填写。

下面就是跟硬件相关的东西了,一般的device是会用中断的方法去触发,这里goldfish的内核使用的是PC的中断资源。

[cpp] view plaincopyprint?
  1. data->irq = platform_get_irq(pdev, 0);  
  2. if (data->irq < 0) {  
  3.     printk(KERN_ERR "%s: platform_get_irq failed\n", pdev->name);  
  4.     ret = -ENODEV;  
  5.     goto err_no_irq;  
  6. }  
  7.   
  8. ret = request_irq(data->irq, goldfish_battery_interrupt, IRQF_SHARED, pdev->name, data);  

得到中断好,然后申请中断,挂好中断触发的函数,这里发生中断后会做一系列的事情,我们也先放一下,先来看看下面的power_supply注册函数:

[cpp] view plaincopyprint?
  1. ret = power_supply_register(&pdev->dev, &data->ac);  
  2. if (ret)  
  3.     goto err_ac_failed;  
  4.   
  5. ret = power_supply_register(&pdev->dev, &data->battery);  
  6. if (ret)  
  7.     goto err_battery_failed;  
  8.   
  9. platform_set_drvdata(pdev, data);  
  10. battery_data = data;  

power_supply_register函数在power_supply_core中被定义

[cpp] view plaincopyprint?
  1. int power_supply_register(struct device *parent, struct power_supply *psy)  
  2. {  
  3.     int rc = 0;  
  4.   
  5.     psy->dev = device_create(power_supply_class, parent, 0, psy,  
  6.                  "%s", psy->name);  
  7.     if (IS_ERR(psy->dev)) {  
  8.         rc = PTR_ERR(psy->dev);  
  9.         goto dev_create_failed;  
  10.     }  
  11.   
  12.     INIT_WORK(&psy->changed_work, power_supply_changed_work);  
  13.   
  14.     rc = power_supply_create_attrs(psy);  
  15.     if (rc)  
  16.         goto create_attrs_failed;  
  17.   
  18.     rc = power_supply_create_triggers(psy);  
  19.     if (rc)  
  20.         goto create_triggers_failed;  
  21.   
  22.     power_supply_changed(psy);  
  23.   
  24.     goto success;  
  25.   
  26. create_triggers_failed:  
  27.     power_supply_remove_attrs(psy);  
  28. create_attrs_failed:  
  29.     device_unregister(psy->dev);  
  30. dev_create_failed:  
  31. success:  
  32.     return rc;  
  33. }  

首先是时候device_create函数在class下创建设备驱动,传入的第一个参数就是我们的power_supply class

然后是初始化了工作队列INIT_WORK(&psy->changed_work, power_supply_changed_work);

oK,我们来看下这个工作队列的回调函数,power_supply_changed_work

[cpp] view plaincopyprint?
  1. static void power_supply_changed_work(struct work_struct *work)  
  2. {  
  3.     struct power_supply *psy = container_of(work, struct power_supply,  
  4.                         changed_work);  
  5.   
  6.     dev_dbg(psy->dev, "%s\n", __func__);  
  7.   
  8.     class_for_each_device(power_supply_class, NULL, psy,  
  9.                   __power_supply_changed_work);  
  10.   
  11.     power_supply_update_leds(psy);  
  12.   
  13.     kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);  
  14. }  

这里就是调用了2个函数,第一个 class_for_each_device(power_supply_class, NULL, psy,
     __power_supply_changed_work);

它遍历了我们power_supply_class上的所有节点,用psy作为参数调用了__power_supply_changed_work函数,__power_supply_changed_work函数的作用是匹配我们的驱动

[cpp] view plaincopyprint?
  1. static int __power_supply_changed_work(struct device *dev, void *data)  
  2. {  
  3.     struct power_supply *psy = (struct power_supply *)data;  
  4.     struct power_supply *pst = dev_get_drvdata(dev);  
  5.     int i;  
  6.   
  7.     for (i = 0; i < psy->num_supplicants; i++)  
  8.         if (!strcmp(psy->supplied_to[i], pst->name)) {  
  9.             if (pst->external_power_changed)  
  10.                 pst->external_power_changed(pst);  
  11.         }  
  12.     return 0;  
  13. }  

之后再调用到了我们最最最最关键的地方kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);这里就是注册了kobject uevent事件,当我们的属性发生变化的时候会把uevent传给用户空间。

所以说,调用到我们的工作队列的时候就会向用户空间上报event,这个动作被封装在

[cpp] view plaincopyprint?
  1. void power_supply_changed(struct power_supply *psy)  
  2. {  
  3.     dev_dbg(psy->dev, "%s\n", __func__);  
  4.   
  5.     schedule_work(&psy->changed_work);  
  6. }  

之后会被使用到。

回到我们的power_supply_register函数中

rc = power_supply_create_attrs(psy);被定义在power_supply_sysfs.c中

[cpp] view plaincopyprint?
  1. int power_supply_create_attrs(struct power_supply *psy)  
  2. {  
  3.     int rc = 0;  
  4.     int i, j;  
  5.   
  6.     for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) {  
  7.         rc = device_create_file(psy->dev,  
  8.                 &power_supply_static_attrs[i]);  
  9.         if (rc)  
  10.             goto statics_failed;  
  11.     }  
  12.   
  13.     for (j = 0; j < psy->num_properties; j++) {  
  14.         rc = device_create_file(psy->dev,  
  15.                 &power_supply_attrs[psy->properties[j]]);  
  16.         if (rc)  
  17.             goto dynamics_failed;  
  18.     }  
  19.   
  20.     goto succeed;  
  21.   
  22. dynamics_failed:  
  23.     while (j--)  
  24.         device_remove_file(psy->dev,  
  25.                &power_supply_attrs[psy->properties[j]]);  
  26. statics_failed:  
  27.     while (i--)  
  28.         device_remove_file(psy->dev, &power_supply_static_attrs[i]);  
  29. succeed:  
  30.     return rc;  
  31. }  

这边遍历了我们的属性数组,把每个属性在我们的驱动中声称文件系统,调用到device_create_flie函数,我们运行模拟器在power_supply/battery/下会发现我们填进去的属性值生成的所有文件。

这里介绍完毕,回到我们的goldfish驱动文件,最后就是我们的中断函数了。

[cpp] view plaincopyprint?
  1. static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id)  
  2. {  
  3.     unsigned long irq_flags;  
  4.     struct goldfish_battery_data *data = dev_id;  
  5.     uint32_t status;  
  6.   
  7.     spin_lock_irqsave(&data->lock, irq_flags);  
  8.   
  9.     /* read status flags, which will clear the interrupt */  
  10.     status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS);  
  11.     status &= BATTERY_INT_MASK;  
  12.   
  13.     if (status & BATTERY_STATUS_CHANGED)  
  14.         power_supply_changed(&data->battery);  
  15.     if (status & AC_STATUS_CHANGED)  
  16.         power_supply_changed(&data->ac);  
  17.   
  18.     spin_unlock_irqrestore(&data->lock, irq_flags);  
  19.     return status ? IRQ_HANDLED : IRQ_NONE;  
  20. }  


这里我什么也不看只想看一句话

[cpp] view plaincopyprint?
  1. if (status & BATTERY_STATUS_CHANGED)  
  2.     power_supply_changed(&data->battery);  
  3. if (status & AC_STATUS_CHANGED)  
  4.     power_supply_changed(&data->ac);  

之前讲过,就是power_supply_changed函数触发了向用户空间上报event事件的代码。OK ,android goldfish battery驱动就讲到这边,我看android模拟器的电池老是动啊动的很是不爽所以我在get_property函数中充电状态改成了不是充电状态,然后把电池电量设置为恒定的,嘿嘿,这样的话就不会动了,哈哈。下面贴张图,有图有真相