目录
简介
一、debugfs
API
二、程序源码
输出
简介
用户空间与内核的交互方式,使用copy_from_user(), copy_to_user().
除了这两种交互方式,内核还提供了其他高级的方式,对于写驱动来说很重要。有proc、sysfs、debugfs、netlink、ioctl。
本文学习debugfs
一、debugfs
在开发调试过程,通过输入cat file 文件命令,内核触发回调函数将所需要的信息提供给用户
内核配置:CONFIG_DEBUG_FS
查看是否已经挂载
# mount | grep -w debugfs
debugfs on /sys/kernel/debug type debugfs (rw,nosuid,nodev,noexec,relatime)
root@ubuntu:/sys/kernel/debug# ls
acpi ? cleancache ? ? ? device_component ?dma_pools ? ? ?error_injection ? ? gpio ? ? ? ? ?kprobes ?pmc_core ?regmap ? ? ?sleep_time ? ? ? ?sync ? ? virtio-ports ? ?zswap
bdi ? ?clear_warn_once ?devices_deferred ?dri ? ? ? ? ? ?extfrag ? ? ? ? ? ? hid ? ? ? ? ? mce ? ? ?pm_genpd ?regulator ? split_huge_pages ?tracing ?vmmemctl
block ?clk ? ? ? ? ? ? ?dma_buf ? ? ? ? ? dynamic_debug ?fault_around_bytes ?interconnect ?opp ? ? ?pwm ? ? ? remoteproc ?suspend_stats ? ? ttm ? ? ?wakeup_sources
cec ? ?devfreq ? ? ? ? ?dmaengine ? ? ? ? energy_model ? frontswap ? ? ? ? ? iosf_sb ? ? ? pinctrl ?ras ? ? ? sched ? ? ? swiotlb ? ? ? ? ? usb ? ? ?x86
API
debugfs_create_dir? 创建debugfs目录
debugfs_create_file 创建debugfs文件
debugfs_create_u32 自动创建内部回调函数,读写无符号32位数;其优点是不需要显示提供file_operations 结构体函数;
debugfs_create_bool 布尔类型的参数
debugfs_remove_recursive 删除文件,模块退出时没有调用此函数,继续访问debugfs文件,将引起oops错误。
二、程序源码
创建debugfs文件夹 dbgfs_simple_intf
创建两个文件,dbgfs_debug_level(显示一个值),dbgfs_show_drvctx(显示一组值)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/uaccess.h>
#include <linux/sched/signal.h>
//debugfs文件
#define OURMODNAME "dbgfs_simple_intf"
MODULE_AUTHOR("wy");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_VERSION("0.1");
/* Module parameters */
static int cause_an_oops;
module_param(cause_an_oops, int, 0644);
MODULE_PARM_DESC(cause_an_oops,
//目录
static struct dentry *gparent;
//互斥体
DEFINE_MUTEX(mtx);
//参数结构体
struct drv_ctx {
int tx, rx, err, myword, power;
u32 config1;
u32 config2;
u64 config3; /* updated to the 'jiffies' value ... */
#define MAXBYTES 128
char oursecret[MAXBYTES];
};
static struct drv_ctx *gdrvctx;
//debug_level参数
static int debug_level;
//文件名
#define DBGFS_FILE2 "dbgfs_debug_level"
#define DBGFS_FILE1 "dbgfs_show_drvctx"
//当read函数触发时,自动调用此函数
static ssize_t dbgfs_show_drvctx(struct file *filp, char __user *ubuf,
size_t count, loff_t *fpos)
{
struct drv_ctx *data = (struct drv_ctx *)filp->f_inode->i_private;
#define MAXUPASS 256 // 内核的栈非常小
char locbuf[MAXUPASS];
if (mutex_lock_interruptible(&mtx))
return -ERESTARTSYS;
//config参数值修改
data->config3 = jiffies;
//打包参数值
snprintf(locbuf, MAXUPASS - 1,
"prodname:%s\n"
"tx:%d,rx:%d,err:%d,myword:%d,power:%d\n"
"config1:0x%x,config2:0x%x,config3:0x%llx (%llu)\n"
"oursecret:%s\n",
OURMODNAME,
data->tx, data->rx, data->err, data->myword, data->power,
data->config1, data->config2, data->config3, data->config3,
data->oursecret);
mutex_unlock(&mtx);
//将参数值传递给user,对copy_to_user的封装
return simple_read_from_buffer(ubuf, MAXUPASS, fpos, locbuf,
strlen(locbuf));
}
//fops read方法
static const struct file_operations dbgfs_drvctx_fops = {
.read = dbgfs_show_drvctx,
};
//结构体内存分配,并赋初始值
static struct drv_ctx *alloc_init_drvctx(void)
{
struct drv_ctx *drvctx = NULL;
drvctx = kzalloc(sizeof(struct drv_ctx), GFP_KERNEL);
if (!drvctx)
return ERR_PTR(-ENOMEM);
drvctx->config1 = 0x0;
drvctx->config2 = 0x48524a5f;
drvctx->config3 = jiffies;
drvctx->power = 1;
strncpy(drvctx->oursecret, "AhA yyy", 8);
pr_info("allocated and init the driver context structure\n");
return drvctx;
}
//模块入口函数
static int __init debugfs_simple_intf_init(void)
{
int stat = 0;
struct dentry *file1, *file2;
//检查是否开启debugfs
if (!IS_ENABLED(CONFIG_DEBUG_FS)) {
return -EINVAL;
}
//创建目录
gparent = debugfs_create_dir(OURMODNAME, NULL);
if (!gparent) {
goto out_fail_1;
}
//创建ctx并赋初值
gdrvctx = alloc_init_drvctx();
if (IS_ERR(gdrvctx)) {
goto out_fail_2;
}
//创建文件1
file1 = debugfs_create_file(DBGFS_FILE1, 0440, gparent, (void *)gdrvctx, &dbgfs_drvctx_fops);
if (!file1) {
goto out_fail_3;
}
//创建文件2 创建的函数使用与第一个不同
file2 = debugfs_create_u32(DBGFS_FILE2, 0644, gparent, &debug_level);
if (!file2) {
goto out_fail_3;
}
return 0;
out_fail_3:
kfree(gdrvctx);
out_fail_2:
debugfs_remove_recursive(gparent);
out_fail_1:
return stat;
}
static void __exit debugfs_simple_intf_cleanup(void)
{
kfree(gdrvctx);
if (!cause_an_oops)//参数控制循环释放引起错误
debugfs_remove_recursive(gparent);
}
module_init(debugfs_simple_intf_init);
module_exit(debugfs_simple_intf_cleanup);
输出
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# ls -l
total 0
-rw-r--r-- 1 root root 0 Sep 30 01:37 dbgfs_debug_level
-r--r----- 1 root root 0 Sep 30 01:37 dbgfs_show_drvctx
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# cat dbgfs_show_drvctx
prodname:dbgfs_simple_intf
tx:0,rx:0,err:0,myword:0,power:1
config1:0x0,config2:0x48524a5f,config3:0x10053c457 (4300457047)
oursecret:AhA yyy
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf#
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf#
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf#
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# cat dbgfs_debug_level
0
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# echo 1 > dbgfs_debug_level
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# cat dbgfs_debug_level
1
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# echo 10 > dbgfs_debug_level
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# cat dbgfs_debug_level
10
参考:
https://course.0voice.com/v1/course/intro?courseId=2&agentId=0
|