驱动程序调试方法之printk——自制proc文件(二)

上一节的程序很振奋人心,我们自己实现了一个myprintk打印函数。但是这个函数存在一个致命的缺陷,那就是只能使用一次cat /proc/mymsg命令来读取mylog_buf的值。这是因为读到最后会出现:mylog_r == mylog_w,表示缓冲区为空,下一次就不能在读到数据了。在本节里面我们就着手来解决这个问题,我们要实现的就是每次使用 cat /proc/mymsg 时,都会从头打印。那么我们就需要将入口做一个拷贝,一个保存起来,一个进行变换。这样的话,当下一次读的时候,我们可以将保存的入口重新做个拷贝,然后让拷贝进行变化。具体程序如下:

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <asm/uaccess.h>

#include <asm/irq.h>

#include <asm/io.h>

#include <asm/arch/regs-gpio.h>

#include <asm/hardware.h>

#include <linux/proc_fs.h>

#define MYLOG_BUF_LEN 1024

struct proc_dir_entry *myentry;

static char mylog_buf[MYLOG_BUF_LEN];

static char tmp_buf[MYLOG_BUF_LEN];

static int mylog_r = 0;

static int mylog_r_for_read = 0;//这个用来拷贝mylog_r ,它将改变,但是mylog_r 不变

static int mylog_w = 0;

static DECLARE_WAIT_QUEUE_HEAD(mymsg_waitq);

static int is_mylog_empty(void)

{

return (mylog_r == mylog_w);

}

static int is_mylog_empty_for_read(void)

{

return (mylog_r_for_read == mylog_w);

}

static int is_mylog_full(void)

{

return ((mylog_w + 1)% MYLOG_BUF_LEN == mylog_r);

}

//这个函数是被myprintk函数调用的

static void mylog_putc(char c)

{

if (is_mylog_full())

{

mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;

/*加上下面三行的原因是:如果读的时候,也一直在调用printk写的话,

*当写的速度比较快的时候,可能会导致mylog_w超过mylog_r_for_read,

*这时就需要更新mylog_r_for_read,使mylog_r_for_read 指向新的入口

*当mylog_w超过入口mylog_r时,mylog_r会一直跟着更新的!

*/

if ((mylog_r_for_read + 1) % MYLOG_BUF_LEN == mylog_r)

{

mylog_r_for_read = mylog_r;

}

}

mylog_buf[mylog_w] = c;

mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN;

wake_up_interruptible(&mymsg_waitq);

}

static int mylog_getc_for_read(char *p)

{

if (is_mylog_empty_for_read())

{

return 0;

}

*p = mylog_buf[mylog_r_for_read];

mylog_r_for_read = (mylog_r_for_read + 1) % MYLOG_BUF_LEN;

return 1;

}

int myprintk(const char *fmt, ...)

{

va_list args;

int i;

int 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 i;

}

static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)

{

int error = 0;

int i = 0;

char c;

if ((file->f_flags & O_NONBLOCK) && is_mylog_empty_for_read())

return -EAGAIN;

error = wait_event_interruptible(mymsg_waitq, !is_mylog_empty_for_read());

/* copy_to_user */

while (!error && (mylog_getc_for_read(&c)) && i < count) {

error = __put_user(c, buf);

buf++;

i++;

}

if (!error)

error = i;

return error;

}

static int mymsg_open(struct inode *inode, struct file *file)

{

mylog_r_for_read = mylog_r;

return 0;

}

const struct file_operations proc_mymsg_operations = {

.open = mymsg_open,

.read = mymsg_read,

};

static int mymsg_init(void)

{

myentry = create_proc_entry("mymsg", S_IRUSR, &proc_root);

if (myentry)

myentry->proc_fops = &proc_mymsg_operations;

return 0;

}

static void mymsg_exit(void)

{

remove_proc_entry("mymsg", &proc_root);

}

module_init(mymsg_init);

module_exit(mymsg_exit);

EXPORT_SYMBOL(myprintk);

MODULE_LICENSE("GPL");

总结,关于这个函数,当我们在用户空间,使用命令:cat /proc/mymsg时,首先会调用open函数,在open函数里面会将入口做一个拷贝,然后拿出一份来作为变化量,另外一个作为入口不改变。这样,每次cat /proc/mymsg时,都会从入口处开始打印!

时间: 2024-12-15 06:49:27

驱动程序调试方法之printk——自制proc文件(二)的相关文章

驱动程序调试方法之printk——自制proc文件(一)

