from:http://blog.csdn.net/eqwewr/article/details/8836948
运用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调试,像qualcomm display中就使用了许多,可以打印mdp等内部各个参数的值,对调试大型模块起到了至关重要作用。
对于模块出现问题使用debugfs来调试是非常好的,前提是模块中有debugfs的加入。我们通常都是在出现问题之后才添加log来跟踪。记得有个蓝屏问题提case给高通,高通就要求在debugfs中cat mdp statues,来判断mdp有没有正常工作。
本文中以pm8921_chg.c详叙使用debugfs调试寄存器以及中断方法。绕dmesg,在debugfs中查看CHG的IRG还是非常重要的,
在模块中添加debugfs来实现自己的分析方法。当然要想在模块出现问题时就能使用自己添加的debugfs就ok了。
.
/*cat时被调用——读
data的值为寄存器地址,在debugfs_create_file()第四个参数中填入;
*val为cat的值
*/
static int get_reg(void *data, u64 * val)
{
int addr = (int)data;
int ret;
u8 temp;
ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
if (ret) {
pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
addr, temp, ret);
return -EAGAIN;
}
printk("%s data = 0x%02x, val= x%02x\n",__func__,addr,temp);
*val = temp;
return 0;
}
/*echo时被调用——写
data值同上
val为写入的值
*/
static int set_reg(void *data, u64 val)
{
int addr = (int)data;
int ret;
u8 temp;
temp = (u8) val;
printk("%s data = 0x%02x, val= x%02x\n",__func__,addr,temp);
ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
if (ret) {
pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
addr, temp, ret);
return -EAGAIN;
}
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
/*获取中断状态文件操作只有读*/
static int get_rt_status(void *data, u64 * val)
{
int i = (int)data;
int ret;
/* global irq number is passed in via data */
ret = pm_chg_get_rt_status(the_chip, i);
printk("%s i=%d ret=%d \n",__func__,i,ret);
*val = ret;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
static void create_debugfs_entries(struct pm8921_chg_chip *chip)
{
int i;
chip->dent = debugfs_create_dir("pm8921_chg", NULL);
if (IS_ERR(chip->dent)) {
pr_err("pmic charger couldnt create debugfs dir\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 -t debugfs debugfs /data/debugfs
root@android:/ # cd /data/debugfs/
root@android:/data/debugfs # cd pm8921
pm8921-bms/ pm8921-dbg/ pm8921_chg/
root@android:/data/debugfs # cd pm8921_chg/
root@android:/data/debugfs/pm8921_chg #
root@android:/data/debugfs/pm8921_chg #
root@android:/data/debugfs/pm8921_chg # ls -l
-r--r--r-- root root 0 2013-04-18 15:25 ATCDONE_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 ATCFAIL_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATFET_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATTTEMP_COLD_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATTTEMP_HOT_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATT_INSERTED_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATT_REMOVED_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 BAT_COOL_ZONE
-r--r--r-- root root 0 2013-04-18 15:25 BAT_TEMP_OK_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 BAT_WARM_ZONE
-r--r--r-- root root 0 2013-04-18 15:25 CHGDONE_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 CHGFAIL_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 CHGHOT_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 CHGSTATE_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 CHGWDOG_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_BUCK_CTRL_TEST1
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_BUCK_CTRL_TEST2
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_BUCK_CTRL_TEST3
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_CNTRL
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_CNTRL_2
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_CNTRL_3
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_COMP_OVR
-r--r--r-- root root 0 2013-04-18 15:25 CHG_GONE_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_IBAT_MAX
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_IBAT_SAFE
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_ITERM
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_ITRICKLE
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_TCHG_MAX
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_TEMP_THRESH
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_TEST
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_TWDOG
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VBAT_DET
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VDD_MAX
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VDD_SAFE
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VIN_MIN
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VTRICKLE
-r--r--r-- root root 0 2013-04-18 15:25 COARSE_DET_LOW_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 DCIN_OV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 DCIN_UV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 DCIN_VALID_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 FASTCHG_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 FSM_STATE
-r--r--r-- root root 0 2013-04-18 15:25 LOOP_CHANGE_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 PBL_ACCESS1
-rw-r--r-- root root 0 2013-04-18 15:25 PBL_ACCESS2
-rw-r--r-- root root 0 2013-04-18 15:25 REGULATION_LOOP_CONTROL
-rw-r--r-- root root 0 2013-04-18 15:25 SYS_CONFIG_1
-rw-r--r-- root root 0 2013-04-18 15:25 SYS_CONFIG_2
-r--r--r-- root root 0 2013-04-18 15:25 TRKLCHG_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 USBIN_OV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 USBIN_UV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 USBIN_VALID_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VBATDET_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VBATDET_LOW_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VBAT_OV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VCP_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VDD_LOOP_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VREG_OV_IRQ
查看中断状态:
root@android:/data/debugfs/pm8921_chg # cat FASTCHG_IRQ //查看是否在快速充电阶段 调用get_reg();
1
dmesg:
<4>[ 95.057652] get_rt_status i=14 ret=1
查看寄存器的值:
root@android:/data/debugfs/pm8921_chg # cat CHG_ITERM //查看充电截至电流寄存器Value 调用set_reg();
0x07
dmesg:
<4>[ 275.319975] get_reg data = 0x215, val= 0x07
写入某个寄存器:
root@android:/data/debugfs/pm8921_chg # echo 0x06 > CHG_ITERM //将0x06写入CHG_ITERM 调用get_rt_status();
0x07
dmesg:
<4>[ 476.374118] set_reg data = 0x215, val= 0x06
如果android应用程序想要访问以上硬件时,就要使用java的JNI技术
1、JNI的全称为:Java Native Interface,java本地接口,设计目的是与C/C++实现本地交互,在java办不到的或者使用方便的代码段调用。
2、JNI的编写步骤
a、编写带有native声明的方法的java类
b、使用javac命令编译a中实现的类
c、javah -jni java类名生成扩展名为h的头文件
d、使用C/C++实现本地方法
e、将d中的本地方法生成动态链接库
f、OK
1、编写java程序
class HelloWorld{
public native void displayHelloWorld();
static{
System.loadLibrary("hello");
}
public static void main(String[] args){
new HelloWorld().displayHelloWorld();
}
}
javac hello.java
然后javah命令
javah -jni HelloWorld
生成.h头文件为
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: displayHelloWorld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif