20150429 调试分析之 imx257中proc下mymsg及myprintk的实现

20150429 调试分析之 imx257procmymsg的实现

2015-04-29 Lover雪儿


.实现在/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 <linux/module.h>
 2 #include <linux/kernel.h>
 3 #include <linux/fs.h>
 4 #include <linux/init.h>
 5 #include <linux/delay.h>
 6 #include <linux/irq.h>
 7 #include <asm/uaccess.h>
 8 #include <linux/proc_fs.h>
 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雪儿");
mymsg_1.c

 


.实现读写函数

由于上面我们的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 <linux/module.h>
 2 #include <linux/kernel.h>
 3 #include <linux/fs.h>
 4 #include <linux/init.h>
 5 #include <linux/delay.h>
 6 #include <linux/irq.h>
 7 #include <asm/uaccess.h>
 8 #include <linux/proc_fs.h>
 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雪儿");
mymsg_2.c

 


 

.模拟内存数据读取


既然要进行读取,自然就少不了数据的拷贝打印,此处我们利用数组来模拟数据的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", "abcdefghijklmn\n");    //模拟伪造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 <linux/module.h>
 2 #include <linux/kernel.h>
 3 #include <linux/fs.h>
 4 #include <linux/init.h>
 5 #include <linux/delay.h>
 6 #include <linux/irq.h>
 7 #include <asm/uaccess.h>
 8 #include <linux/proc_fs.h>
 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", "abcdefghijklmn\n");    //模拟伪造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 */
mymsg_3.c

 


.参考printk的函数,可以用于对消息的进行打印保存

现在我们来编写一个类似printkmyprintk函数,从而实现其他驱动程序调用myprintk将打印信息全部输出到/proc/mymsg,

便于统一对驱动的打印信息进行调试,不会收到其他的打印信息的干扰.

测试驱动程序我们选用以前imx257led驱动程序:

博客文章地址: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.csprinf函数,实现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<i; 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为空的话,则直接返回,否则让程序进入可中断的睡眠,

唤醒的条件是buff不空.当程序被唤醒时,则调用copy_to_user函数将数据拷贝到用户进程中进行打印出来.


8.修改测试驱动程序err_led.c.

首先外部引入myprintk函数,然后将测试驱动程序的printk全部修改为myprintk函数.

1 extern int myprintk(const char *fmt, ...); //引入外部声明
2 
3 static int key_open(struct inode *inode, struct file *file)
4 {
5     myprintk("<0>function open!\n\n");  //将printk修改未myprintk
6     return 0;
7 }

 


9.编译测试:

注意加载驱动的顺序.

加载mymsg.ko驱动程序

加载test/err_led.ko驱动程序:发现板子上的err_led灯闪烁,led闪烁完毕

读取 cat /proc/mymsg: 发现成功的打印出我们err_led要打印的消息,如下图

卸载test/err_led.ko:发现板子上的err_led等闪烁,等闪烁完毕

读取 cat /proc/mymsg: 再消息最末尾多了一条goodbye的消息,成功

卸载mymsg.ko驱动程序




