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 return 0; } if (strcmp(argv[1], "on")== 0) { val= 1; } else { val = 0; } write(fd, &val, 4); return 0; } |
由于在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
推荐阅读
- STM32F103/302 SPI3 接口使用例程
- Uncompressing Linux... done, booting the kernel (问题集锦)
- 嵌入式软件|彻底的系统调用---open函数
- Linux数据类型大小
- mini2440网卡驱动 之 虚拟网卡@2.6.32注册netdev问题的解决
- STM32F103X启动代码详细分析