嵌入式内核及驱动开发之学习笔记(十二) 设备驱动模型

举报
王建峰 发表于 2021/11/19 02:36:38 2021/11/19
【摘要】 按照之前的实现驱动的方法。对于同一类设备,驱动层实现的操作方法是相似的,而设备信息总是不同的,一个产品上有很多这样的同类设备,我们为每一个设备都定制一套驱动程序,代价似乎太“高昂点”;对于一个设别,如果硬件有所改动,也必然要修改取代代码。 为了提高代码的通用性,我们将驱动和设备进行分离,设备对象专门用来描述设备(硬件)的信息。而驱动负...

按照之前的实现驱动的方法。对于同一类设备,驱动层实现的操作方法是相似的,而设备信息总是不同的,一个产品上有很多这样的同类设备,我们为每一个设备都定制一套驱动程序,代价似乎太“高昂点”;对于一个设别,如果硬件有所改动,也必然要修改取代代码。

为了提高代码的通用性,我们将驱动和设备进行分离,设备对象专门用来描述设备(硬件)的信息。而驱动负责重设备中获取这些硬件描述,主要用来实现操作方法。总线负责将两者配对。

这样可以提高代码的通用性,让驱动可以兼容不同的硬件。至于如何应用,笔者还是不清楚。这里只介绍设备驱动模型,之后会将模型构建出来。

 

自定义总线 mybus

mybus.c实现device和device的匹配。在模块加载后,注册mybus到总线;每调用一次注册函数(driver_register或者device_register)就会匹配一次,匹配就会执行match函数,match函数执行成功之后,代码会往下走,去执行驱动中的probe函数。
模块加载 -->  注册mybus总线  -->  回调 mybus.match  -->  匹配成功

  1. 构建总线对象
  2. 注册和注销总线
  3. 实现回调mybus.match方法

  
  1. //mubus.c
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/device.h>
  5. int mybus_match(struct device *dev, struct device_driver *drv);
  6. struct bus_type mybus = {//实例化一个bus对象
  7. .name = "mybus",
  8. .match = mybus_match,
  9. };
  10. EXPORT_SYMBOL(mybus);
  11. static int __init mybus_init(void)
  12. {
  13. printk("----------%s-------------\n", __FUNCTION__);
  14. int ret;
  15. ret = bus_register(&mybus); //注册bus
  16. if(ret != 0)
  17. {
  18. printk("bus_register error\n");
  19. return ret;
  20. }
  21. return ret;
  22. }
  23. static void __exit mybus_exit(void)
  24. {
  25. printk("----------%s-------------\n", __FUNCTION__);
  26. //注销bus
  27. bus_unregister(&mybus);
  28. }
  29. int mybus_match(struct device *dev, struct device_driver *drv)
  30. {
  31. //如果匹配成功,match方法一定要返回一个1, 失败返回0
  32. if(!strncmp(drv->name, dev->kobj.name, strlen(drv->name)))
  33. {
  34. printk("match ok\n");
  35. return 1;
  36. }else{
  37. printk("match failed\n");
  38. return 0;
  39. }
  40. return 0;
  41. }
  42. module_init(mybus_init);
  43. module_exit(mybus_exit);
  44. MODULE_LICENSE("GPL");

 

注册成功后在系统sys/目录下查看到这个结点

 

 

定义设备 mydev

mydev.c用来描述设备信息。将硬件的信息描述成为一个结构体,添加到mydev.platform_data这个属性当中。在模块加载后,注册device到了mybus总线

  1. 构建device对象
  2. 将device注册到mybus总线/从mybus总线注销
  3. 自定义数据类型,构造结构体描述硬件信息

  
  1. //mydev.c
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/device.h>
  5. #include "dev_info.h"
  6. void mydev_release(struct device *dev);
  7. extern struct bus_type mybus;
  8. struct mydev_desc devinfo = {
  9. .name = "testdev",
  10. .irqno = 9999,
  11. .addr = 0x30008000,
  12. };
  13. struct device mydev = {
  14. .init_name = "fsdev_drv",
  15. .bus = &mybus,
  16. .release = mydev_release,
  17. .platform_data = &devinfo,
  18. };
  19. static int __init mydev_init(void)
  20. {
  21. printk("----------%s-------------\n", __FUNCTION__);
  22. //将device注册到总线中
  23. int ret;
  24. ret = device_register(&mydev);
  25. if(ret < 0)
  26. {
  27. printk("device_register error\n");
  28. return ret;
  29. }
  30. return ret;
  31. }
  32. static void __exit mydev_exit(void)
  33. {
  34. printk("----------%s-------------\n", __FUNCTION__);
  35. device_unregister(&mydev);//注销dev
  36. }
  37. void mydev_release(struct device *dev)
  38. {
  39. printk("----------%s-------------\n", __FUNCTION__);
  40. }
  41. module_init(mydev_init);
  42. module_exit(mydev_exit);
  43. MODULE_LICENSE("GPL");

注册成功后在系统sys/目录下查看到这个设备结点

 

 

编写驱动 mydrv

mydrv.c用来实现驱动的方法。在模块加载后,注册driver到了mybus总线。当驱动和设备匹配成功后,系统自动调用mydrv.probe这个方法。另外,驱动也通过总线获取设备的信息,"dev_info.h"头文件中声明的是描述设备的结构体类型,是用来接收另一边设备数据的格式。

  1. 构建driver对象
  2. 将driver对象注册总线/从总线注销
  3. 实现驱动的回调mydrv.probe 和 mydrv.remove方法

  
  1. //mydrv.c
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/device.h>
  5. #include <linux/io.h>
  6. #include "dev_info.h"
  7. int mydrv_probe(struct device *dev);
  8. int mydrv_remove(struct device *dev);
  9. extern struct bus_type mybus;
  10. struct device_driver mydrv = {
  11. .name = "fsdev_drv",
  12. .bus = &mybus,
  13. .probe = mydrv_probe,
  14. .remove = mydrv_remove,
  15. };
  16. static int __init mydrv_init(void)
  17. {
  18. printk("----------%s-------------\n", __FUNCTION__);
  19. //将driver注册到总线中
  20. int ret;
  21. ret = driver_register(&mydrv);
  22. if(ret < 0)
  23. {
  24. printk("device_register error\n");
  25. return ret;
  26. }
  27. return ret;
  28. }
  29. static void __exit mydrv_exit(void)
  30. {
  31. printk("----------%s-------------\n", __FUNCTION__);
  32. driver_unregister(&mydrv);
  33. }
  34. struct mydev_desc *pdesc;
  35. int mydrv_probe(struct device *dev)
  36. {
  37. printk("----------%s-------------\n", __FUNCTION__);
  38. pdesc = (struct mydev_desc *)dev->platform_data;
  39. printk("name = %s\n", pdesc->name);
  40. printk("irqno = %d\n", pdesc->irqno);
  41. return 0;
  42. }
  43. int mydrv_remove(struct device *dev)
  44. {
  45. printk("----------%s-------------\n", __FUNCTION__);
  46. return 0;
  47. }
  48. module_init(mydrv_init);
  49. module_exit(mydrv_exit);
  50. MODULE_LICENSE("GPL");

 

注册成功后在系统sys/目录下查看到这个结点

文章来源: blog.csdn.net,作者:hinzer,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/feit2417/article/details/84308266

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。