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 

 

#define  UBUNTU_LOG_BUF_LENGTH 1024   //»·Ðλº³åÇø³¤¶È

 

static  DECLARE_WAIT_QUEUE_HEAD(ubuntu_log_waitq);

 

static  char ubuntu_log_buf[UBUNTU_LOG_BUF_LENGTH];   //»·Ðλº³åÇøÊý×é

static  char tmp_buf[UBUNTU_LOG_BUF_LENGTH]; //ÔÝ´æ

static  int ubuntu_log_rp=0; //»·Ðλº³åÇø¶ÁÖ¸Õë, ²»±ä

static  int ubuntu_log_wp = 0; //»·Ðλº³åÇøдָÕë

static  int ubuntu_log_rp_for_read = 0; //»·Ðλº³åÇø¶ÁÖ¸Õ룬ΪÁ˶ÁÈ¡Êý¾Ý£¬¿É±ä

 

 

 

/*Åжϻ·Ðλº³åÇøÊÇ·ñÂú*/

static  int ubuntu_Is_log_full(void)

{

         return ((ubuntu_log_wp + 1) %  UBUNTU_LOG_BUF_LENGTH == ubuntu_log_rp);

}

 

/*Åжϻ·Ðλº³åÇøÊÇ·ñ¿Õ*/

static  int ubuntu_Is_log_empty(void)

{

         return (ubuntu_log_rp ==  ubuntu_log_wp);

}

 

static  int ubuntu_Is_log_empty_for_read(void)

{

         return (ubuntu_log_rp_for_read ==  ubuntu_log_wp);

}

 

 

 

/*  Ïò»·Ðλº³åÇøÄÚдÈëÒ»¸ö×Ö·ûÊý¾Ý */

static  void ubuntu_log_putchar(char c)

{

         if(ubuntu_Is_log_full())  //Èç¹ûÂúÁË

         {

                   /*¶ªÆúÒ»¸öÊý¾Ý*/

                   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;

        

}

 

 

 

/*½«¸ñʽ»¯µÄÊý¾ÝдÈëÔݴ滺³åÇøÖÐ

   ×¢Òâ: ÓÉÓÚÕâ¸öº¯ÊýÒª±»ÆäËûÎļþËùÓÃ

                ËùÒÔÆäÇ°Ãæ²»ÄܼÓstatic      

   ²Î¿¼: sprintf º¯Êý                                                                    */

  

static  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++)

         {

                   ubuntu_log_putchar(  tmp_buf[j] );

         }

 

         return i;

}

 

 

/*  µ¼³ö¸Ãº¯Êý */

EXPORT_SYMBOL(myprintk);

 

 

 

 

 

 

/*  ´Ó»·Ðλº³åÇø¶Á³öÒ»¸öÊý¾Ý */

static  int ubuntu_log_getchar(char *p)

{

         if( ubuntu_Is_log_empty( ))  //Èç¹ûÊÇ¿Õ£¬·µ»Ø¶Áȡʧ°Ü

         {

                   return 0;

         }

         *p = ubuntu_log_buf[ubuntu_log_rp];

         ubuntu_log_rp = (ubuntu_log_rp + 1) %  UBUNTU_LOG_BUF_LENGTH;

         return 1;

}

static  int ubuntu_log_getchar_for_read(char *p)

{

         if( ubuntu_Is_log_empty_for_read( ))  //Èç¹ûÊÇ¿Õ£¬·µ»Ø¶Áȡʧ°Ü

         {

                   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;

}

 

 

 

 

static  ssize_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())  //Èç¹û·Ç×èÈû´ò¿ª²¢ÇÒ»·Ðλº³åÇøΪ¿Õ

                   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;

}

 

 

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

{

         ubuntu_log_rp_for_read =  ubuntu_log_rp;

         return 0;

}

 

 

static  const struct file_operations ubuntu_proc_kmsg_operations = {

         .read           =  ubuntu_kmsg_read,

         .open          =  ubuntu_kmsg_open,

};

 

 

static  int __init ubuntu_mymsg_init(void)

{

 

         proc_create("mymsg",  S_IRUSR, NULL, &ubuntu_proc_kmsg_operations);

         return 0;

}

 

static  void __exit ubuntu_mymsg_exit(void)

{

         remove_proc_entry("mymsg",  NULL );

}

 

 

 

#define  DRIVER_VERSION "v1.0"

#define  DRIVER_AUTHOR "Guoyu "

#define  DRIVER_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 

 

 

//Íⲿº¯Êý,ÓÐûÓаüº¬¸ÃÍ·Îļþ£¬Ö»ÄÜÓÃextern

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

 

static  struct class *firstdrv_class;

static  struct class_device        *firstdrv_class_dev;

 

volatile  unsigned long *gpbcon = NULL;

volatile  unsigned long *gpbdat = NULL;

 

//#define  DBG_PRINTK printk

//#define  DBG_PRINTK(x...)   //È¥µô´òÓ¡Óï¾ä

 

static  int 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ΪÊä³ö */

        

         *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;

}

 

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

{

         int val;

         static  int 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

         {

                   // ÃðµÆ

                   *gpbdat |= (1<<5) |  (1<<6) | (1<<7) | (1<<8);

         }

        

         return 0;

}

 

static  struct file_operations first_drv_fops = {

    .owner   =   THIS_MODULE,    /* ÕâÊÇÒ»¸öºê£¬ÍÆÏò±àÒëÄ£¿éʱ×Ô¶¯´´½¨µÄ__this_module±äÁ¿  */

    .open    =   first_drv_open,    

         .write          =       first_drv_write,     

};

 

 

int  major;

static  int first_drv_init(void)

{

         myprintk("first driver init!  \n");

        

         major = register_chrdev(0,  "first_drv", &first_drv_fops); // ×¢²á, ¸æËßÄÚºË

 

         firstdrv_class =  class_create(THIS_MODULE, "firstdrv");  //ΪÁËʹÓÃudev×Ô¶¯´´½¨É豸Îļþ

        

         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;

}

 

static  void first_drv_exit(void)

{

         myprintk("first driver exit!  \n");

        

         unregister_chrdev(major,  "first_drv"); // жÔØ

 

         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

  */

int  main(int argc, char **argv)

{

         int fd;

         int val = 1;

         fd = open("/dev/xyz",  O_RDWR);

         if (fd < 0)

         {

                   printf("can't  open!\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.koMakefile中加入以下语句:

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

你可能感兴趣的:(嵌入式软件)