调试分析之 imx257中proc下mymsg及myprintk的实现

发布时间:2024-08-13  

一.实现在/proc下面创建文件条目


1.定义proc_dir_entry结构体,已经file_operatioons结构体


1 //定义proc的entry结构体

2 static struct proc_dir_entry *myentry;

4 static struct file_operations proc_mymsg_operations = {

5 };


2.在入口函数中创建proc条目,并且关联file_operations结构体


 1 static int mymsg_init(void)

 2 {

 3     //创建proc的目录

 4     myentry = create_proc_entry('mymsg',S_IRUSR,NULL);  //S_IRUSR:400 只读

 5 

 6     if(myentry)

 7         myentry->proc_fops = &proc_mymsg_operations;

 8     

 9     return 0;

10 }


3.在出口函数中自然就是删除条目咯


1 static void mymsg_exit(void)

2 {

3     remove_proc_entry('mymsg', NULL);

4 }

 

4.编译测试代码,再/proc目录下创建了一个文件mymsg

7e480d720fd506e199d8838e8cb188e0_Et5PLyBNqQj5E8dGcGtZVoQ5WCvUwmn+adTHys6qppXRczV6tuk5OU3T9GWksaC5RXJhf2nzfuxe5wYo4r5axIq3YDXwW7bA4iLncBTTa0x9+v+BJ8FWtcyUCAAAAABJRU5ErkJggg==.png

附上驱动程序mymsg_1.c


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 #include

 8 #include

 9 

10 //定义proc的entry结构体

11 static struct proc_dir_entry *myentry;

12 

13 static struct file_operations proc_mymsg_operations = {

14 };

15 

16 static int mymsg_init(void)

17 {

18     //创建proc的目录

19     myentry = create_proc_entry('mymsg',S_IRUSR,NULL);    //S_IRUSR:400 只读

20     

21     if(myentry)

22         myentry->proc_fops = &proc_mymsg_operations;

23     

24     return 0;

25 }

26 

27 static void mymsg_exit(void)

28 {

29     remove_proc_entry('mymsg', NULL);

30 }

31 

32 module_init(mymsg_init);

33 module_exit(mymsg_exit);

34 

35 MODULE_LICENSE('GPL');

36 MODULE_AUTHOR('Lover雪儿');


二.实现读写函数


由于上面我们的file_operations结构体为空,所以我们自然就无法对/proc/mymsg进行读取,此处我们增加一个读函数.


1 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)

2 {

3     printk('mymsg_read n');

4     return 0;

5 }

7 static struct file_operations proc_mymsg_operations = {

8     .read = mymsg_read,

9 };


编译加载完成后,我们使用cat命令对齐进行读取,结果如下所示:说明已经成功的进入了mymsg_read函数中.

4df7f62580e947d22b336a773780a698_h90WZmOMWo6LAAAAABJRU5ErkJggg==.png

附上驱动程序mymsg_2.c


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 #include

 8 #include

 9 

10 //定义proc的entry结构体

11 static struct proc_dir_entry *myentry;

12 

13 

14 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)

15 {

16     printk('mymsg_read n');

17     return 0;

18 }

19 

20 

21 static struct file_operations proc_mymsg_operations = {

22     .read = mymsg_read,

23 };

24 

25 static int mymsg_init(void)

26 {

27     //创建proc的目录

28     myentry = create_proc_entry('mymsg',S_IRUSR,NULL);    //S_IRUSR:400 只读

29     

30     if(myentry)

31         myentry->proc_fops = &proc_mymsg_operations;

32     

33     

34     return 0;

35 }

36 

37 static void mymsg_exit(void)

38 {

39     remove_proc_entry('mymsg', NULL);

40 }

41 

42 module_init(mymsg_init);

43 module_exit(mymsg_exit);

44 

45 MODULE_LICENSE('GPL');

46 MODULE_AUTHOR('Lover雪儿');


三.模拟内存数据读取


既然要进行读取,自然就少不了数据的拷贝打印,此处我们利用数组来模拟数据的buff,然后再init函数中对其进行格式化数据,模拟写数据,


接着我们在mymsg_read函数中对其进行读取,看是否能成功读出数据.


1.定义一个内存buff数组


1 //定义proc的entry结构体

2 static struct proc_dir_entry *myentry;

3 static char mylog_buf[1024];        //数据缓冲区

 

2.在init函数中对其进行格式化字符串,模拟写数据


 1 static int mymsg_init(void)

 2 {

 3     sprintf(mylog_buf, '%s', 'abcdefghijklmnn');    //模拟伪造buf的数据

 4     //创建proc的目录

 5     myentry = create_proc_entry('mymsg',S_IRUSR,NULL);    //S_IRUSR:400 只读

 6     

 7     if(myentry)

 8         myentry->proc_fops = &proc_mymsg_operations;

 9     

10     return 0;

11 }


3.再mymsg_read函数中对其进行读取


1 //实现读函数

2 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)

3 {

4     if(copy_to_user(buf, mylog_buf, 10));

5     return 10;

6 }

 

4.编译测试:发现成功的读出了数据.

b0f56e35d7dae278067df7739bcd876b_ACP2VBHeQAvGAAAAAElFTkSuQmCC.png

附上驱动程序mymsg_3.c

 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 #include

 8 #include

 9 

10 //定义proc的entry结构体

11 static struct proc_dir_entry *myentry;

12 static char mylog_buf[1024];        //数据缓冲区

13 

14 //实现读函数

15 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)

16 {

17     //int cnt;

18     //printk('mymsg_read n');

19     // 把mylog_buf的数据copy_to_user, return

20     //cnt = min(1024,count);

21     if(copy_to_user(buf, mylog_buf, 10));

22     

23     return 10;

24 }

25 

26 //定义file_operation结构体

27 static struct file_operations proc_mymsg_operations = {

28     .read = mymsg_read,

29 };

30 

31 static int mymsg_init(void)

32 {

33     sprintf(mylog_buf, '%s', 'abcdefghijklmnn');    //模拟伪造buf的数据

34     //创建proc的目录

35     myentry = create_proc_entry('mymsg',S_IRUSR,NULL);    //S_IRUSR:400 只读

36     

37     if(myentry)

38         myentry->proc_fops = &proc_mymsg_operations;

39     

40     return 0;

41 }

42 

43 static void mymsg_exit(void)

44 {

45     remove_proc_entry('mymsg', NULL);

46 }

47 

48 module_init(mymsg_init);

49 module_exit(mymsg_exit);

50 

51 MODULE_LICENSE('GPL');

52 MODULE_AUTHOR('Lover雪儿');

53 

54 

55 /*

56 1.环形缓冲区

57     空: R == W

58     写: buf[W] = val;

59         W = (W+1) % 10;

60     读: val = buf[R]

61         R = (R+1) % 10    

62 2.        

63         

64         

65         

66 

67 

68 

69 

70 

71 

72 

73 */


四.参考printk的函数,可以用于对消息的进行打印保存


现在我们来编写一个类似printk的myprintk函数,从而实现其他驱动程序调用myprintk将打印信息全部输出到/proc/mymsg中,


便于统一对驱动的打印信息进行调试,不会收到其他的打印信息的干扰.


测试驱动程序我们选用以前imx257的led驱动程序:


博客文章地址:http://www.cnblogs.com/lihaiyan/p/4297923.html


当然,选择其他的驱动程序也一样,只要外部声明一下myprintk函数,然后将全部的printk替换为myprintk即可.


1.定义两个数据buff,以及读写指针,和一个等待队列


1 //定义proc的entry结构体

2 static struct proc_dir_entry *myentry;

3 static char mylog_buf[MYLOG_BUF_LEN];        //数据缓冲区

4 static char tmp_buf[MYLOG_BUF_LEN];            //数据缓冲区

5 static int mylog_r = 0;

6 static int mylog_w = 0;

8 static DECLARE_WAIT_QUEUE_HEAD(mylog_wait);


2.实现 判断buff空的函数


1 //判断是否为空

2 static int is_mylog_empty(void)

3 {

4     return (mylog_r == mylog_w);

5 }

 

3.实现 判断buff满的函数


1 //判断是否已满

2 static int is_mylog_full(void)

3 {

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

5 }

 

4.实现 向buff写入字符的函数


 1 //写入字符

 2 static void mylog_putc(char c)

 3 {

 4     if(is_mylog_full)

 5     {

 6         //丢弃一个数据

 7         mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;

 8     }

 9     mylog_buf[mylog_w] = c;

10     mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN;

11     

12     /* 唤醒等待数据的进程 */

13     wake_up_interruptible(&mylog_wait);

14 }


函数除了向buff中写的功能外,还有一个重要的任务就是唤醒进程,从而再read函数中将数据打印出来


5.实现 读取buff字符的函数


1 //读取字符

2 static int mylog_getc(char *p)

3 {

4     if(is_mylog_empty())

5         return 0;

6     *p = mylog_buf[mylog_r];

7     mylog_r = (mylog_r + 1) %  MYLOG_BUF_LEN;

8     return 1;

9 }


6.参考内核代码中的vsprintf.c的sprinf函数,实现myprintk函数,并且导出myprintk函数,供其他的程序使用


//打印输出  参考vsprintf.c  的 sprintf

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

{

    va_list args;

    int i,j;

    

    va_start(args, fmt);

    i = vsnprintf(tmp_buf, INT_MAX, fmt, args);

    va_end(args);

    for(j = 0; j    {

        mylog_putc(tmp_buf[j]);

    }

    return 1;

}

EXPORT_SYMBOL(myprintk);


7.完善读函数


//实现读函数     参考kmsg.c

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

{

    int error;

    int i = 0;        //所读的数据的个数

    char c;

    

    //以非阻塞打开,并且数据队列为空

    if ((file->f_flags & O_NONBLOCK) && is_mylog_empty())

        return -EAGAIN;

    

    //等待直到队列非空

    error = wait_event_interruptible(mylog_wait,!is_mylog_empty());

    

    /* copy_to_user 若是没错,获取字符串成功 */

    while( !error && (mylog_getc(&c)) && i < count ){

        error = __put_user(c, buf);            //等同copy_to_user

        buf++;

        i++;

    }

    if(!error)

        error = i;

    return error;

}


当应用程序使用cat来读取/proc/mymsg时,如果程序是以非阻塞的方式开始,并且buff为空的话,则直接返回,否则让程序进入可中断的睡眠,

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>