PROC虚拟文件系统自制kmsg文件存储打印信息

PROC虚拟文件系统自制kmsg文件存储打印信息
像内核proc文件系统的dmsg命令一样,prink内核打印的信息都会存储在/proc/kmsg文件里,我们cat它就能读出所有的内核打印信息,但是该文件类似于管道,读完了就读走了,不会再有,除非有printk函数继续向里面写入东西。而dmsg会打印出所有log_buf里面的东西,应该是开机以来所有的printk打印出来的。
在这里先说明下我的软硬件平台:
硬件: 友善之臂的mini2440,淘宝里面嵌入式家园那里买的(绝对不是打广告,而是详细说明自己的板子)
软件:linux-2.6.32.2

好,现在进入我们的话题:
在我们进行驱动调试的时候,我不想用printk函数,因为这样会和其他内核打印出来的信息混在一块。所以我希望在建立自己的/proc/mymsg文件,使用自己的打印函数myprintk,需要查看我打印出来的驱动调试信息时只要简单的cat /proc/mymsg,里面全是myprintk打印出来的东西。
1.写mymsg的驱动
贴出源码:

Ubuntu_myproc_dmsg.c
#include
#include
#include
#include
#include
#include
#include
#include

#defineUBUNTU_LOG_BUF_LENGTH 1024//?·D??o3???3¤?è

staticDECLARE_WAIT_QUEUE_HEAD(ubuntu_log_waitq);

staticchar ubuntu_log_buf[UBUNTU_LOG_BUF_LENGTH]; //?·D??o3???êy×é
staticchar tmp_buf[UBUNTU_LOG_BUF_LENGTH]; //?Y′?
staticint ubuntu_log_rp=0; //?·D??o3????á????, 2?±?
staticint ubuntu_log_wp = 0; //?·D??o3???D′????
staticint ubuntu_log_rp_for_read = 0; //?·D??o3????á????£??aá??áè?êy?Y£??é±?



/*?D???·D??o3???ê?·??ú*/
staticint ubuntu_Is_log_full(void)
{
return ((ubuntu_log_wp + 1) %UBUNTU_LOG_BUF_LENGTH == ubuntu_log_rp);
}

/*?D???·D??o3???ê?·???*/
staticint ubuntu_Is_log_empty(void)
{
return (ubuntu_log_rp ==ubuntu_log_wp);
【PROC虚拟文件系统自制kmsg文件存储打印信息】}

staticint ubuntu_Is_log_empty_for_read(void)
{
return (ubuntu_log_rp_for_read ==ubuntu_log_wp);
}



/*?ò?·D??o3????úD′è?ò???×?·?êy?Y */
staticvoid ubuntu_log_putchar(char c)
{
if(ubuntu_Is_log_full())//è?1??úá?
{
/*?a?úò???êy?Y*/
ubuntu_log_rp += 1;

if ((ubuntu_log_rp_for_read+ 1) % UBUNTU_LOG_BUF_LENGTH == ubuntu_log_rp)
{
ubuntu_log_rp_for_read= ubuntu_log_rp;
}

}

ubuntu_log_buf[ubuntu_log_wp] = c;
ubuntu_log_wp = (ubuntu_log_wp + 1) %UBUNTU_LOG_BUF_LENGTH;

}



/*????ê??ˉμ?êy?YD′è??Y′??o3????D
×¢òa: óéóú?a??oˉêyòa±????????t?ùó?
?ùò????°??2??ü?óstatic
2???: sprintf oˉêy*/

staticint myprintk(const char* fmt , ...)
{
va_list args;
int i;
int j;

/* ·?è??Y′? */
va_start(args, fmt);
i = vsnprintf(tmp_buf, INT_MAX, fmt,args);
va_end(args);

/* ?ù·?è??·D??o3??? */
for(j = 0 ; j < i ; j++)
{
ubuntu_log_putchar(tmp_buf[j] );
}

return i;
}


/*μ?3???oˉêy */
EXPORT_SYMBOL(myprintk);






/*′ó?·D??o3????á3?ò???êy?Y */
staticint ubuntu_log_getchar(char *p)
{
if( ubuntu_Is_log_empty( ))//è?1?ê???£?·μ???áè?꧰ü
{
return 0;
}
*p = ubuntu_log_buf[ubuntu_log_rp];
ubuntu_log_rp = (ubuntu_log_rp + 1) %UBUNTU_LOG_BUF_LENGTH;
return 1;
}
staticint ubuntu_log_getchar_for_read(char *p)
{
if( ubuntu_Is_log_empty_for_read( ))//è?1?ê???£?·μ???áè?꧰ü
{
return 0;
}
*p =ubuntu_log_buf[ubuntu_log_rp_for_read];
ubuntu_log_rp_for_read =(ubuntu_log_rp_for_read + 1) % UBUNTU_LOG_BUF_LENGTH;
return 1;
}




staticssize_t ubuntu_kmsg_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) && ubuntu_Is_log_empty_for_read())//è?1?·?×èè?′ò?a2¢?ò?·D??o3????a??
return -EAGAIN;

error =wait_event_interruptible(ubuntu_log_waitq, !ubuntu_Is_log_empty_for_read()); //???ò×èè?

/* ??±′μ?ó??§???? */
while( !error &&(ubuntu_log_getchar_for_read(&c))&& (i < count))
{
error = __put_user(c ,buf);
buf++;
i++;
}

if(!error)
error = i;

return error;
}


staticint ubuntu_kmsg_open(struct inode * inode, struct file * file)
{
ubuntu_log_rp_for_read =ubuntu_log_rp;
return 0;
}


staticconst struct file_operations ubuntu_proc_kmsg_operations = {
.read=ubuntu_kmsg_read,
.open=ubuntu_kmsg_open,
};


staticint __init ubuntu_mymsg_init(void)
{

proc_create("mymsg",S_IRUSR, NULL, &ubuntu_proc_kmsg_operations);
return 0;
}

staticvoid __exit ubuntu_mymsg_exit(void)
{
remove_proc_entry("mymsg",NULL );
}



#defineDRIVER_VERSION "v1.0"
#defineDRIVER_AUTHOR "Guoyu "
#defineDRIVER_DESC "MINI2440 FOR simple proc dmsg driver"

module_init(ubuntu_mymsg_init);
module_exit(ubuntu_mymsg_exit);


MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

2.写测试程序的驱动
贴出源码
First_drv.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include


//ía2?oˉêy,óD??óD°üo???í·???t£????üó?extern
externint myprintk(const char *fmt, ...);

staticstruct class *firstdrv_class;
staticstruct class_device*firstdrv_class_dev;

volatileunsigned long *gpbcon = NULL;
volatileunsigned long *gpbdat = NULL;

//#defineDBG_PRINTK printk
//#defineDBG_PRINTK(x...)//è¥μ?′òó?ó???

staticint first_drv_open(struct inode *inode, struct file *file)
{
static int cnt = 0;
myprintk("first_drv_open :%d\n", ++cnt);
//printk("first_drv_open\n");
/*
* LED1,LED2,LED4??ó|GPB5?¢GPB6?¢GPB7?¢GPB8
*/
/* ????GPB5,6,7,8?aê?3? */

*gpbcon &= ~((0x3<<(5*2)) |(0x3<<(6*2)) | (0x3<<(7*2)) | (0x3<<(8*2)));

*gpbcon |= ((0x1<<(5*2)) |(0x1<<(6*2)) | (0x1<<(7*2)) | (0x1<<(8*2)));

return 0;
}

staticssize_t first_drv_write(struct file *file, const char __user *buf, size_tcount, loff_t * ppos)
{
int val;
staticint cnt = 0;
myprintk("first_drv_write :%d\n", ++cnt);
//printk("first_drv_write\n");

copy_from_user(&val, buf, count); //copy_to_user();

if (val == 1)
{
// μ?μ?
*gpbdat &=~((1<<5) | (1<<6) | (1<<7) | (1<<8));
}
else
{
// ?eμ?
*gpbdat |= (1<<5) |(1<<6) | (1<<7) | (1<<8);
}

return 0;
}

