20150429 调试分析之 imx257中proc下mymsg及myprintk的实现
发布日期:2021-06-29 14:51:52 浏览次数:2 分类:技术文章

本文共 24684 字,大约阅读时间需要 82 分钟。

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 
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雪儿");
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 
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雪儿");
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 
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, return20 //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 == W58 写: 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驱动程序:

博客文章地址:

当然,选择其他的驱动程序也一样,只要外部声明一下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  的 sprintfint 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

 

7.完善读函数

//实现读函数     参考kmsg.cstatic 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修改未myprintk6     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 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
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
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 == W132 写: 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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
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置1100 ssleep(1);101 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零102 ssleep(1);103 DR_GPIO3 |= (0x01 << 23); //将GPIO2_23置1104 }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 mknod110 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_CTL119 MUX_CTL &= ~(0x07 << 0); 120 MUX_CTL |= (0X05 << 0); //设置为ALT5 GPIO3_23 ERR_LED121 //PAD_CTL122 PAD_CTL &= ~(0x01<<13 | 0x01<<3 | 0x03<<1 | 0x01<<0); //1.8v 不需要上拉下拉 CMOS输出 slew rate123 //GDIR_GPIO3 配置为输出模式124 GDIR_GPIO3 &= ~(0x01 << 23); 125 GDIR_GPIO3 |= (0x01 << 23); //配置为输出模式 126 127 //DR_GPIO3 配置为输出0 点亮ERR_LED128 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_user20         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 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
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
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_user113 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 == W164 写: 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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
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置1100 ssleep(1);101 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零102 ssleep(1);103 DR_GPIO3 |= (0x01 << 23); //将GPIO2_23置1104 }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 mknod110 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_CTL119 MUX_CTL &= ~(0x07 << 0); 120 MUX_CTL |= (0X05 << 0); //设置为ALT5 GPIO3_23 ERR_LED121 //PAD_CTL122 PAD_CTL &= ~(0x01<<13 | 0x01<<3 | 0x03<<1 | 0x01<<0); //1.8v 不需要上拉下拉 CMOS输出 slew rate123 //GDIR_GPIO3 配置为输出模式124 GDIR_GPIO3 &= ~(0x01 << 23); 125 GDIR_GPIO3 |= (0x01 << 23); //配置为输出模式 126 127 //DR_GPIO3 配置为输出0 点亮ERR_LED128 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

 

 

 

 

好啦,大功告成.

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

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

转载地址:https://ciellee.blog.csdn.net/article/details/106022792 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:【高通SDM660平台 Android 10.0】(9) --- Qcom Camera Daemon 代码分析
下一篇:20150503 imx257下实现I2C驱动的四种方法

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月04日 20时29分17秒