一.实现在/proc下面创建文件条目
1.定义proc_dir_entry结构体,已经file_operatioons结构体
1 //定义proc的entry结构体
2 static struct proc_dir_entry *myentry;
3
4 static struct file_operations proc_mymsg_operations = {
5 };
2.在入口函数中创建proc条目,并且关联file_operations结构体
1 static int mymsg_init(void)
2 {
3 //创建proc的目录
4 myentry = create_proc_entry('mymsg',S_IRUSR,NULL); //S_IRUSR:400 只读
5
6 if(myentry)
7 myentry->proc_fops = &proc_mymsg_operations;
8
9 return 0;
10 }
3.在出口函数中自然就是删除条目咯
1 static void mymsg_exit(void)
2 {
3 remove_proc_entry('mymsg', NULL);
4 }
4.编译测试代码,再/proc目录下创建了一个文件mymsg
附上驱动程序mymsg_1.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9
10 //定义proc的entry结构体
11 static struct proc_dir_entry *myentry;
12
13 static struct file_operations proc_mymsg_operations = {
14 };
15
16 static int mymsg_init(void)
17 {
18 //创建proc的目录
19 myentry = create_proc_entry('mymsg',S_IRUSR,NULL); //S_IRUSR:400 只读
20
21 if(myentry)
22 myentry->proc_fops = &proc_mymsg_operations;
23
24 return 0;
25 }
26
27 static void mymsg_exit(void)
28 {
29 remove_proc_entry('mymsg', NULL);
30 }
31
32 module_init(mymsg_init);
33 module_exit(mymsg_exit);
34
35 MODULE_LICENSE('GPL');
36 MODULE_AUTHOR('Lover雪儿');
二.实现读写函数
由于上面我们的file_operations结构体为空,所以我们自然就无法对/proc/mymsg进行读取,此处我们增加一个读函数.
1 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
2 {
3 printk('mymsg_read n');
4 return 0;
5 }
6
7 static struct file_operations proc_mymsg_operations = {
8 .read = mymsg_read,
9 };
编译加载完成后,我们使用cat命令对齐进行读取,结果如下所示:说明已经成功的进入了mymsg_read函数中.
附上驱动程序mymsg_2.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9
10 //定义proc的entry结构体
11 static struct proc_dir_entry *myentry;
12
13
14 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
15 {
16 printk('mymsg_read n');
17 return 0;
18 }
19
20
21 static struct file_operations proc_mymsg_operations = {
22 .read = mymsg_read,
23 };
24
25 static int mymsg_init(void)
26 {
27 //创建proc的目录
28 myentry = create_proc_entry('mymsg',S_IRUSR,NULL); //S_IRUSR:400 只读
29
30 if(myentry)
31 myentry->proc_fops = &proc_mymsg_operations;
32
33
34 return 0;
35 }
36
37 static void mymsg_exit(void)
38 {
39 remove_proc_entry('mymsg', NULL);
40 }
41
42 module_init(mymsg_init);
43 module_exit(mymsg_exit);
44
45 MODULE_LICENSE('GPL');
46 MODULE_AUTHOR('Lover雪儿');
三.模拟内存数据读取
既然要进行读取,自然就少不了数据的拷贝打印,此处我们利用数组来模拟数据的buff,然后再init函数中对其进行格式化数据,模拟写数据,
接着我们在mymsg_read函数中对其进行读取,看是否能成功读出数据.
1.定义一个内存buff数组
1 //定义proc的entry结构体
2 static struct proc_dir_entry *myentry;
3 static char mylog_buf[1024]; //数据缓冲区
2.在init函数中对其进行格式化字符串,模拟写数据
1 static int mymsg_init(void)
2 {
3 sprintf(mylog_buf, '%s', 'abcdefghijklmnn'); //模拟伪造buf的数据
4 //创建proc的目录
5 myentry = create_proc_entry('mymsg',S_IRUSR,NULL); //S_IRUSR:400 只读
6
7 if(myentry)
8 myentry->proc_fops = &proc_mymsg_operations;
9
10 return 0;
11 }
3.再mymsg_read函数中对其进行读取
1 //实现读函数
2 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
3 {
4 if(copy_to_user(buf, mylog_buf, 10));
5 return 10;
6 }
4.编译测试:发现成功的读出了数据.
附上驱动程序mymsg_3.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9
10 //定义proc的entry结构体
11 static struct proc_dir_entry *myentry;
12 static char mylog_buf[1024]; //数据缓冲区
13
14 //实现读函数
15 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
16 {
17 //int cnt;
18 //printk('mymsg_read n');
19 // 把mylog_buf的数据copy_to_user, return
20 //cnt = min(1024,count);
21 if(copy_to_user(buf, mylog_buf, 10));
22
23 return 10;
24 }
25
26 //定义file_operation结构体
27 static struct file_operations proc_mymsg_operations = {
28 .read = mymsg_read,
29 };
30
31 static int mymsg_init(void)
32 {
33 sprintf(mylog_buf, '%s', 'abcdefghijklmnn'); //模拟伪造buf的数据
34 //创建proc的目录
35 myentry = create_proc_entry('mymsg',S_IRUSR,NULL); //S_IRUSR:400 只读
36
37 if(myentry)
38 myentry->proc_fops = &proc_mymsg_operations;
39
40 return 0;
41 }
42
43 static void mymsg_exit(void)
44 {
45 remove_proc_entry('mymsg', NULL);
46 }
47
48 module_init(mymsg_init);
49 module_exit(mymsg_exit);
50
51 MODULE_LICENSE('GPL');
52 MODULE_AUTHOR('Lover雪儿');
53
54
55 /*
56 1.环形缓冲区
57 空: R == W
58 写: buf[W] = val;
59 W = (W+1) % 10;
60 读: val = buf[R]
61 R = (R+1) % 10
62 2.
63
64
65
66
67
68
69
70
71
72
73 */
四.参考printk的函数,可以用于对消息的进行打印保存
现在我们来编写一个类似printk的myprintk函数,从而实现其他驱动程序调用myprintk将打印信息全部输出到/proc/mymsg中,
便于统一对驱动的打印信息进行调试,不会收到其他的打印信息的干扰.
测试驱动程序我们选用以前imx257的led驱动程序:
博客文章地址:http://www.cnblogs.com/lihaiyan/p/4297923.html
当然,选择其他的驱动程序也一样,只要外部声明一下myprintk函数,然后将全部的printk替换为myprintk即可.
1.定义两个数据buff,以及读写指针,和一个等待队列
1 //定义proc的entry结构体
2 static struct proc_dir_entry *myentry;
3 static char mylog_buf[MYLOG_BUF_LEN]; //数据缓冲区
4 static char tmp_buf[MYLOG_BUF_LEN]; //数据缓冲区
5 static int mylog_r = 0;
6 static int mylog_w = 0;
7
8 static DECLARE_WAIT_QUEUE_HEAD(mylog_wait);
2.实现 判断buff空的函数
1 //判断是否为空
2 static int is_mylog_empty(void)
3 {
4 return (mylog_r == mylog_w);
5 }
3.实现 判断buff满的函数
1 //判断是否已满
2 static int is_mylog_full(void)
3 {
4 return (((mylog_w + 1) % MYLOG_BUF_LEN) == mylog_r);
5 }
4.实现 向buff写入字符的函数
1 //写入字符
2 static void mylog_putc(char c)
3 {
4 if(is_mylog_full)
5 {
6 //丢弃一个数据
7 mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;
8 }
9 mylog_buf[mylog_w] = c;
10 mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN;
11
12 /* 唤醒等待数据的进程 */
13 wake_up_interruptible(&mylog_wait);
14 }
函数除了向buff中写的功能外,还有一个重要的任务就是唤醒进程,从而再read函数中将数据打印出来
5.实现 读取buff字符的函数
1 //读取字符
2 static int mylog_getc(char *p)
3 {
4 if(is_mylog_empty())
5 return 0;
6 *p = mylog_buf[mylog_r];
7 mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;
8 return 1;
9 }
6.参考内核代码中的vsprintf.c的sprinf函数,实现myprintk函数,并且导出myprintk函数,供其他的程序使用
//打印输出 参考vsprintf.c 的 sprintf
int myprintk(const char *fmt, ...)
{
va_list args;
int i,j;
va_start(args, fmt);
i = vsnprintf(tmp_buf, INT_MAX, fmt, args);
va_end(args);
for(j = 0; j {
mylog_putc(tmp_buf[j]);
}
return 1;
}
EXPORT_SYMBOL(myprintk);
7.完善读函数
//实现读函数 参考kmsg.c
static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
{
int error;
int i = 0; //所读的数据的个数
char c;
//以非阻塞打开,并且数据队列为空
if ((file->f_flags & O_NONBLOCK) && is_mylog_empty())
return -EAGAIN;
//等待直到队列非空
error = wait_event_interruptible(mylog_wait,!is_mylog_empty());
/* copy_to_user 若是没错,获取字符串成功 */
while( !error && (mylog_getc(&c)) && i < count ){
error = __put_user(c, buf); //等同copy_to_user
buf++;
i++;
}
if(!error)
error = i;
return error;
}
当应用程序使用cat来读取/proc/mymsg时,如果程序是以非阻塞的方式开始,并且buff为空的话,则直接返回,否则让程序进入可中断的睡眠,