首先我们需要弄清楚proc机制,来看看fs/proc/proc_misc.c这个文件,从入口函数开始看: proc_misc_init(void) #ifdef CONFIG_PRINTK { struct proc_dir_entry *entry; entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);//这里创建了一个proc入口kmsg if (entry) entry->proc_fops = &p

驱动程序调试方法之printk——printk的原理与直接使用

1.基本原理 (1)在UBOOT里设置console=ttySAC0或者console=tty1 这里是设置控制终端,tySAC0 表示串口, tty1 表示lcd(2)内核用printk打印 内核就会根据命令行参数来找到对应的硬件操作函数,并将信息通过对应的硬件终端打印出来! 2.printk的使用 (1)printk函数的信息如何才能在终端显示出来 在内核代码include/linux/kernel.h中,定义了控制台的级别: extern int console_printk[]; #de

ARM驱动调试方法、思路总结、笔记

驱动程序的调试一. 打印: prink, 自制proc文件UBOOT传入console=ttySAC0 console=tty11. 内核处理UBOOT传入的参数console_setup add_preferred_console // 我想用名为"ttySAC0"的控制台,先记录下来 2. 硬件驱动的入口函数里: drivers/serial/s3c2410.c register_console(&s3c24xx_serial_console); 3. printk vpr

ubuntu/linux mint 创建proc文件的三种方法(四)

在做内核驱动开发的时候,可以使用/proc下的文件,获取相应的信息,以便调试. 大多数/proc下的文件是只读的,但为了示例的完整性,都提供了写方法. 方法一:使用create_proc_entry创建proc文件(简单,但写操作有缓冲区溢出的危险): 方法二:使用proc_create和seq_file创建proc文件(较方法三简洁): 方法三:使用proc_create_data和seq_file创建proc文件(较麻烦,但比较完整): 示例四:在proc文件中使用内核链表的一个示例(用的方

ubuntu/linux mint 创建proc文件的三种方法(一)

在做内核驱动开发的时候,可以使用/proc下的文件,获取相应的信息,以便调试. 大多数/proc下的文件是只读的,但为了示例的完整性,都提供了写方法. 方法一:使用create_proc_entry创建proc文件(简单,但写操作有缓冲区溢出的危险): 方法二:使用proc_create和seq_file创建proc文件(较方法三简洁): 方法三:使用proc_create_data和seq_file创建proc文件(较麻烦,但比较完整): 示例四:在proc文件中使用内核链表的一个示例(用的方

ubuntu/linux mint 创建proc文件的三种方法(三)

在做内核驱动开发的时候,可以使用/proc下的文件,获取相应的信息,以便调试. 大多数/proc下的文件是只读的,但为了示例的完整性,都提供了写方法. 方法一:使用create_proc_entry创建proc文件(简单,但写操作有缓冲区溢出的危险): 方法二:使用proc_create和seq_file创建proc文件(较方法三简洁): 方法三:使用proc_create_data和seq_file创建proc文件(较麻烦,但比较完整): 示例四:在proc文件中使用内核链表的一个示例(用的方

ubuntu/linux mint 创建proc文件的三种方法(二)

在做内核驱动开发的时候,可以使用/proc下的文件,获取相应的信息,以便调试. 大多数/proc下的文件是只读的,但为了示例的完整性,都提供了写方法. 方法一:使用create_proc_entry创建proc文件(简单,但写操作有缓冲区溢出的危险): 方法二:使用proc_create和seq_file创建proc文件(较方法三简洁): 方法三:使用proc_create_data和seq_file创建proc文件(较麻烦,但比较完整): 示例四:在proc文件中使用内核链表的一个示例(用的方

linux下core文件调试方法(转载)

转自于:http://blog.csdn.net/fcryuuhou/article/details/8507775 在程序遇到段错误不寻常退出时,一般是访问内存出错.但是不会给出程序哪里出现的问题,这个时候就需要core文件来帮助调试. 内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息).使用gdb来查看core文件,可以指示出导致程序出错的代码所在文件和行数. 1.core文件的生成开关和大小限制 1)使用ulimit -c命令可查看core文件的生成开关.若结果

Mex文件在VS2010中调试方法

matlab里面无法单步调试mex函数,故需转到VS上面调试,这里采用VS2010. 参考网上很多人写的方法但都很乱,杂,试了多次都没有成功.今天终于解决了,现把方法记录下来. 1.VC中编写Mex函数 新建一个win32 dll 空项目. 2.添加源文件Test.cpp,编写MEX函数,MEX函数编写方法这里不赘述了. 3.配置项目属性. 打开项目属性配置页,C++ -> 附加包含目录 加入MATLAB安装目录下的 \extern\include 路径. 连接器 -> 附加库目录 加入MAT