附上驱动程序mymsg_4.c

  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/fs.h>
  4 #include <linux/init.h>
  5 #include <linux/delay.h>
  6 #include <linux/irq.h>
  7 #include <asm/uaccess.h>
  8 #include <linux/proc_fs.h>
  9 #include <linux/interrupt.h>
 10 
 11 
 12 #define MYLOG_BUF_LEN  1024
 13 
 14 //定义proc的entry结构体
 15 static struct proc_dir_entry *myentry;
 16 static char mylog_buf[MYLOG_BUF_LEN];        //数据缓冲区
 17 static char tmp_buf[MYLOG_BUF_LEN];            //数据缓冲区
 18 static int mylog_r = 0;
 19 static int mylog_w = 0;
 20 
 21 static DECLARE_WAIT_QUEUE_HEAD(mylog_wait);
 22 
 23 //判断是否为空
 24 static int is_mylog_empty(void)
 25 {
 26     return (mylog_r == mylog_w);
 27 }
 28 //判断是否已满
 29 static int is_mylog_full(void)
 30 {
 31     return (((mylog_w + 1) % MYLOG_BUF_LEN) == mylog_r);
 32 }
 33 //写入字符
 34 static void mylog_putc(char c)
 35 {
 36     if(is_mylog_full)
 37     {
 38         //丢弃一个数据
 39         mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;
 40     }
 41     mylog_buf[mylog_w] = c;
 42     mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN;
 43     
 44     /* 唤醒等待数据的进程 */
 45     wake_up_interruptible(&mylog_wait);
 46 }
 47 //读取字符
 48 static int mylog_getc(char *p)
 49 {
 50     if(is_mylog_empty())
 51         return 0;
 52     *p = mylog_buf[mylog_r];
 53     mylog_r = (mylog_r + 1) %  MYLOG_BUF_LEN;
 54     return 1;
 55 }
 56 
 57 //打印输出  参考vsprintf.c  的 sprintf
 58 int myprintk(const char *fmt, ...)
 59 {
 60     va_list args;
 61     int i,j;
 62     
 63     va_start(args, fmt);
 64     i = vsnprintf(tmp_buf, INT_MAX, fmt, args);
 65     va_end(args);
 66     for(j = 0; j<i; j++)
 67     {
 68         mylog_putc(tmp_buf[j]);
 69     }
 70     return 1;
 71 }
 72 EXPORT_SYMBOL(myprintk);
 73 
 74 //实现读函数     参考kmsg.c
 75 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
 76 {
 77     int error;
 78     int i = 0;        //所读的数据的个数
 79     char c;
 80     
 81     //以非阻塞打开,并且数据队列为空
 82     if ((file->f_flags & O_NONBLOCK) && is_mylog_empty())
 83         return -EAGAIN;
 84     
 85     //等待直到队列非空
 86     error = wait_event_interruptible(mylog_wait,!is_mylog_empty());
 87     
 88     /* copy_to_user 若是没错,获取字符串成功 */
 89     while( !error && (mylog_getc(&c)) && i < count ){
 90         error = __put_user(c, buf);            //等同copy_to_user
 91         buf++;
 92         i++;
 93     }
 94     if(!error)
 95         error = i;
 96     return error;
 97 }
 98 
 99 //定义file_operation结构体
100 static struct file_operations proc_mymsg_operations = {
101     .read = mymsg_read,
102 };
103 //入口函数
104 static int mymsg_init(void)
105 {
106     //sprintf(mylog_buf, "%s", "abcdefghijklmn\n");    //模拟伪造buf的数据
107     //创建proc的条目
108     myentry = create_proc_entry("mymsg",S_IRUSR,NULL);    //S_IRUSR:400 只读
109     
110     if(myentry)
111         myentry->proc_fops = &proc_mymsg_operations;
112     
113     
114     return 0;
115 }
116 //出口函数
117 static void mymsg_exit(void)
118 {
119     remove_proc_entry("mymsg", NULL);
120 }
121 
122 module_init(mymsg_init);
123 module_exit(mymsg_exit);
124 
125 MODULE_LICENSE("GPL");
126 MODULE_AUTHOR("Lover雪儿");
127 
128 
129 /*
130 1.环形缓冲区
131     空: R == W
132     写: buf[W] = val;
133         W = (W+1) % 10;
134     读: val = buf[R]
135         R = (R+1) % 10    
136     
137 
138 
139 */
mymsg_4.c

 


