利用/proc虚拟文件作虚拟设备

开发驱动程序时,身边没有硬件设备或者使用设备太麻烦,可以在/proc下创建一个虚拟文件来当作硬件设备,方便调试。/proc 文件系统包含了一些目录(用作组织信息的方式)和虚拟文件。虚拟文件可以向用户呈现内核中的一些信息,也可以用作一种从用户空间向内核发送信息的手段。与普通文件不同的是,这些虚拟文件的内容都是动态创建的,即需要使用的时候创建即可,不用时消亡,不占用磁盘空间。


驱动模块的设计


proc_list.c

/*****************************************
 *利用链表在/proc下创建缓冲文件模拟设备
 *Author:LC
 *Data:2014-5-14
 *****************************************/
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/list.h>
#include <linux/uaccess.h>
#include <linux/sched.h>

struct proc_head{
	struct list_head head;
	int file_size;
	};

//链表数据结构体
struct proc_item{
	char *str;
	struct list_head item;
	};

//链表头的指针
static struct proc_head *mylist;
static struct list_head my_head;

//proc文件的读函数
static int my_proc_read(char *page,char **start,off_t off,int count,int *eof,void *data)
{
	int ret = 0;
	//遍历链表,显示字符串
	//显示文件大小
	//list_for_each/list_each_entry
	//list_for_each_entry_reverse;
	struct proc_item *tmp;
	list_for_each_entry(tmp,&mylist->head,item){
		ret += sprintf(page + ret,"timer is %s\n",tmp->str);
			
		}
		ret += sprintf(page + ret,"file size is %d\n",mylist->file_size);
	return ret;
}


//写函数
static int my_proc_write(struct file *filp,const char __user *buf,unsigned long count,void *data)
{
	//分配一个新的proc_item
	//为proc_item->str分配空间
	//copy_from_user
	//INIT_LIST_HEAD();
	//list_add/list_add_tail
	//更新proc_head->file_size
	struct proc_item *new;
	
	new = (struct proc_item *)kzalloc(count+1,GFP_KERNEL);
	if(!new)
		return -ENOMEM;
	new->str = (char *)kzalloc(count+1,GFP_KERNEL);
	if(!new->str)
	{
		kfree(new);
		return -ENOMEM;
	}
	if(copy_from_user(new->str,buf,count)){
		kfree(new->str);
		kfree(new);
		return -EFAULT;
		}
	
	INIT_LIST_HEAD(&new->item);
	list_add_tail(&new->item,&mylist->head);
	mylist->file_size += count;


	return count;	
	
	
}

static int __init my_init(void)
{
	//分配并初始化proc_head
	//创建proc文件

	struct proc_dir_entry *file;
	mylist = (struct proc_head *)kzalloc(sizeof(*mylist), GFP_KERNEL);
	mylist->file_size = 0;
	INIT_LIST_HEAD(&mylist->head);

	file = create_proc_entry("test_list",0644, NULL);
	if (!file) {
		kfree(mylist);
		printk("Cannot create /proc/test_list");
		return -1;
	}
	file->read_proc = my_proc_read;
	file->write_proc = my_proc_write;

	return 0;
		
}

static int __exit my_exit(void)
{
	//remove_proc_entryl
	//释放整个链表
	//list_for_each_entry_safe
	//list_del();
	//kfree();
	//释放链表头kfree(mylist)

	struct proc_item *tmp1,*tmp2;
	remove_proc_entry("test_list",NULL);
	list_for_each_entry_safe(tmp1,tmp2,&mylist->head,item){
			list_del(&tmp1->item);
			kfree(tmp1->str);
			kfree(tmp1);
		
		}

	kfree(mylist);


	return 0;
}

module_init(my_init);
module_exit(my_exit);
MODULE_AUTHOR("LC");
MODULE_LICENSE("GPL");

利用my_proc_read函数从一个 /proc 项中读取数据(从内核空间到用户空间)。这个函数的原型如下:

static int my_proc_read(char *page,char **start,off_t off,int count,int *eof,void *data)

page 参数是这些数据写入到的位置,其中 count 定义了可以写入的最大字符数。在返回多页数据(通常一页是 4KB)时,我们需要使用startoff 参数。当所有数据全部写入之后,就需要设置 eof(文件结束参数),data为私有数据,这里一般为NULL。


这里使用链表存储数据,可以使用write_proc向/proc中写入多项数据

static int my_proc_write(struct file *filp,const char __user *buf,unsigned long count,void *data)

filp 参数实际上是一个打开文件结构(我们可以忽略这个参数)。buff 参数是传递给您的字符串数据。缓冲区地址实际上是一个用户空间的缓冲区,因此我们不能直接读取它。count 参数定义了在buff 中有多少数据要被写入。data为私有数据,默认为NULL就行。


创建并初始化proc文件


file = create_proc_entry("test_list",0644, NULL);


销毁链表

list_for_each_entry_safe(tmp1,tmp2,&mylist->head,item)


Makefile

obj-m := proc_list.o
KERNEL := /lib/modules/`uname -r`/build/

all:
	make -C $(KERNEL) M=`pwd` modules
install:
	make -C $(KERNEL) M=`pwd` modules_install
	depmod -A
clean:
	make -C $(KERNEL) M=`pwd` clean


编译完成后,生成proc_list.ko文件。挂载模块。

insmod proc_list.ko

挂载成功后,会在/proc下生成test_list文件,可以对这个文件进行读或者写操作。


读操作:

cat /proc/test_list

还没有写入数据之前,读不出信息。


echo > hello /proc/test_list

echo > world /proc/test_list


此时再cat

cat /proc/test_list

在终端上上得到如下信息

lc@LC--PC:$ cat /proc/test_list

hello

world


注:程序在rhel6.4系统下运行没问题,在ubuntu下运行好像需要在proc_list.c中加#include <linux/slab.h>头文件






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值