proc文件系统是一种伪文件系统,这种文件系统不存在于磁盘上,只存在于内存中,只有内核运行时才会动态生成里面的内容。这个文件系统通常挂载在/proc目录下,是内核向开发者到处信息的常用方式。
在系统中,有的这种文件也可写,这种在不重新编译内核以及不重启系统的情况下可以改变内核的行为。下面我们用一个实例来演示proc接口的使用
/*************************************************************************
> File Name: vser.c
> Author: longway.bai
> Mail: 953821672@qq.com
> Created Time: 2021年12月11日 星期六 19时12分04秒
> cat /proc/vser/info
************************************************************************/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kfifo.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/seq_file.h> //proc相关头文件
#include <linux/proc_fs.h>
#define VSER_MAJOR 256
#define VSER_MINOR 0
#define VSER_DEV_CNT 1
#define VSER_DEV_NAME "vser"
struct option {
unsigned int datab;
unsigned int parity;
unsigned int stopb;
};
/* 在vser结构体中添加两个struct proc_dir_entry类型的结构指针成员,我们要现在/proc目录下建立一个vser目录
* 再在vser目录下建立一个info文件*/
struct vser_dev {
unsigned int baud;
struct option opt;
struct cdev cdev;
struct proc_dir_entry *pdir; //创建的目录
struct proc_dir_entry *pdat; //创建的文件
};
static struct vser_dev vsdev;
static int dat_show(struct seq_file *m, void *v)
{
struct vser_dev *dev = m->private; //从私有数据中获得设备结构体地址,通过proc_create_data函数调用时(第五个参数)传递的
seq_printf(m, "baudrate: %d\n", dev->baud);
seq_printf(m, "frame format: %d%c%d\n", dev->opt.datab,\
dev->opt.parity == 0 ? 'N' : dev->opt.parity == 1 ? 'O':'E',\
dev->opt.stopb);
return 0;
}
static int proc_open(struct inode *inode, struct file *file)
{
/*proc_open调用single_open来辅助实现*/
return single_open(file, dat_show, PDE_DATA(inode));
}
static struct file_operations proc_ops = {
.owner = THIS_MODULE,
.open = proc_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek,
};
static int __init vser_init(void)
{
int ret;
dev_t dev;
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
ret = register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);
if(ret)
goto reg_err;
cdev_init(&vsdev.cdev, &proc_ops);
vsdev.cdev.owner = THIS_MODULE;
vsdev.baud = 115200;
vsdev.opt.datab = 8;
vsdev.opt.parity = 0;
vsdev.opt.stopb = 1;
ret = cdev_add(&vsdev.cdev, dev, VSER_DEV_CNT);
if (ret)
goto add_err;
/*以下是创建proc文件*/
vsdev.pdir = proc_mkdir("vser", NULL);//第一个参数表示目录的名字,第二个参数为NULL,表示在/proc目录下创建目录
if (!vsdev.pdir)
goto dir_err;
/* 第一个参数表示创建文件的名字,第二个参数表示权限,第三个参数是目录的目录项指针
* 第四个参数表示该文件的操作方法集合,第五个表示该文件的私有数据*/
vsdev.pdat = proc_create_data("info", 0, vsdev.pdir, &proc_ops, &vsdev);
if (!vsdev.pdat)
goto dat_err;
return 0;
dat_err:
remove_proc_entry("vser", NULL);
dir_err:
cdev_del(&vsdev.cdev);
add_err:
unregister_chrdev_region(dev,VSER_DEV_CNT);
reg_err:
return ret;
}
static void __exit vser_exit(void)
{
dev_t dev;
dev = MKDEV(VSER_MAJOR, VSER_MINOR);
remove_proc_entry("info", vsdev.pdir);
remove_proc_entry("vser", NULL);
cdev_del(&vsdev.cdev);
unregister_chrdev_region(dev,VSER_DEV_CNT);
}
module_init(vser_init);
module_exit(vser_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("longway<longway.bai@outlook.com>");
MODULE_DESCRIPTION("A simple module");
MODULE_ALIAS("virtual-serial");
驱动实现后,可以用以下命令来验证
#cat /proc/vser/info
baudrate: 115200
frame format: 8N1