附上测试驱动程序err_led.c:

  1 #include<linux/cdev.h>
  2 #include<linux/module.h>
  3 #include<linux/types.h>
  4 #include<linux/fs.h>
  5 #include<linux/errno.h>
  6 #include<linux/mm.h>
  7 #include<linux/sched.h>
  8 #include<linux/init.h>
  9 #include<asm/io.h>
 10 #include<asm/system.h>
 11 #include<asm/uaccess.h>
 12 #include<linux/device.h>
 13 #include <linux/delay.h>
 14 
 15 #define Driver_NAME "err_led_dev"
 16 #define DEVICE_NAME "err_led_dev"
 17 
 18 static int major = 0;
 19 
 20 //auto to create device node
 21 static struct class *drv_class = NULL;
 22 static struct class_device *drv_class_dev = NULL;
 23 
 24 //寄存器基址;
 25 static unsigned long base_iomux;      //iomux基址 0X 43FA C000 -  0X 43FA FFFF
 26 static unsigned long base_gpio3;    //gpio3      0X 53FA 4000 -  0X 53FA 7FFF
 27 // MUX_CTL模式选择  配置寄存器
 28 #define MUX_CTL  (*(volatile unsigned long *)(base_iomux + 0x0060))
 29 // PAD_CTL GPIO常用功能设置
 30 #define PAD_CTL  (*(volatile unsigned long *)(base_iomux + 0x0270))
 31 // GPIO DR   数据寄存器  DR
 32 #define DR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0000))
 33 // GPIO GDIR 方向控制寄存器  GDIR
 34 #define GDIR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0004))
 35 
 36 
 37 extern int myprintk(const char *fmt, ...);
 38 
 39 static int key_open(struct inode *inode, struct file *file)
 40 {
 41     myprintk("<0>function open!\n\n");
 42     return 0;
 43 }
 44 
 45 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
 46 {
 47     return 0;
 48 }
 49 
 50 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
 51 {
 52     myprintk("<0>function write!\n\n");
 53     return 1;
 54 }
 55 
 56 static int  key_release(struct inode *inode, struct file *filp)
 57 {
 58     myprintk("<0>function write!\n\n");
 59     return 0;
 60 }
 61 
 62 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)
 63 {
 64     myprintk("<0>function ioctl!\n\n");
 65     return 0;
 66 }
 67 static struct file_operations key_fops = {
 68     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
 69     .open   =   key_open,
 70     .read   =   key_read,
 71     .write  =   key_write,
 72     .release=   key_release,
 73     .ioctl  =   key_ioctl,
 74 };
 75 
 76 void gpio_addr(void){
 77     myprintk("<0>addr base_iomux : %x \n",base_iomux);
 78     myprintk("<0>addr base_gpio3 : %x \n",base_gpio3);
 79     myprintk("<0>addr MUX_CTL : %x \n",&MUX_CTL);
 80     myprintk("<0>addr PAD_CTL : %x \n",&PAD_CTL);
 81     myprintk("<0>addr GDIR_GPIO3 : %x \n",&GDIR_GPIO3);
 82     myprintk("<0>addr DR_GPIO3 : %x \n",&DR_GPIO3);
 83 }
 84 
 85 void led_on_off(void){
 86     ssleep(1);
 87     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
 88     ssleep(1);
 89     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
 90     ssleep(1);
 91     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
 92     ssleep(1);
 93     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
 94     ssleep(1);
 95     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
 96     ssleep(1);
 97     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
 98     ssleep(1);
 99     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
100     ssleep(1);
101     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
102     ssleep(1);
103     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
104 }
105 
106 static int __init  key_irq_init(void)
107 {
108     myprintk("<0>\nHello,this is %s module!\n\n",Driver_NAME);
109     //register and mknod
110     major = register_chrdev(0,Driver_NAME,&key_fops);
111     drv_class = class_create(THIS_MODULE,Driver_NAME);
112     drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME);  /*/dev/key_query*/
113     
114     //IO端口申请 ioremap  可以直接通过指针来访问这些地址
115     base_iomux = ioremap(0x43FAC000,0xFFF);
116     base_gpio3 = ioremap(0x53FA4000,0xFFF);
117 
118     //MUX_CTL
119     MUX_CTL &= ~(0x07 << 0);    
120     MUX_CTL |= (0X05 << 0);    //设置为ALT5  GPIO3_23 ERR_LED
121     //PAD_CTL
122     PAD_CTL &= ~(0x01<<13 | 0x01<<3 | 0x03<<1 | 0x01<<0);   //1.8v 不需要上拉下拉  CMOS输出 slew rate
123     //GDIR_GPIO3    配置为输出模式
124     GDIR_GPIO3 &= ~(0x01 << 23);    
125     GDIR_GPIO3 |= (0x01 << 23);    //配置为输出模式    
126 
127     //DR_GPIO3        配置为输出0 点亮ERR_LED
128     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
129     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
130     gpio_addr();
131     led_on_off();
132     return 0; 
133 }
134                      
135 static void __exit key_irq_exit(void)
136 {
137     gpio_addr();
138     myprintk("<0>\nGoodbye,%s!\n\n",Driver_NAME);
139     led_on_off();
140 
141        unregister_chrdev(major,Driver_NAME);
142     device_unregister(drv_class_dev);
143     class_destroy(drv_class);
144     
145     //释放IO端口
146     iounmap(base_iomux);
147     iounmap(base_gpio3);
148 }
149 
150 
151 /* 这两行指定驱动程序的初始化函数和卸载函数 */
152 module_init(key_irq_init);
153 module_exit(key_irq_exit);
154 
155 /* 描述驱动程序的一些信息,不是必须的 */
156 MODULE_AUTHOR("Lover雪儿");
157 MODULE_VERSION("0.1.0");
158 MODULE_DESCRIPTION("IMX257 key Driver");
159 MODULE_LICENSE("GPL");
err_led.c

 



