linux驱动 seq_file学习测试实例
一、从内核中导出信息到用户空间有很多方法,可以自己去实现file_operations的read函数或者mmap函数,但是这种方法不够简单,而且也会有一些限制,比如一次read读取大于1页时,驱动里就不得不去进行复杂的缓冲区管理。为此,就需要学习一下seq_file的用法,为了更简单和方便,内核提供了single_xxx系列接口,它是对seq_file的进一步封装。
二、实际测试
测试驱动代码:
test.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
static struct dentry *seq_file_demo_dir;
static int seq_file_demo_show(struct seq_file *seq, void *v)
{
printk("%s %d \n",__FUNCTION__,__LINE__);
seq_printf(seq, "Hello World\n");
return 0;
}
static ssize_t seq_file_demo_write(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
u32 reg, val;
char kbuf[25];
//if (copy_from_user(kbuf, buf, count))
// return -EFAULT;
printk("%s %d \n",__FUNCTION__,__LINE__);
//printk("%s %d \n",kbuf,count);
return count;
}
static int seq_file_demo_open(struct inode *inode, struct file *file)
{
printk("%s %d \n",__FUNCTION__,__LINE__);
return single_open(file, &seq_file_demo_show, NULL);
}
static const struct file_operations seq_file_demo_fops = {
.owner = THIS_MODULE,
.open = seq_file_demo_open,
.read = seq_read,
.write = seq_file_demo_write,
.llseek = seq_lseek,
.release = single_release,
};
static int __init seq_file_demo_init(void)
{
printk("%s %d \n",__FUNCTION__,__LINE__);
seq_file_demo_dir = debugfs_create_file("seq_file_demo", 0444, NULL,
NULL, &seq_file_demo_fops);
return 0;
}
static void __exit seq_file_demo_exit(void)
{
printk("%s %d \n",__FUNCTION__,__LINE__);
if (seq_file_demo_dir)
debugfs_remove(seq_file_demo_dir);
}
module_init(seq_file_demo_init);
module_exit(seq_file_demo_exit);
MODULE_LICENSE("GPL");
Makefile
obj-m += test.o
KDIR := /disk/wwww/rk3288_project/firefly-rk3288/kernel
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o
三、测试结果
在/sys/kernel/debug/下创建了一个"seq_file_demo"
adb shell执行界面
串口打印信息log界面
四、当需要多个接口是也可以对代码进行如下简化
static int hdmi_##name##_open(struct inode *inode, struct file *file) \
{ \
return single_open(file, hdmi_##name##_show, inode->i_private); \
} \
\
static const struct file_operations hdmi_##name##_fops = { \
.owner = THIS_MODULE, \
.open = hdmi_##name##_open, \
.read = seq_read, \
.write = hdmi_##name##_write, \
.llseek = seq_lseek, \
.release = single_release, \
}
HDMI_DEBUG_ENTRY(regs_phy);
HDMI_DEBUG_ENTRY(regs_ctrl);