运用debugfs调试方法
DebugFS,顾名思义,是一种用于内核调试的虚拟文件系统,内核开发者通过debugfs和用户空间交换数据。类似的虚拟文件系统还有procfs和sysfs等,这几种虚拟文件系统都并不实际存储在硬盘上,而是Linux内核运行起来后才建立起来。
通常情况下,最常用的内核调试手段是printk。但printk并不是所有情况都好用,比如打印的数据可能过多,我们真正关心的数据在大量的输出里不是那么一目了然;或者我们在调试时可能需要修改某些内核变量,这种情况下printk就无能为力,而如果为了修改某个值重新编译内核或者驱动又过于低效,此时就需要一个临时的文件系统可以把我们需要关心的数据映射到用户空间。在过去,procfs可以实现这个目的,到了2.6时代,新引入的sysfs也同样可以实现,但不论是procfs或是sysfs,用它们来实现某些debug的需求,似乎偏离了它们创建的本意。比如procfs,其目的是反映进程的状态信息;而sysfs主要用于Linux设备模型。不论是procfs或是sysfs的接口应该保持相对稳定,因为用户态程序很可能会依赖它们。当然,如果我们只是临时借用procfs或者sysfs来作debug之用,在代码发布之前将相关调试代码删除也无不可。但如果相关的调试借口要在相当长的一段时间内存在于内核之中,就不太适合放在procfs和sysfs里了。故此,debugfs应运而生。
以上摘自互联网中,详解了debugfs的好处。我么知道在kernel里面许多大型模块都使用了debugfs调试,像qualcommdisplay中就使用了许多,可以打印mdp等内部各个参数的值,对调试大型模块起到了至关重要作用。
对于模块出现问题使用debugfs来调试是非常好的,前提是模块中有debugfs的加入。我们通常都是在出现问题之后才添加log来跟踪。记得有个蓝屏问题提case给高通,高通就要求在debugfs中catmdpstatues,来判断mdp有没有正常工作。
本文中以pm8921_chg.c详叙使用debugfs调试寄存器以及中断方法。绕dmesg,在debugfs中查看CHG的IRG还是非常重要的,
在模块中添加debugfs来实现自己的分析方法。当然要想在模块出现问题时就能使用自己添加的debugfs就ok了。
.
/*cat时被调用——读
data的值为寄存器地址,在debugfs_create_file()第四个参数中填入;
*val为cat的值
*/
staticintget_reg(void*data,u64*val)
{
intaddr=(int)data;
intret;
u8temp;
ret=pm8xxx_readb(the_chip->dev->parent,addr,&temp);
if(ret){
pr_err("pm8xxx_readbto%xvalue=%derrored=%d\n",
addr,temp,ret);
return-EAGAIN;
}
printk("%sdata=0x%02x,val=x%02x\n",__func__,addr,temp);
*val=temp;
return0;
}
/*echo时被调用——写
data值同上
val为写入的值
*/
staticintset_reg(void*data,u64val)
{
intaddr=(int)data;
intret;
u8temp;
temp=(u8)val;
printk("%sdata=0x%02x,val=x%02x\n",__func__,addr,temp);
ret=pm8xxx_writeb(the_chip->dev->parent,addr,temp);
if(ret){
pr_err("pm8xxx_writebto%xvalue=%derrored=%d\n",
addr,temp,ret);
return-EAGAIN;
}
return0;
}
DEFINE_SIMPLE_ATTRIBUTE(reg_fops,get_reg,set_reg,"0x%02llx\n");
/*获取中断状态文件操作只有读*/
staticintget_rt_status(void*data,u64*val)
{
inti=(int)data;
intret;
/*globalirqnumberispassedinviadata*/
ret=pm_chg_get_rt_status(the_chip,i);
printk("%si=%dret=%d\n",__func__,i,ret);
*val=ret;
return0;
}
DEFINE_SIMPLE_ATTRIBUTE(rt_fops,get_rt_status,NULL,"%llu\n");
staticvoidcreate_debugfs_entries(structpm8921_chg_chip*chip)
{
inti;
chip->dent=debugfs_create_dir("pm8921_chg",NULL);
if(IS_ERR(chip->dent)){
pr_err("pmicchargercouldntcreatedebugfsdir\n");
return;
}
debugfs_create_file("CHG_CNTRL",0644,chip->dent,
(void*)CHG_CNTRL,?_fops);
debugfs_create_file("CHG_CNTRL_2",0644,chip->dent,
(void*)CHG_CNTRL_2,?_fops);
debugfs_create_file("CHG_CNTRL_3",0644,chip->dent,
(void*)CHG_CNTRL_3,?_fops);
debugfs_create_file("PBL_ACCESS1",0644,chip->dent,
(void*)PBL_ACCESS1,?_fops);
debugfs_create_file("PBL_ACCESS2",0644,chip->dent,
(void*)PBL_ACCESS2,?_fops);
debugfs_create_file("SYS_CONFIG_1",0644,chip->dent,
(void*)SYS_CONFIG_1,?_fops);
debugfs_create_file("SYS_CONFIG_2",0644,chip->dent,
(void*)SYS_CONFIG_2,?_fops);
debugfs_create_file("CHG_VDD_MAX",0644,chip->dent,
(void*)CHG_VDD_MAX,?_fops);
debugfs_create_file("CHG_VDD_SAFE",0644,chip->dent,
(void*)CHG_VDD_SAFE,?_fops);
debugfs_create_file("CHG_VBAT_DET",0644,chip->dent,
(void*)CHG_VBAT_DET,?_fops);
debugfs_create_file("CHG_IBAT_MAX",0644,chip->dent,
(void*)CHG_IBAT_MAX,?_fops);
debugfs_create_file("CHG_IBAT_SAFE",0644,chip->dent,
(void*)CHG_IBAT_SAFE,?_fops);
debugfs_create_file("CHG_VIN_MIN",0644,chip->dent,
(void*)CHG_VIN_MIN,?_fops);
debugfs_create_file("CHG_VTRICKLE",0644,chip->dent,
(void*)CHG_VTRICKLE,?_fops);
debugfs_create_file("CHG_ITRICKLE",0644,chip->dent,
(void*)CHG_ITRICKLE,?_fops);
debugfs_create_file("CHG_ITERM",0644,chip->dent,
(void*)CHG_ITERM,?_fops);
debugfs_create_file("CHG_TCHG_MAX",0644,chip->dent,
(void*)CHG_TCHG_MAX,?_fops);
debugfs_create_file("CHG_TWDOG",0644,chip->dent,
(void*)CHG_TWDOG,?_fops);
debugfs_create_file("CHG_TEMP_THRESH",0644,chip->dent,
(void*)CHG_TEMP_THRESH,?_fops);
debugfs_create_file("CHG_COMP_OVR",0644,chip->dent,
(void*)CHG_COMP_OVR,?_fops);
debugfs_create_file("CHG_BUCK_CTRL_TEST1",0644,chip->dent,
(void*)CHG_BUCK_CTRL_TEST1,?_fops);
debugfs_create_file("CHG_BUCK_CTRL_TEST2",0644,chip->dent,
(void*)CHG_BUCK_CTRL_TEST2,?_fops);
debugfs_create_file("CHG_BUCK_CTRL_TEST3",0644,chip->dent,
(void*)CHG_BUCK_CTRL_TEST3,?_fops);
debugfs_create_file("CHG_TEST",0644,chip->dent,
(void*)CHG_TEST,?_fops);
debugfs_create_file("FSM_STATE",0644,chip->dent,NULL,
&fsm_fops);
debugfs_create_file("REGULATION_LOOP_CONTROL",0644,chip->dent,NULL,
?_loop_fops);
debugfs_create_file("BAT_WARM_ZONE",0644,chip->dent,
(void*)BAT_WARM_ZONE,&warm_cool_fops);
debugfs_create_file("BAT_COOL_ZONE",0644,chip->dent,
(void*)BAT_COOL_ZONE,&warm_cool_fops);
for(i=0;i<ARRAY_SIZE(chg_irq_data);i++){
if(chip->pmic_chg_irq[chg_irq_data[i].irq_id])
debugfs_create_file(chg_irq_data[i].name,0444,
chip->dent,
(void*)chg_irq_data[i].irq_id,
&rt_fops);
}
}
使用debugfs调试:
root@android:/#mkdir/data/debugfs
root@android:/#mount-tdebugfsdebugfs/data/debugfs
root@android:/#cd/data/debugfs/
root@android:/data/debugfs#cdpm8921
pm8921-bms/pm8921-dbg/pm8921_chg/
root@android:/data/debugfs#cdpm8921_chg/
root@android:/data/debugfs/pm8921_chg#
root@android:/data/debugfs/pm8921_chg#
root@android:/data/debugfs/pm8921_chg#ls-l
-r–r–r–rootroot02013-04-1815:25ATCDONE_IRQ
-r–r–r–rootroot02013-04-1815:25ATCFAIL_IRQ
-r–r–r–rootroot02013-04-1815:25BATFET_IRQ
-r–r–r–rootroot02013-04-1815:25BATTTEMP_COLD_IRQ
-r–r–r–rootroot02013-04-1815:25BATTTEMP_HOT_IRQ
-r–r–r–rootroot02013-04-1815:25BATT_INSERTED_IRQ
-r–r–r–rootroot02013-04-1815:25BATT_REMOVED_IRQ
-rw-r–r–rootroot02013-04-1815:25BAT_COOL_ZONE
-r–r–r–rootroot02013-04-1815:25BAT_TEMP_OK_IRQ
-rw-r–r–rootroot02013-04-1815:25BAT_WARM_ZONE
-r–r–r–rootroot02013-04-1815:25CHGDONE_IRQ
-r–r–r–rootroot02013-04-1815:25CHGFAIL_IRQ
-r–r–r–rootroot02013-04-1815:25CHGHOT_IRQ
-r–r–r–rootroot02013-04-1815:25CHGSTATE_IRQ
-r–r–r–rootroot02013-04-1815:25CHGWDOG_IRQ
-rw-r–r–rootroot02013-04-1815:25CHG_BUCK_CTRL_TEST1
-rw-r–r–rootroot02013-04-1815:25CHG_BUCK_CTRL_TEST2
-rw-r–r–rootroot02013-04-1815:25CHG_BUCK_CTRL_TEST3
-rw-r–r–rootroot02013-04-1815:25CHG_CNTRL
-rw-r–r–rootroot02013-04-1815:25CHG_CNTRL_2
-rw-r–r–rootroot02013-04-1815:25CHG_CNTRL_3
-rw-r–r–rootroot02013-04-1815:25CHG_COMP_OVR
-r–r–r–rootroot02013-04-1815:25CHG_GONE_IRQ
-rw-r–r–rootroot02013-04-1815:25CHG_IBAT_MAX
-rw-r–r–rootroot02013-04-1815:25CHG_IBAT_SAFE
-rw-r–r–rootroot02013-04-1815:25CHG_ITERM
-rw-r–r–rootroot02013-04-1815:25CHG_ITRICKLE
-rw-r–r–rootroot02013-04-1815:25CHG_TCHG_MAX
-rw-r–r–rootroot02013-04-1815:25CHG_TEMP_THRESH
-rw-r–r–rootroot02013-04-1815:25CHG_TEST
-rw-r–r–rootroot02013-04-1815:25CHG_TWDOG
-rw-r–r–rootroot02013-04-1815:25CHG_VBAT_DET
-rw-r–r–rootroot02013-04-1815:25CHG_VDD_MAX
-rw-r–r–rootroot02013-04-1815:25CHG_VDD_SAFE
-rw-r–r–rootroot02013-04-1815:25CHG_VIN_MIN
-rw-r–r–rootroot02013-04-1815:25CHG_VTRICKLE
-r–r–r–rootroot02013-04-1815:25COARSE_DET_LOW_IRQ
-r–r–r–rootroot02013-04-1815:25DCIN_OV_IRQ
-r–r–r–rootroot02013-04-1815:25DCIN_UV_IRQ
-r–r–r–rootroot02013-04-1815:25DCIN_VALID_IRQ
-r–r–r–rootroot02013-04-1815:25FASTCHG_IRQ
-rw-r–r–rootroot02013-04-1815:25FSM_STATE
-r–r–r–rootroot02013-04-1815:25LOOP_CHANGE_IRQ
-rw-r–r–rootroot02013-04-1815:25PBL_ACCESS1
-rw-r–r–rootroot02013-04-1815:25PBL_ACCESS2
-rw-r–r–rootroot02013-04-1815:25REGULATION_LOOP_CONTROL
-rw-r–r–rootroot02013-04-1815:25SYS_CONFIG_1
-rw-r–r–rootroot02013-04-1815:25SYS_CONFIG_2
-r–r–r–rootroot02013-04-1815:25TRKLCHG_IRQ
-r–r–r–rootroot02013-04-1815:25USBIN_OV_IRQ
-r–r–r–rootroot02013-04-1815:25USBIN_UV_IRQ
-r–r–r–rootroot02013-04-1815:25USBIN_VALID_IRQ
-r–r–r–rootroot02013-04-1815:25VBATDET_IRQ
-r–r–r–rootroot02013-04-1815:25VBATDET_LOW_IRQ
-r–r–r–rootroot02013-04-1815:25VBAT_OV_IRQ
-r–r–r–rootroot02013-04-1815:25VCP_IRQ
-r–r–r–rootroot02013-04-1815:25VDD_LOOP_IRQ
-r–r–r–rootroot02013-04-1815:25VREG_OV_IRQ
查看中断状态:
root@android:/data/debugfs/pm8921_chg#catFASTCHG_IRQ//查看是否在快速充电阶段调用get_reg();
1
dmesg:
<4>[95.057652]get_rt_statusi=14ret=1
查看寄存器的值:
root@android:/data/debugfs/pm8921_chg#catCHG_ITERM//查看充电截至电流寄存器Value调用set_reg();
0x07
dmesg:
<4>[275.319975]get_regdata=0x215,val=0x07
写入某个寄存器:
root@android:/data/debugfs/pm8921_chg#echo0x06>CHG_ITERM//将0x06写入CHG_ITERM调用get_rt_status();
0x07
dmesg:
<4>[476.374118]set_regdata=0x215,val=0x06
愈想得到,就愈要放手。放手是很难的,但是别无选择。