【版权声明:转载请保留出处:blog.csdn.net/gentleliu。邮箱:shallnew*163.com】
在 Linux 设备驱动程序中,驱动工程师自定义/proc 节点以向外界传递信息的方法还是比较常见的。
下列函数用于创建/proc 目录:
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
下列函数创建/proc 节点:
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,struct proc_dir_entry *parent);
struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void * data);
结合 create_proc_entry()和 proc_mkdir(),可用于先在/proc 下创建一个目录,而后在该目录下创建一个文件。
可用如下函数删除/proc 节点:
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
上述函数各返回值的 proc_dir_entry 结构体中包含了/proc 节点的读函数指针(read_proc_t*read_proc)、写函数指针(write_proc_t *write_proc)以及父节点、子节点信息等。/proc 节点的读写函数的类型分别为:
typedef int (read_proc_t)(char *page, char **start, off_t off,int count, int *eof, void *data);
typedef int (write_proc_t)(struct file *file, const char __user *buffer,unsigned long count, void *data);
这两函数需要我们来实现。
读函数中 page 指针指向用于写入数据的缓冲区,start 用于返回实际的数据写到内存页的位置,eof 是用于返回读结束标志,offset 是读的偏移,count 是要读的数据长度。start 参数比较复杂,对于/proc 只包含简单数据的情况,通常不需要在读函数中设置*start,意味着内核将认为数据保存在内存页偏移 0 的地方。如果将*start 设置为非 0 值,意味着内核将认为*start 指向的数据是 offset 偏移处的数据。写函数与 file_operations 中的 write()成员类似,需要一次从用户缓冲区到内存空间的复制过程。
下面给一个示例,该示例只是简单的在/proc目录下创建一个文件夹和文件,用户可以在用户态向该文件写入文件,并读出文件内容。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#define USER_ROOT_DIR "slndir"
#define USER_ENTRY "slnfile"
struct proc_dir_entry *root_dir, *entry;
char kbuff[1024];
static int proc_write(struct file *filep, const char __user *buffer,
unsigned long len, void *data)
{
if (copy_from_user(kbuff, buffer, len)) {
return -1;
}
kbuff[len] = '\0';
return len;
}
static int proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len;
len = sprintf(page, "%s", kbuff);
return len;
}
static int __init sln_init(void)
{
printk("Hello, %s\n", __func__);
root_dir = proc_mkdir(USER_ROOT_DIR, NULL);
if (NULL == root_dir) {
printk("proc_mkdir create dir %s failed!\n", USER_ROOT_DIR);
return -1;
}
entry = create_proc_entry(USER_ENTRY, 0666, root_dir);
if (NULL == entry) {
printk("create_proc_entry create entry %s failed\n", USER_ENTRY);
goto err;
}
entry->read_proc = proc_read;
entry->write_proc = proc_write;
return 0;
err:
remove_proc_entry(USER_ROOT_DIR, NULL);
return -1;
}
static void __exit sln_exit(void)
{
printk("Bye, %s\n", __func__);
remove_proc_entry(USER_ENTRY, root_dir);
remove_proc_entry(USER_ROOT_DIR, NULL);
}
module_init(sln_init);
module_exit(sln_exit);
MODULE_LICENSE("GPL");