一.实现在/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为空的话,则直接返回,否则让程序进入可中断的睡眠,
上一篇:调试分析之 根据内核报错信息PC指针分析错误
下一篇:iMX257引脚配置函数/内存读写函数
推荐阅读最新更新时间:2024-11-06 11:27
设计资源 培训 开发板 精华推荐
- LT1117CM-5 高效双电源的典型应用
- LT1764EQ 3.3 VIN 至 2.5 VOUT LDO 稳压器的典型应用
- PASADENA (MAXREFDES31#):3.3V和5V POE用电器件
- 使用 STMicroelectronics 的 R5975AD 的参考设计
- 用于背光手持计算机显示器的 LED 的高效低成本替代品
- LTC4066EUF 演示板、USB 电源管理器和锂离子充电器
- DC2062A-A,在 12V、3A ISO-7637-2 应用中用于 LT4363 -1 浪涌抑制器的演示板
- MC34071DR2G快速建立逆变器的典型应用
- LTC2945HMS 宽范围 -4V 至 -500V 负功率监视器的典型应用
- LTC3553-2 的典型应用 - 具有锂离子充电器、永远在线的 LDO 和降压稳压器的微功率 USB 电源管理器