.完善读取,让进程读取到更加全面的内容

在前面的程序有一个问题,不知道大家发现没有,若是连续读cat /proc/mymsg的话,读的内容不全.

为了解决此问题,我们引入两套指针的方法,再次开辟一套指针用于专门读取内容

1.另外定义一套专门供读的指针

 

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_r_forread = 0;
7 static int mylog_w = 0;

 

 

 

2.增加一个专门用于读取消息的判断空函数

 

 1 //判断是否为空
 2 static int is_mylog_empty(void)
 3 {
 4     return (mylog_r == mylog_w);
 5 }
 6 
 7 //判断是否为空
 8 static int is_mylog_empty_forread(void)
 9 {
10     return (mylog_r_forread == mylog_w);
11 }

 

 

 

3.增加一个专门用于读取消息的读取字符函数

 

 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 }
10 
11 static int mylog_getc_forread(char *p)
12 {
13     if(is_mylog_empty_forread())
14         return 0;
15     *p = mylog_buf[mylog_r_forread];
16     mylog_r_forread = (mylog_r_forread + 1) %  MYLOG_BUF_LEN;
17     return 1;
18 }

 

 

 

4.修改mymsg_read函数中的一些函数修改为专门用于读取的函数

 

 1 //利用其他的驱动程序将printk函数写为myprintk,就会写入其中
 2 
 3 //实现读函数     参考kmsg.c
 4 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
 5 {
 6     int error;
 7     int i = 0;        //所读的数据的个数
 8     char c;
 9     
10     //以非阻塞打开,并且数据队列为空
11     if ((file->f_flags & O_NONBLOCK) && is_mylog_empty_forread())
12         return -EAGAIN;
13     
14     //等待直到队列非空
15     error = wait_event_interruptible(mylog_wait,!is_mylog_empty_forread());
16     
17     /* copy_to_user 若是没错,获取字符串成功 */
18     while( !error && (mylog_getc_forread(&c)) && i < count ){
19         error = __put_user(c, buf);            //等同copy_to_user
20         buf++;
21         i++;
22     }
23     if(!error)
24         error = i;
25     return error;
26 }

 

 

 

5.定义一个mymsg_open函数,用于重定位读指针

 1 static int mymsg_open(struct inode *inode, struct file  *file)
 2 {
 3     mylog_r_forread = mylog_r;
 4     return 0;
 5 }
 6 
 7 
 8 //定义file_operation结构体
 9 static struct file_operations proc_mymsg_operations = {
10     .read = mymsg_read,
11     .open = mymsg_open,
12 };

 