staticstruct file_operations first_drv_fops = {
.owner=THIS_MODULE,/* ?aê?ò???oê£?í??ò±àò??£?éê±×??ˉ′′?¨μ?__this_module±?á?*/
.open=first_drv_open,
.write=first_drv_write,
};


intmajor;
staticint first_drv_init(void)
{
myprintk("first driver init!\n");

major = register_chrdev(0,"first_drv", &first_drv_fops); // ×¢2á, ?????úo?

firstdrv_class =class_create(THIS_MODULE, "firstdrv"); //?aá?ê1ó?udev×??ˉ′′?¨éè±????t

firstdrv_class_dev = device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */

gpbcon = (volatile unsigned long*)ioremap(0x56000010, 16);
gpbdat = gpbcon + 1;

return 0;
}

staticvoid first_drv_exit(void)
{
myprintk("first driver exit!\n");

unregister_chrdev(major,"first_drv"); // D???

device_destroy(firstdrv_class,MKDEV(major, 0));
class_destroy(firstdrv_class);
iounmap(gpbcon);
}

module_init(first_drv_init);
module_exit(first_drv_exit);


MODULE_LICENSE("GPL");
再贴出测试要用的应用程序:
Firstdrvtest.c
#include
#include
#include
#include

/*firstdrvtest on
* firstdrvtest off
*/
intmain(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/xyz",O_RDWR);
if (fd < 0)
{
printf("can'topen!\n");
}
if (argc != 2)
{
printf("Usage:\n");
printf("%s\n", argv[0]);
return 0;
}

if (strcmp(argv[1], "on")== 0)
{
val= 1;
}
else
{
val = 0;
}

write(fd, &val, 4);
return 0;
}
3.编译要注意的地方
由于在ubuntu_myproc_dmsg.c文件中EXPORT_SYMBOL(myprontk),将该符号导出了,以让其他模块能用,所以,编译的时候有三种方法,我尝试了前两种成功了。
(1)将ubuntu_myproc_dmsg.c和 first_drv.c放在同一个文件夹下,先编译ubuntu_myproc_dmsg.ko再编译first_drv.ko
(2)将两个文件放在不同的文件夹下,先编译ubuntu_myproc_dmsg.ko,再把其中的Module.symvers文件拷贝到first_drv.c所在的文件夹中,再编译first_drv.ko
(3)在first_drv.ko的Makefile中加入以下语句:
KBUILD_EXTRA_SYMBOLS+= /path/to/Module A/Module.symvers
export KBUILD_EXTRA_SYMBOLS
如:

这个方法没试,但是原理应该是一样的。
4.测试结果:
[root@FriendlyARM 3th]#
[root@FriendlyARM 3th]#
[root@FriendlyARM 3th]#
[root@FriendlyARM 3th]#
[root@FriendlyARM 3th]# insmod ubuntu_myproc_dmsg.ko
[root@FriendlyARM 3th]# insmod first_drv.ko
[root@FriendlyARM 3th]# cat /proc/mymsg
first driver init!
^C
[root@FriendlyARM 3th]# ./firstdrvtest on
[root@FriendlyARM 3th]# cat /proc/mymsg
first driver init!
first_drv_open : 1
first_drv_write : 1
^C
[root@FriendlyARM 3th]# ./firstdrvtest off
[root@FriendlyARM 3th]# cat /proc/mymsg
first driver init!
first_drv_open : 1
first_drv_write : 1
first_drv_open : 2
first_drv_write : 2
^C
[root@FriendlyARM 3th]#


5.参考帖子
http://bbs.chinaunix.net/thread-1918814-1-1.html
http://bbs.chinaunix.net/thread-1919530-1-1.html
http://hi.baidu.com/tracyangrad/blog/item/f668530a7d3785b50a7b82d9.html

    推荐阅读