驱动调试之打印到proc虚拟文件2--编写程序

文件名为mymsg.c参考kmsg.c,printk.c

目的:想定义1个缓冲区如mulog_buf,在读函数里面把缓冲区里面的数据给/proc/mymsg,应用程序通过cat /proc/mymsg就会进入到内核态,发现是虚拟文件系统的文件,找到它的file_operation结构体,调用读函数,在读函数里面调用copy_to_user


#define MYLOG_BUF_LEN 1024


//全局指针
struct proc_dir_entry *myentry;

//缓冲区大小为1024字节
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;
static int mylog_w = 0;

//声明1个等待队列头
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)

{

//(写位置+1)%长度=读位置

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

//写入1个数据
static void mylog_putc(char c)

{

//如果缓冲区满了

if (is_mylog_full())
{
/* 丢弃一个数据 */扔掉的数据是读指针指向的数据,读指针向移移

mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;

if ((mylog_r_for_read + 1) % MYLOG_BUF_LEN == mylog_r)//1:15分钟视频有解析
{
mylog_r_for_read = mylog_r;//更新读指针
}
}

//写数据
mylog_buf[mylog_w] = c;
mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN;//写指针向后移1位


/* 唤醒等待数据的进程 */
    wake_up_interruptible(&mymsg_waitq);   /* 唤醒休眠的进程 */
}

//取数据
static int mylog_getc(char *p)

{

//如果缓冲区为空,返回0

if (is_mylog_empty())
{
return 0;
}
*p = mylog_buf[mylog_r];//非空取出数据
mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;//读指针向后移
return 1;
}

//读取字符
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;
}



//把打印信息输出到mylog_buf里面
int myprintk(const char *fmt, ...)
{
va_list args;
int i;
int j;


va_start(args, fmt);

//把fmt里面的信息输出到tmp_buf里面,i是tmp_buf中数据量的大小

i = vsnprintf(tmp_buf, INT_MAX, fmt, args);
va_end(args);
//把临时缓冲区的数据放到mylog_buf环形缓冲区
for (j = 0; j < i; j++)
mylog_putc(tmp_buf[j]);

return i;
}

//读函数

如果应用程序以非阻塞方式打开我们在proc下创建的文件mymsg,

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;


/* 把mylog_buf的数据copy_to_user, return */

//文件以非阻塞方式打开,并且环形缓冲区是空的就立刻返回

if ((file->f_flags & O_NONBLOCK) && is_mylog_empty_for_read())
return -EAGAIN;

加打印语句看卡在哪里
//printk("%s %d\n", __FUNCTION__, __LINE__);//打印哪一个函数,哪一行
//printk("count = %d\n", count);//打印需要读的数据数
//printk("mylog_r = %d\n", mylog_r);//读位置
//printk("mylog_w = %d\n", mylog_w);//写位置

//等待环形缓冲区非空 ,mymsg_waitq参数是队列,休眠时,(写数据时)以后吧你唤醒,到队列里找到进程唤醒,所以进程先放到1个队列。
error = wait_event_interruptible(mymsg_waitq, !is_mylog_empty_for_read());
条件不成立就会休眠

//环形后再次打印

//printk("%s %d\n", __FUNCTION__, __LINE__);
//printk("count = %d\n", count);
//printk("mylog_r = %d\n", mylog_r);
//printk("mylog_w = %d\n", mylog_w);


/* copy_to_user */吧数据拷贝到用户空间

//如果没有错误且获得字符串,i表示读到的数据数,还没有达到count值,先获得数据存在c中

mylog_getc_for_read

while (!error && (mylog_getc_for_read(&c)) && i < count) {
error = __put_user(c, buf);//把数据拷贝到用户空间
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;
}

//file_operation结构体(里面有打开函数和读函数)
const struct file_operations proc_mymsg_operations = {
.open = mymsg_open,
.read = mymsg_read,
};

//入口函数

创建了proc下面的1个条目(文件mymsg),以后读写这个文件的时候就会调用到proc_mymsg_operations这个结构体,调用里面的读函数

static int mymsg_init(void)
{ //第1个参数文件名字是mymsg,第2个参数是属性(只读),第3个参数是parent,表示proc这个根目录里面
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);

//myprintk函数要导出来给其他驱动调用
EXPORT_SYMBOL(myprintk);

//添加GPL 协议

MODULE_LICENSE("GPL");

#################################################

#################################################

另外1个驱动程序调用myprintk函数打印信息(用first_drv.c)

调用时声明是1个外部函数


在open函数里面调用myprintk函数打印信息


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值