6.编译测试:

如下图所示:我们连续读取,所读取的内容都是全面的了

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

附上驱动程序mymsg_5.c

 

  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/fs.h>
  4 #include <linux/init.h>
  5 #include <linux/delay.h>
  6 #include <linux/irq.h>
  7 #include <asm/uaccess.h>
  8 #include <linux/proc_fs.h>
  9 #include <linux/interrupt.h>
 10 
 11 
 12 #define MYLOG_BUF_LEN  1024
 13 
 14 //定义proc的entry结构体
 15 static struct proc_dir_entry *myentry;
 16 static char mylog_buf[MYLOG_BUF_LEN];        //数据缓冲区
 17 static char tmp_buf[MYLOG_BUF_LEN];            //数据缓冲区
 18 static int mylog_r = 0;
 19 static int mylog_r_forread = 0;
 20 static int mylog_w = 0;
 21 
 22 static DECLARE_WAIT_QUEUE_HEAD(mylog_wait);
 23 
 24 //判断是否为空
 25 static int is_mylog_empty(void)
 26 {
 27     return (mylog_r == mylog_w);
 28 }
 29 
 30 //判断是否为空
 31 static int is_mylog_empty_forread(void)
 32 {
 33     return (mylog_r_forread == mylog_w);
 34 }
 35 
 36 //判断是否已满
 37 static int is_mylog_full(void)
 38 {
 39     return (((mylog_w + 1) % MYLOG_BUF_LEN) == mylog_r);
 40 }
 41 //写入字符
 42 static void mylog_putc(char c)
 43 {
 44     if(is_mylog_full())
 45     {
 46         //丢弃一个数据
 47         mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;
 48         if(((mylog_r_forread + 1) % MYLOG_BUF_LEN) == mylog_r)
 49             mylog_r_forread = mylog_r;
 50     }
 51     mylog_buf[mylog_w] = c;
 52     mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN;
 53     
 54     /* 唤醒等待数据的进程 */
 55     wake_up_interruptible(&mylog_wait);
 56 }
 57 //读取字符
 58 static int mylog_getc(char *p)
 59 {
 60     if(is_mylog_empty())
 61         return 0;
 62     *p = mylog_buf[mylog_r];
 63     mylog_r = (mylog_r + 1) %  MYLOG_BUF_LEN;
 64     return 1;
 65 }
 66 
 67 static int mylog_getc_forread(char *p)
 68 {
 69     if(is_mylog_empty_forread())
 70         return 0;
 71     *p = mylog_buf[mylog_r_forread];
 72     mylog_r_forread = (mylog_r_forread + 1) %  MYLOG_BUF_LEN;
 73     return 1;
 74 }
 75 
 76 
 77 //打印输出  参考vsprintf.c  的 sprintf
 78 int myprintk(const char *fmt, ...)
 79 {
 80     va_list args;
 81     int i,j;
 82     
 83     va_start(args, fmt);
 84     i = vsnprintf(tmp_buf, INT_MAX, fmt, args);
 85     va_end(args);
 86     for(j = 0; j<i; j++)
 87     {
 88         mylog_putc(tmp_buf[j]);
 89     }
 90     
 91     return 1;
 92 }
 93 
 94 //利用其他的驱动程序将printk函数写为myprintk,就会写入其中
 95 
 96 //实现读函数     参考kmsg.c
 97 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
 98 {
 99     int error;
100     int i = 0;        //所读的数据的个数
101     char c;
102     
103     //以非阻塞打开,并且数据队列为空
104     if ((file->f_flags & O_NONBLOCK) && is_mylog_empty_forread())
105         return -EAGAIN;
106     
107     //等待直到队列非空
108     error = wait_event_interruptible(mylog_wait,!is_mylog_empty_forread());
109     
110     /* copy_to_user 若是没错,获取字符串成功 */
111     while( !error && (mylog_getc_forread(&c)) && i < count ){
112         error = __put_user(c, buf);            //等同copy_to_user
113         buf++;
114         i++;
115     }
116     if(!error)
117         error = i;
118     return error;
119 }
120 
121 static int mymsg_open(struct inode *inode, struct file  *file)
122 {
123     mylog_r_forread = mylog_r;
124     return 0;
125 }
126 
127 
128 //定义file_operation结构体
129 static struct file_operations proc_mymsg_operations = {
130     .read = mymsg_read,
131     .open = mymsg_open,
132 };
133 //入口函数
134 static int mymsg_init(void)
135 {
136     //sprintf(mylog_buf, "%s", "abcdefghijklmn\n");    //模拟伪造buf的数据
137     //创建proc的条目
138     myentry = create_proc_entry("mymsg",S_IRUSR,NULL);    //S_IRUSR:400 只读
139     
140     if(myentry)
141         myentry->proc_fops = &proc_mymsg_operations;
142     
143     
144     return 0;
145 }
146 //出口函数
147 static void mymsg_exit(void)
148 {
149     remove_proc_entry("mymsg", NULL);
150 }
151 
152 module_init(mymsg_init);
153 module_exit(mymsg_exit);
154 
155 MODULE_LICENSE("GPL");
156 MODULE_AUTHOR("Lover雪儿");
157 
158 EXPORT_SYMBOL(myprintk);
159 
160 
161 /*
162 1.环形缓冲区
163     空: R == W
164     写: buf[W] = val;
165         W = (W+1) % 10;
166     读: val = buf[R]
167         R = (R+1) % 10    
168     
169 
170 
171 */
mymsg_5.c

 

 

 

