一、介绍在内核中使用printk可以将调试信息保存在log_buf缓冲区中,可以使用命令#cat/proc/kmsg将其中的数据打印出来buffer的data区,今天研究一下,自己写kmsg文件。我们将其命名为mymsg。2.查看内核中/proc/kmsg是怎么写的!在proc_misc.c(fs\proc)文件中:void__initproc_misc_init(void){......................structproc_dir_entry*entry;//创建procentryherekmsgentry=create_proc_entry("kmsg",S_IRUSR,&proc_root);if(entry) /*构建proc_fops结构*/ entry->proc_fops=&proc_kmsg_operations; ...??......................}在Kmsg.c(fs\proc)文件中:conststructfile_operationsproc_kmsg_operations={.read=kmsg_read,.poll=kmsg_poll,.open=kmsg_open,.release=kmsg_release,};在用户空间使用cat/proc/kmsg时,会调用kmsg_open,调用kmsg_read函数读取log_buf中的数据。复制到用户空间显示。3、在写之前,我们需要了解一下循环队列。循环队列是实际编程中非常有用的一种数据结构。它有以下特点:是一个首尾相连的FIFO数据结构,使用数组的线性空间,数据组织简单,可以快速知道队列是满的还是空的。可以非常快速地访问数据。出于简单和高效的原因,环形队列甚至在硬件中实现。环形队列广泛用于网络数据的发送和接收,不同程序之间的数据交换(如内核和应用程序之间交换大量数据,从硬件接收大量数据)都使用环形队列。3.1.环形队列的实现原理内存中没有环形结构,所以环形队列实际上是通过数组的线性空间来实现的。那么当数据到达终点时如何处理呢?它会回到0位置进行处理。这种折回是通过模运算执行的。因此,环形队列就是将数组元素q[0]和q[MAXN-1]在逻辑上连接起来,形成一个环形空间来存放队列。为了方便读写,还使用数组下标来表示队列的读写位置。头/尾。其中head指向可读位置,tail指向可写位置。环形队列的关键是判断队列是空的还是满的。当尾追上头时,队列满,当头追上尾时,队列空。但是怎么知道谁在追谁。还需要一些辅助手段来判断。判断环队列是空还是满有两种方式。(1)是加一个标志位标签。当头部追上尾部且队列为空时,设置tag=0。当尾追上头,队列已满时,设置tag=1。(2)限制尾赶上头,即队列尾节点和队列头节点之间至少有一个元素的空间。队列空:head==tail队列满:(tail+1)%MAXN==head4,编程#include#include#include#include#include#include#include#include#include#include#include#defineMYLOG_BUF_LEN1024staticcharmylog_buf[MYLOG_BUF_LEN];staticchartmp_buf[MYLOG_BUF_LEN];staticintmylog_r=0;r_0;staticintmylog_int=*睡眠队列初始化*/staticDECLARE_WAIT_QUEUE_HEAD(mymsg_waitq);/**判断环队列是否为空*返回0:表示不为空返回1:表示为空*/staticintis_mylog_empty(void){return(mylog_r==mylog_w);}/**判断是否为空ring队列满*返回0:表示不满返回1:表示满*/staticintis_mylog_full(void){return((mylog_w+1)%MYLOG_BUF_LEN==mylog_r);}/**读取时判断ring中的数据是否队列为空*返回0:表示不为空返回1:表示为空*/staticintis_mylog_empty_for_read(void){return(mylog_r_tmp==mylog_w);}/**循环队列中存储字符*输入:c字符单位:1byte*输出:无*/staticvoidmylog_putc(charc){if(is_mylog_full()){/*如果检测到当队列满时,丢弃数据*/mylog_r=(mylog_r+1)%MYLOG_BUF_LEN;/*mylog_r_tmp不能大于mylog_r*/if((mylog_r_tmp+1)%MYLOG_BUF_LEN==mylog_r)mylog_r_tmp=mylog_r;}mylog_buf[mylog_w]=c;/*当mylog_w=1023(mylog_w+1)%MYLOG_BUF_LEN=0时,回到队头,实现循环*/mylog_w=(mylog_w+1)%MYLOG_BUF_LEN;/*唤醒processwaitingfordata*/wake_up_interruptible(&mymsg_waitq);}/**从循环队列中读取字符*input:*punit:1byte*output:1表示成功*/staticintmylog_getc(char*p){/*判断是否有数据为空*/if(is_mylog_empty_for_read()){return0;}*p=mylog_buf[mylog_r_tmp];mylog_r_tmp=(mylog_r_tmp+1)%MYLOG_BUF_LEN;return1;}/**调用myprintk,用法同printf*/intmyprintk(constchar*fmt,...){va_listargs;inti;intj;va_start(args,fmt);i=vsnprintf(tmp_buf,INT_MAX,fmt,args);va_end(args);for(j=0;jf_flags&O_NONBLOCK)&&is_mylog_empty())return-EAGAIN;/*睡眠队列wait_event_interruptible(xxx,0)-->Hibernate*/error=wait_event_interruptible(mymsg_waitq,!is_mylog_empty_for_read());/*copy_to_user*/while(!error&&(mylog_getc(&c))&&iproc_fops=&proc_mymsg_operations;return0;}静态无效mymsg_exit(void){remove_proc_entry("mymsg",&proc_root);}module_init(mymsg_init);module_exit(mymsg_exit);/*向内核空间声明*/EXPORT_SYMBOL(myprintk);MODULE_LICENSE("GPL");:EXPORT_SYMBOL(myprintk)用于上述程序;意味着myprintk可以在整个内核空间使用使用方法:①externintmyprintk(constchar*fmt,...);声明②myprintk("first_drv_open:%d\n",++cnt);使用#include#include#include#include#include#include#include#包含#include#includestaticstructclass*firstdrv_class;staticstructclass_device*firstdrv_class_dev;volatileunsignedlong*gpfcon=NULL;volatileunsignedlong*gpfdat=NULL;externintmyprintk(constchar*fmt,...);staticintfirst_drv_open(structinode*inode,structfile*file){staticintcnt=0;myprintk("first_drv_open:%d\n",++cnt);/*配置GPF4,5,6为输出*/*gpfcon&=~((0x3<<(4*2))|(0x3<<(5*2))|(0x3<<(6*2)));*gpfcon|=((0x1<<(4*2))|(0x1<<(5*2))|(0x1<<(6*2)));return0;}staticssize_tfirst_drv_write(structfile*file,constchar__user*buf,size_tcount,loff_t*ppos){间隔;staticintcnt=0;myprintk("first_drv_write:%d\n",++cnt);copy_from_user(&val,buf,count);//copy_to_user();if(val==1){//光照*gpfdat&=~((1<<4)|(1<<5)|(1<<6));}else{//关灯*gpfdat|=(1<<4)|(1<<5)|(1<<6);}return0;}staticstructfile_operationsfirst_drv_fops={.owner=THIS_MODULE,/*这是一个宏,推送到编译模块时自动创建的__this_module变量*/.open=first_drv_open,.write=first_drv_write,};intmajor;staticintfirst_drv_init(void){myprintk("first_drv_init\n");major=register_chrdev(0,"first_drv",&first_drv_fops);//注册,先告诉内核drv_class=class_create(THIS_MODULE,"firstdrv");firstdrv_class_dev=class_devicedr,NULL,MKDEV(major,0),NULL,"xyz");/*/dev/xyz*/gpfcon=(volatileunsignedlong*)ioremap(0x56000050,16);gpfdat=gpfcon+1;return0;}staticvoidfirst_drv_exit(void){unregister_chrdev(major,"first_drv");//卸载class_device_unregister(firstdrv_class_dev);class_destroy(firstdrv_class);iounmap(gpfcon);}module_init(first_drv_init);module_exit(first_drv_exit);MODULE_LICENSE("GPL");6.在tty中测试效果#insmodmy_msg.ko#insmodfirst_drv.ko#cat/proc/mymsgmymsg_openmylog_r_tmp=0first_drv_init