上一节我们看了设备驱动的设备驱动设备注册过程,对于它的注册过程就不多讲了,和上一节的注册过程一样,
这一节我们来看看电池的驱动模块的执行过程;
static struct platform_driver jz_battery_driver = {.probe = jz_battery_probe ,.remove = __devexit_p( jz_battery_remove ),.driver = {.name = "jz4775-battery",.owner = THIS_MODULE,},.suspend = jz_battery_suspend ,.resume = jz_battery_resume ,};
下面我们就来看看探测函数
jz_battery_probe
的具体内容,具体做了些什么准备工作,
static int __devinit jz_battery_probe (struct platform_device *pdev){int ret = 0;struct jz_battery_platform_data *pdata = pdev->dev.parent->platform_data;struct jz_battery *bat;struct power_supply *battery;struct proc_dir_entry *root;struct proc_dir_entry *res;if (!pdata) {dev_err(&pdev->dev, "No platform_data supplied\n");return -ENXIO;}bat = kzalloc(sizeof(*bat), GFP_KERNEL); // 申请内存空间if (!bat) {dev_err(&pdev->dev, "Failed to allocate driver structre\n");return -ENOMEM;}bat->cell = mfd_get_cell(pdev);bat->ucharger = regulator_get(&pdev->dev, "ucharger");if (!bat->ucharger) {pr_info("Missing regulator ucharger\n");}bat->irq = platform_get_irq(pdev, 0); // 获得平台对应的中断号if (bat->irq < 0) {ret = bat->irq;dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);goto err_free;}bat->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); // 获得平台对应资源if (!bat->mem) {ret = -ENOENT;dev_err(&pdev->dev, "Failed to get platform mmio resource\n");goto err_free;}bat->mem = request_mem_region(bat->mem->start, resource_size(bat->mem), pdev->name); // 申请内存块资源if (!bat->mem) {ret = -EBUSY;dev_err(&pdev->dev, "Failed to request mmio memory region\n");goto err_free;}bat->base = ioremap_nocache(bat->mem->start, resource_size(bat->mem)); // IO资源空间映射if (!bat->base) {ret = -EBUSY;dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");goto err_release_mem_region;}get_slop_cut();// 初始化电池结构体battery = &bat->battery;battery->name = "battery";battery->type = POWER_SUPPLY_TYPE_BATTERY;battery->properties = jz_battery_properties;battery->num_properties = ARRAY_SIZE(jz_battery_properties);battery->get_property = jz_battery_get_property ; //获取电池的基本属性battery->external_power_changed = jz_battery_external_power_changed ;battery->use_for_apm = 1;bat->pdata = pdata;bat->pdev = pdev;#ifdef CONFIG_HAS_EARLYSUSPEND
bat->early_suspend.suspend = jz_battery_early_suspend ;bat->early_suspend.resume = jz_battery_late_resume ;bat->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;#endifregister_early_suspend(&bat->early_suspend);// 锁机制的初始化init_completion(&bat->read_completion);mutex_init(&bat->lock);// 初始化延时队列INIT_DELAYED_WORK(&bat->work, jz_battery_work );INIT_DELAYED_WORK(&bat->init_work, jz_battery_init_work );INIT_DELAYED_WORK(&bat->resume_work, jz_battery_resume_work );wake_lock_init(&bat->work_wake_lock, WAKE_LOCK_SUSPEND, "jz_battery");// 申请中断ret = request_irq(bat->irq, adc_irq_handler, 0, pdev->name, bat); // 下半部唤醒所有等待队列if (ret) {dev_err(&pdev->dev, "Failed to request irq %d\n", ret);goto err_iounmap;}disable_irq(bat->irq);// 注册充电电池设备ret = power_supply_register(&pdev->dev, &bat->battery);if (ret) {dev_err(&pdev->dev, "Power supply battery register failed.\n");goto err_iounmap;}platform_set_drvdata(pdev, bat);if (pdata->info.usb_chg_current) {bat->usb_charge_time = pdata->info.battery_max_cpt * 36 / pdata->info.usb_chg_current;}if (bat->usb_charge_time < 90)bat->usb_charge_time = 90;// 获取电压值bat->voltage = get_adc_voltage (bat);bat->next_scan_time = 15;/* init_work init function is only called once,* 5 seconds delay waiting Charger Device registration*/schedule_delayed_work(&bat->init_work, 5 * HZ); // 调度任务// 创建文件节点root = proc_mkdir("power_supply", 0); // 创建目录res = create_proc_entry("capacity", 0200, root); // 创建文件节点if (res) {res->write_proc = proc_set_capacity ; // 写函数res->data = bat;}res = create_proc_entry("status", 0444, root); // 创建文件节点if (res) {res->read_proc = proc_read_status ; // 读函数res->data = bat;}// 打印电池的基本信息pr_info(LOG_TAG "discharging max voltage is %d\n", jz_cv_discharging[100]);pr_info(LOG_TAG "discharging min voltage is %d\n", jz_cv_discharging[0]);pr_info(LOG_TAG "charging max voltage is %d\n", jz_cv_charging[100]);pr_info(LOG_TAG "charging min voltage is %d\n", jz_cv_charging[0]);pr_info(LOG_TAG "battery_max_cpt is %d\n", pdata->info.battery_max_cpt);pr_info(LOG_TAG "usb_chg_current is %d\n", pdata->info.usb_chg_current);pr_info(LOG_TAG "sleep_current is %d\n", pdata->info.sleep_current);pr_info(LOG_TAG "registers over!\n");return 0;// 注销退出err_iounmap:#ifndef CONFIG_SLPTwake_lock_destroy(&bat->work_wake_lock); //工作队列唤醒锁#endifplatform_set_drvdata(pdev, NULL); // 清除平台数据iounmap(bat->base); // 取消IO映射空间err_release_mem_region:release_mem_region(bat->mem->start, resource_size(bat->mem)); // 注销内存映射空间err_free:if (bat->ucharger)regulator_put(bat->ucharger);kfree(bat); //释放电池结构体数据return ret;}
之前我也读过该函数接口,所以在介绍它的执行过程之前我们先来看看几个函数接口,为我们介绍它的执行过程做准备工作。
static void jz_battery_early_suspend (struct early_suspend *early_suspend){#ifndef CONFIG_SLPTstruct jz_battery *bat;pr_info(LOG_TAG "%s\n", __FUNCTION__);bat = container_of(early_suspend, struct jz_battery, early_suspend); // 获得结构体的地址jz_battery_set_resume_time (bat); // 设置睡眠唤醒时间#endif}
有该接口的具体实现,我们很容易看明白其实它只做了一件事,那就是调用唤醒时间函数jz_battery_set_resume_time,我们再来具体看看它的具体内容,如下:
static void jz_battery_set_resume_time (struct jz_battery *bat) //设置定时器的定时时间
{
struct timespec alarm_time;unsigned long interval = 60 * 60;getnstimeofday (&alarm_time); //获取当前时间printk(LOG_TAG "time now is %ld\n",alarm_time.tv_sec); // 打印当前时间// 根据显示的容量来设置时间值if (bat->pdata->info.sleep_current == 0){interval = 60 * 60;} else if (bat->capacity_show > 10) {interval = ((bat->capacity_show - 10) * bat->pdata->info.battery_max_cpt * 36) / (bat->pdata->info.sleep_current);} else if (bat->capacity_show > 3) {interval = ((bat->capacity_show - 3) * bat->pdata->info.battery_max_cpt * 36) / (bat->pdata->info.sleep_current);} else if (bat->capacity_show > 1){interval = ((bat->capacity_show - 1) * bat->pdata->info.battery_max_cpt * 36) / (bat->pdata->info.sleep_current);} else if (bat->capacity_show == 1){interval = (bat->pdata->info.battery_max_cpt * 36) / bat->pdata->info.sleep_current;}if (interval == 0)interval = 60 * 60;alarm_time.tv_sec += interval; // 定时时间值printk(LOG_TAG "set resume time %ld(delta %ld, %ldh %ldm %lds)\n", alarm_time.tv_sec, interval, interval/3600,(interval/60)%60, interval%60); // 打印定时器时间alarm_start_range (&alarm, timespec_to_ktime(alarm_time), timespec_to_ktime(alarm_time)); // 设置时间
}
通过查看jz_battery_late_resume函数的具体执行内容,可以知道其实它只是在进行空执行,所以这里我们就不把它列出来分析了,如果特别想了解它,可以自己查看代码,代码在 driver/power/jz4775-battery-lut.c中。
准备工作做得差不多了,我们来看看它的执行过程,看看它到底是怎样工作的,根据调度函数schedule_delayed_work(&bat->init_work, 5 * HZ) 我们可以知道,它将调度初始化工作队列也就是 jz_battery_init_work函数。
static void jz_battery_init_work (struct work_struct *work){struct delayed_work *delayed_work = container_of(work, struct delayed_work, work);struct jz_battery *bat = container_of(delayed_work, struct jz_battery, init_work);pr_info(LOG_TAG "%s\n", __FUNCTION__);if (bat->get_pmu_status == NULL) {pr_err(LOG_TAG "Changer device not yet registered !\n");return;}bat->status = get_status (bat); // 获取当前电池状态bat->voltage = get_adc_voltage (bat); // 获取电池电压值// 根据电池的状态来设置它的显示值if (bat->status != POWER_SUPPLY_STATUS_FULL) {bat->capacity_real = lookup_capacity (is_charging (bat->status), bat->voltage); // 获得当前电压的百分比bat->capacity_show = bat->capacity_real;} elsebat->capacity_real = bat->capacity_show = 100;pr_info(LOG_TAG "%s, cap real: %d, cap show: %d, volt: %dmV\n", status2str(bat->status), bat->capacity_real,bat->capacity_show, bat->voltage);power_supply_changed (&bat->battery); //告诉Android 端,电池电量发生改变cancel_delayed_work_sync(&bat->work);#ifndef CONFIG_SLPTschedule_delayed_work(&bat->work, 20 * HZ); //调度到工作队列去工作#endifalarm_init(&alarm, ANDROID_ALARM_RTC_WAKEUP, wake_up_fun); // 0bat->pmu_work_enable(bat->pmu_interface);external_cb_en = 1;}
static int get_status (struct jz_battery *bat) // 获取当前电池的状态{int status;status = bat->get_pmu_status(bat->pmu_interface, STATUS);if ((status == POWER_SUPPLY_STATUS_CHARGING) && force_full && (bat->capacity_real > 85)) { // force_full = 0pr_info(LOG_TAG "Force FULL\n");return POWER_SUPPLY_STATUS_FULL;}if (status == POWER_SUPPLY_STATUS_FULL)force_full = 1;return status; // 返回当前电池的状态}
static int get_adc_voltage (struct jz_battery *bat) // 对读出的电压值进行校正处理{
unsigned int current_value[12], final_value = 0;unsigned int value_sum = 0;unsigned int max_value, min_value;unsigned int i,j = 0, temp;unsigned int max_index = 0, min_index = 0;unsigned int real_voltage = 0;current_value[0] = get_adc_value (bat); // 读取电压值// 对读出的电压值进行处理value_sum = max_value = min_value = current_value[0];for (i = 1; i < 12; i++) {
current_value[i] = get_adc_value(bat);value_sum += current_value[i];if (max_value < current_value[i]) {max_value = current_value[i];max_index = i;}if (min_value > current_value[i]) {min_value = current_value[i];min_index = i;}
}value_sum -= (max_value + min_value);final_value = value_sum / 10; // 获取平均电压值for (i = 0; i < 12; i++) {
if (i == min_index)
continue;
if (i == max_index)
continue;
temp = abs (current_value[i] - final_value); // 计算绝对值if (temp > 4) {j++;value_sum -= current_value[i]; // 去掉浮动大于4的值}
}if (j < 10) {
final_value = value_sum / (10 - j); // 计算剩余的电压值得平均值
}// 校正处理real_voltage = final_value * 1200 / 4096;real_voltage *= 4;if ((slop == 0) && (cut == 0)) {
pr_info(LOG_TAG "ADC voltage is %dmV\n",real_voltage);
} else {
unsigned int origin_voltage;origin_voltage = real_voltage;real_voltage = (final_value * slop + cut) / 10000;real_voltage *= 4;pr_info(LOG_TAG "ADC voltage is %d(%d)mV\n", real_voltage, origin_voltage);
}return real_voltage; // 返回校正后的电压值
}
static unsigned intget_adc_value (struct jz_battery *bat) // 获取电压值{unsigned long tmp;unsigned int value;mutex_lock(&bat->lock);INIT_COMPLETION(bat->read_completion);bat->cell->enable(bat->pdev);enable_irq(bat->irq);tmp = wait_for_completion_interruptible_timeout( &bat->read_completion, HZ); // tmp = 1 执行成功;tmp = 0 执行失败(超时)。if (tmp > 0) {value = readw(bat->base) & 0xfff; // 获取端口电压值} else {value = tmp ? tmp : -ETIMEDOUT;}disable_irq(bat->irq);bat->cell->disable(bat->pdev);mutex_unlock(&bat->lock);return value; // 返回获得的实际电压值}
=================================================================
static int lookup_capacity (int charging, int volt){int i;const int *cv;if (charging) // 判断是否正在充电,根据判断结果获取电池曲线cv = jz_cv_charging ; // 获得充电曲线的地址elsecv = jz_cv_discharging ; // 获得放电曲线的地址for (i = 100; i > 0; --i) {if (volt >= cv[i])return i; // 根据当前电压返回当前电量百分比}return 0;}
电池曲线分充电曲线和放电曲线,充电曲线相比同一百分比下的放电曲线的容量可能要高点,具体的数据需要靠对电池曲线的获取,获取的方法有手动获取的方法,当然也可以通过软件自动获取。const int __attribute__((weak)) jz_cv_discharging [101] = { //放电曲线
3408, /* 0% */3424,3448,3472,3496,3516,3536,3556,3576,3596,3616,3624,3632,3640,3644,3652,3656,3664,3668,3672,3676,3680,3682,3684,3688,3692,3694,3696,3700,3704,3708,3712,3716,3720,3728,3732,3736,3740,3742,3744,3748,3756,3760,3764,3768,3772,3776,3780,3784,3788,3792,3796,3800,3804,3808,3812,3816,3820,3828,3832,3836,3844,3852,3860,3868,3872,3880,3884,3888,3892,3900,3904,3910,3916,3920,3928,3936,3944,3952,3960,3968,3976,3984,3988,3996,4000,4008,4012,4020,4028,4040,4052,4058,4064,4076,4088,4096,4100,4104,4112,4120 /* 100% */
};
const int __attribute__((weak)) jz_cv_charging [101] = { // 充电曲线
3680, /* 0% */3804,3820,3824,3826,3828,3832,3838,3840,3842,3844, /* 10% */3847,3850,3854,3857,3860,3863,3866,3869,3872,3875, /* 20% */3878,3881,3885,3888,3892,3895,3898,3901,3905,3908, /* 30% */3910,3912,3914,3916,3918,3920,3922,3924,3926,3928, /* 40% */3929,3930,3932,3933,3934,3935,3937,3938,3939,3940, /* 50% */3941,3942,3943,3944,3945,3946,3947,3948,3949,3950, /* 60% */3952,3954,3956,3959,3962,3966,3970,3973,3976,3980, /* 70% */3985,3990,3995,4000,4005,4010,4015,4020,4025,4030, /* 80% */4036,4042,4048,4055,4062,4069,4076,4073,4080,4088, /* 90% */4089,4090,4091,4092,4093,4094,4096,4098,4190,4200 /* 100% */
==========================================================};
static int is_charging (int status){switch (status) {case POWER_SUPPLY_STATUS_CHARGING:case POWER_SUPPLY_STATUS_FULL:return 1;default:return 0;}}
根据函数的调度的顺序,我们从 jz_battery_init_work函数中的调度函数可以看出下一步将跳转到jz_battery_work函数去执行,我们再去看看它的具体实现;
static void jz_battery_work (struct work_struct *work){struct jz_battery *bat = container_of(work, struct jz_battery, work.work);int old_status = bat->status;pr_info(LOG_TAG "%s\n", __FUNCTION__);bat->status = get_status (bat);if (old_status != bat->status) // 比较之前状态和当期状态是否一致pr_info(LOG_TAG "old_status: %s\n", status2str (old_status));bat->voltage = get_adc_voltage (bat); // 获得校正后的电压值bat->capacity_real = lookup_capacity (is_charging (bat->status), bat->voltage); // 获得容量值switch (bat->status) { // 设置电池在不同的状态下的调度时间case POWER_SUPPLY_STATUS_CHARGING: jz_battery_capacity_rising (bat); break;case POWER_SUPPLY_STATUS_FULL: jz_battery_capacity_full (bat); break;case POWER_SUPPLY_STATUS_DISCHARGING:case POWER_SUPPLY_STATUS_NOT_CHARGING: jz_battery_capacity_falling (bat); break;case POWER_SUPPLY_STATUS_UNKNOWN: bat->next_scan_time = 60; break;}pr_info(LOG_TAG "%s, cap real: %d, cap show: %d, volt: %dmV, next %ds\n", status2str(bat->status), bat->capacity_real,bat->capacity_show, bat->voltage, bat->next_scan_time);#ifdef CONFIG_SLPT //编译测试时代码未编译slpt_set_battery_low_voltage(low_battery_voltage);slpt_set_battery_voltage(bat->voltage, bat->capacity_show);SLPT_SET_KEY(SLPT_K_LOW_BATTERY_WARN_VOL, low_battery_warn_voltage);#endifpower_supply_changed (&bat->battery); //上报当前电池状态schedule_delayed_work (&bat->work, bat->next_scan_time * HZ); // 根据设置的调度时间值,循环调度工作队列}
再来简单看下几个陌生的函数接口,看看它们的具体实现。
static const char *status2str (int status) // 返回当前状态的指针{switch (status) {case POWER_SUPPLY_STATUS_CHARGING:return "CHARGING";case POWER_SUPPLY_STATUS_DISCHARGING:return "DISCHARGING";case POWER_SUPPLY_STATUS_NOT_CHARGING:return "NOT_CHARGING";case POWER_SUPPLY_STATUS_FULL:return "FULL";default:return "UNKNOWN";}}
=======================================================================
static voidjz_battery_capacity_rising (struct jz_battery *bat) //设置电池在充电时的下一次执行工作队列的延时时间{bat->next_scan_time = 40;//根据当前显示的容量百分比设置执行工作队列的延时时间if (bat->capacity_show >= 100) {bat->next_scan_time = 60;bat->capacity_show = 99;return;} else if (bat->capacity_show == 99) {bat->next_scan_time = 60;return;}if (bat->capacity_real > bat->capacity_show + 5)bat->next_scan_time = 30;if (bat->capacity_real > bat->capacity_show + 10)bat->next_scan_time = 15;if (bat->capacity_real > bat->capacity_show)if (bat->capacity_show != 100)}bat->capacity_show++; // 设置显示的容量百分比自增
==============================================================================
static voidjz_battery_capacity_full (struct jz_battery *bat) // 设置显示的容量百分比和下次调度工作队列的延时时间{ // 根据当前的容量百分比重新设置容量百分比和延时调度时间if (bat->capacity_show >= 99) {bat->capacity_show = 100;bat->status = POWER_SUPPLY_STATUS_FULL;bat->next_scan_time = 5 * 60;} else {bat->next_scan_time = 45;bat->capacity_show++; // 设置显示的容量百分比自增}}
==============================================================================
当电池充电时进入电池工作队列后,就会进入循环工作,只有外部条件出发时才会执行其他的函数,下面我们再来看看驱动的卸载函数。static void jz_battery_capacity_falling (struct jz_battery *bat) // 设置显示的容量百分比和下次调度工作队列的延时时间{ // 重新设置容量百分比和调度延迟时间if (bat->capacity_show >= 90) {bat->next_scan_time = 120;} else if (bat->capacity_show >= 15 ) {bat->next_scan_time = 60;} else if (bat->capacity_show >= 8){bat->next_scan_time = 30;} else {bat->next_scan_time = 10;}if (bat->capacity_real < bat->capacity_show - 10)bat->next_scan_time = 10;if (bat->capacity_real < bat->capacity_show)if (bat->capacity_show != 0)bat->capacity_show--; //放电时电量自减}
static int __devexit jz_battery_remove (struct platform_device *pdev) //卸载退出函数接口{
struct jz_battery *bat = platform_get_drvdata(pdev);//注销工作队列和唤醒工作队列cancel_delayed_work_sync (&bat->work);cancel_delayed_work_sync (&bat->resume_work);
#ifndef CONFIG_SLPT
wake_lock_destroy (&bat->work_wake_lock); //销毁工作队列唤醒锁
#endif
power_supply_unregister (&bat->battery); // 注销充电电池的注册
free_irq (bat->irq, bat); // 释放中断号
iounmap (bat->base); // 取消IO空间映射release_mem_region (bat->mem->start, resource_size(bat->mem)); // 注销内存空间kfree (bat); //释放电池信息
return 0;
下面我们来看睡眠函数具体做了些什么工作,先看看它的代码;}
static int jz_battery_suspend (struct platform_device *pdev, pm_message_t state) // 取消唤醒队列和工作队列并保存当前进入睡眠时间{struct jz_battery *bat = platform_get_drvdata(pdev);struct timeval battery_time; // 微秒级pr_info(LOG_TAG "%s\n", __FUNCTION__);// 打印当期电池信息bat->status = get_status (bat);pr_info(LOG_TAG "%s, cap real: %d, cap show: %d, volt: %dmV\n", status2str (bat->status), bat->capacity_real,
bat->capacity_show, bat->voltage);
// 注销工作队列和唤醒队列cancel_delayed_work_sync (&bat->resume_work);cancel_delayed_work_sync (&bat->work);//获得当前时间并设置打印出来do_gettimeofday (&battery_time);bat->suspend_time = battery_time.tv_sec; // seconds 保存当前时间pr_info(LOG_TAG "suspend_time is %ld\n", battery_time.tv_sec);external_cb_en = 0;
return 0;}
最后一个就是唤醒函数了,我们来追踪下它的执行过程;
static int jz_battery_resume (struct platform_device *pdev) // 调度到唤醒工作对了中去执行{struct jz_battery *bat = platform_get_drvdata(pdev);
cancel_delayed_work (&bat->resume_work); //取消唤醒工作队列#ifdef CONFIG_SLPT // true 编译测试结构为真wake_lock (&bat->work_wake_lock); // 设置唤醒锁#elseschedule_delayed_work (&bat->resume_work, 0 * HZ); //执行唤醒工作队列#endifschedule_delayed_work(&bat->resume_work, 1 * HZ);return 0;}
紧接着看看唤醒工作函数,看看它的具体的代码;
static void jz_battery_resume_work(struct work_struct *work){
struct delayed_work *delayed_work = container_of(work, struct delayed_work, work);struct jz_battery *bat = container_of (delayed_work, struct jz_battery, resume_work);struct timeval battery_time;unsigned long time_delta;pr_info(LOG_TAG "%s\n", __FUNCTION__);
bat->status = get_status (bat); // 获得当前状态
#ifdef CONFIG_SLPT // true
bat->voltage = slpt_get_battery_voltage ();if (bat->voltage <= low_battery_voltage && bat->status != POWER_SUPPLY_STATUS_CHARGING) {
pr_info(LOG_TAG "SLPT: low capacity(%dmV), shutting down...\n", bat->voltage);bat->capacity_show = bat->capacity_real = 0;power_supply_changed (&bat->battery); // 上报电池信息while (1)
msleep(1000); // 延时1 second
}
#else
bat->voltage = get_adc_voltage (bat);
#endif
/** TODO: to create a table for SLPT capacity lookup specifically*/bat->capacity_real = lookup_capacity ( is_charging (bat->status), bat->voltage); // 获得电池容量百分比
do_gettimeofday (&battery_time); // 获得当前时间bat->resume_time = battery_time.tv_sec; // 单位second 保存当前时间pr_info(LOG_TAG "resume_time is %ld\n", battery_time.tv_sec);time_delta = bat->resume_time - bat->suspend_time; // 总共睡眠时间长pr_info(LOG_TAG "time_delta is %ld, %ldh %ldm %lds\n", time_delta, time_delta/3600,
(time_delta/60)%60, time_delta%60);
bat->next_scan_time = 15;
// 根据当前状态设置实际电压百分比和延时调度工作队列的时间
if (bat->status == POWER_SUPPLY_STATUS_FULL ) {
bat->capacity_show = bat->capacity_real = 100;
} else if (bat->status == POWER_SUPPLY_STATUS_CHARGING) {
if ((bat->capacity_real > bat->capacity_show) && (time_delta > 10 * 60)) {bat->capacity_show = bat->capacity_real;} elsejz_battery_capacity_rising (bat);
} else { /* DISCHARGING || NOT_CHARGING */
if ((bat->capacity_real < bat->capacity_show) && (time_delta > 10 * 60)) {
bat->capacity_show = bat->capacity_real;
} else
jz_battery_capacity_falling (bat);
}
// 上报电池信息并打印显示信息
power_supply_changed (&bat->battery);pr_info(LOG_TAG "%s, cap real: %d, cap show: %d, volt: %dmV, next %ds\n",
status2str (bat->status), bat->capacity_real, bat->capacity_show, bat->voltage, bat->next_scan_time);
schedule_delayed_work (&bat->work, bat->next_scan_time * HZ); // 调度执行到工作队列
external_cb_en = 1;
#ifndef CONFIG_SLPT // false
jz_battery_set_resume_time(bat);
#endif
wake_unlock (&bat->work_wake_lock); // 解锁工作队列唤醒锁
}
通过本函数的具体实现很容易看明白它最后又去调度工作队列了,又开始进入工作队列的循环中去进行工作了。看到这里基本的驱动代码也就看完了,如果感兴趣去可以再去看看细节部分的代码的具体的实现机制,在这里我就介绍到这里!