附上测试程序err_led.c

 

  1 #include<linux/cdev.h>
  2 #include<linux/module.h>
  3 #include<linux/types.h>
  4 #include<linux/fs.h>
  5 #include<linux/errno.h>
  6 #include<linux/mm.h>
  7 #include<linux/sched.h>
  8 #include<linux/init.h>
  9 #include<asm/io.h>
 10 #include<asm/system.h>
 11 #include<asm/uaccess.h>
 12 #include<linux/device.h>
 13 #include <linux/delay.h>
 14 
 15 #define Driver_NAME "err_led_dev"
 16 #define DEVICE_NAME "err_led_dev"
 17 
 18 static int major = 0;
 19 
 20 //auto to create device node
 21 static struct class *drv_class = NULL;
 22 static struct class_device *drv_class_dev = NULL;
 23 
 24 //寄存器基址;
 25 static unsigned long base_iomux;      //iomux基址 0X 43FA C000 -  0X 43FA FFFF
 26 static unsigned long base_gpio3;    //gpio3      0X 53FA 4000 -  0X 53FA 7FFF
 27 // MUX_CTL模式选择  配置寄存器
 28 #define MUX_CTL  (*(volatile unsigned long *)(base_iomux + 0x0060))
 29 // PAD_CTL GPIO常用功能设置
 30 #define PAD_CTL  (*(volatile unsigned long *)(base_iomux + 0x0270))
 31 // GPIO DR   数据寄存器  DR
 32 #define DR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0000))
 33 // GPIO GDIR 方向控制寄存器  GDIR
 34 #define GDIR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0004))
 35 
 36 
 37 extern int myprintk(const char *fmt, ...);
 38 
 39 static int key_open(struct inode *inode, struct file *file)
 40 {
 41     myprintk("<0>function open!\n\n");
 42     return 0;
 43 }
 44 
 45 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
 46 {
 47     return 0;
 48 }
 49 
 50 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
 51 {
 52     myprintk("<0>function write!\n\n");
 53     return 1;
 54 }
 55 
 56 static int  key_release(struct inode *inode, struct file *filp)
 57 {
 58     myprintk("<0>function write!\n\n");
 59     return 0;
 60 }
 61 
 62 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)
 63 {
 64     myprintk("<0>function ioctl!\n\n");
 65     return 0;
 66 }
 67 static struct file_operations key_fops = {
 68     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
 69     .open   =   key_open,
 70     .read   =   key_read,
 71     .write  =   key_write,
 72     .release=   key_release,
 73     .ioctl  =   key_ioctl,
 74 };
 75 
 76 void gpio_addr(void){
 77     myprintk("<0>addr base_iomux : %x \n",base_iomux);
 78     myprintk("<0>addr base_gpio3 : %x \n",base_gpio3);
 79     myprintk("<0>addr MUX_CTL : %x \n",&MUX_CTL);
 80     myprintk("<0>addr PAD_CTL : %x \n",&PAD_CTL);
 81     myprintk("<0>addr GDIR_GPIO3 : %x \n",&GDIR_GPIO3);
 82     myprintk("<0>addr DR_GPIO3 : %x \n",&DR_GPIO3);
 83 }
 84 
 85 void led_on_off(void){
 86     ssleep(1);
 87     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
 88     ssleep(1);
 89     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
 90     ssleep(1);
 91     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
 92     ssleep(1);
 93     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
 94     ssleep(1);
 95     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
 96     ssleep(1);
 97     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
 98     ssleep(1);
 99     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
100     ssleep(1);
101     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
102     ssleep(1);
103     DR_GPIO3 |= (0x01 << 23);        //将GPIO2_23置1
104 }
105 
106 static int __init  key_irq_init(void)
107 {
108     myprintk("<0>\nHello,this is %s module!\n\n",Driver_NAME);
109     //register and mknod
110     major = register_chrdev(0,Driver_NAME,&key_fops);
111     drv_class = class_create(THIS_MODULE,Driver_NAME);
112     drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME);  /*/dev/key_query*/
113     
114     //IO端口申请 ioremap  可以直接通过指针来访问这些地址
115     base_iomux = ioremap(0x43FAC000,0xFFF);
116     base_gpio3 = ioremap(0x53FA4000,0xFFF);
117 
118     //MUX_CTL
119     MUX_CTL &= ~(0x07 << 0);    
120     MUX_CTL |= (0X05 << 0);    //设置为ALT5  GPIO3_23 ERR_LED
121     //PAD_CTL
122     PAD_CTL &= ~(0x01<<13 | 0x01<<3 | 0x03<<1 | 0x01<<0);   //1.8v 不需要上拉下拉  CMOS输出 slew rate
123     //GDIR_GPIO3    配置为输出模式
124     GDIR_GPIO3 &= ~(0x01 << 23);    
125     GDIR_GPIO3 |= (0x01 << 23);    //配置为输出模式    
126 
127     //DR_GPIO3        配置为输出0 点亮ERR_LED
128     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
129     DR_GPIO3 &= ~(0x01 << 23);        //将GPIO2_23清零
130     gpio_addr();
131     led_on_off();
132     return 0; 
133 }
134                      
135 static void __exit key_irq_exit(void)
136 {
137     gpio_addr();
138     myprintk("<0>\nGoodbye,%s!\n\n",Driver_NAME);
139     led_on_off();
140 
141        unregister_chrdev(major,Driver_NAME);
142     device_unregister(drv_class_dev);
143     class_destroy(drv_class);
144     
145     //释放IO端口
146     iounmap(base_iomux);
147     iounmap(base_gpio3);
148 }
149 
150 
151 /* 这两行指定驱动程序的初始化函数和卸载函数 */
152 module_init(key_irq_init);
153 module_exit(key_irq_exit);
154 
155 /* 描述驱动程序的一些信息,不是必须的 */
156 MODULE_AUTHOR("Lover雪儿");
157 MODULE_VERSION("0.1.0");
158 MODULE_DESCRIPTION("IMX257 key Driver");
159 MODULE_LICENSE("GPL");
err_Led.c

 

 

 

 

好啦,大功告成.

我们这样做的好处是,可以将某一个驱动程序的打印信息集中在某个文件中,从而是打印信息不会受其他的驱动程序所影响,便于后续的调试.

接下来,我们就开始学习,根据内核打印出来的错误消息进行排错,敬请期待吧...^_^






你可能感兴趣的:(print)