加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 钦州站长网 (https://www.0777zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

linux-字符设备总结

发布时间:2022-12-03 12:58:42 所属栏目:Linux 来源:
导读:  文章目录

  前言

  @和原子哥一起学习Linux

  开发环境:I.MX6Ull开发板

  参考书籍:

  《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6.pdf》

  《linux设备驱动开发详
  文章目录
 
  前言
 
  @和原子哥一起学习Linux
 
  开发环境:I.MX6Ull开发板
 
  参考书籍:
 
  《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6.pdf》
 
  《linux设备驱动开发详解-基于最新的linux4.0内核》
 
  个人学习笔记,欢迎讨论
 
  一、字符设备的位置
 
  驱动编译完成后会形成模块,加载模块会形成驱动文件,本质上就是对文件的操作。
 
  1、使用命令“cat /proc/devices”可以看到你注册设备的设备号
 
  2、字符设备就是“dev/xxx”,xxx是注册的字符设备名称
 
  在这里插入图片描述
 
  二、驱动的分离
 
  简单来说,就是大家想复用写好的东西
  1.一个设备驱动想对应多个不同平台
 
  每个平台对设备的控制器是不一样的,比如I2C控制器,SPI控制器,这些根据不同厂家设计不同而不同,厂家实现了主机端控制器的驱动,也就是可以产生各种波形,那么设备驱动写入设备寄存器的接口难道要按照厂家变化?
 
  此处需要引入中间层,实现对外统一接口api,这样不同的主机就有了相同的神经。厂家可以根据自己的不同方案,去实现自己的控制器驱动,统一注册到api接口,设备驱动只需要调用通用接口,这样就完成了一个设备驱动可以在多个平台上运行的构想。
 
  在这里插入图片描述
 
  2.一个设备驱动想对应多个同类设备
 
  有了一个设备驱动后,当然想的是无论多少这样的设备都可以使用这个设备驱动了,但是不同设备设备信息不同,比如地址之类的,此时必须要把设备信息从设备驱动中剥离出去,设备驱动使用标准的方法获取设备信息即可。
 
  此处引入总线,当我们向系统注册一个驱动的时候,总线就会在设备中查找,看看有没有与之匹配的设备,如果有的话就将两者联系起来。同样的,当向系统中注册一个设备的时候,总线就会在驱动中查找看有没有与之匹配的设备,有的话也联系起来。 这样就实现了一个驱动多个设备都可以用的设想。
 
  在这里插入图片描述
 
  3.设备驱动完成了他的终极进化
 
  Linux 的总线(bus)、驱动(driver)和设备(device)模型,也就是常说的驱动分离,总线负责连接设备和驱动
 
  在这里插入图片描述
 
  二、驱动的分层
 
  简单来说,就是大家想只做自己的活,不一定是分几层,就是为了在不同的层处理不同的内容。
 
  >最主要的核心层有三个功能
  1、对上提供接口,类似2.1中的对外统一接口API
  2、中间层通用逻辑,避免底层重复实现
  3、底层驱动只负责硬件相关的访问
  这就是面向对象的设计!
 
  三、总线驱动
 
  Linux 的总线(bus)、驱动(driver)和设备(device)模型的总线,比如 I2C、 SPI、 USB 等总线是实体的。但是有些外设是没有总线这个概念的,为了解决此问题, Linux 提出了 platform 这个虚拟总线,相应的就有 platform_driver 和 platform_device。
 
  1.platform 总线
 
  Linux系统内核使用 bus_type结构体表示总线,platform 总线是 bus_type 的一个具体实例:
 
  struct bus_type platform_bus_type = {
   .name = "platform",
   .dev_groups = platform_dev_groups,
   .match = platform_match,
   .uevent = platform_uevent,
   .pm = &platform_dev_pm_ops,
  };
  platform_bus_type 就是 platform 平台总线,其中 platform_match 就是匹配函数,采用3种匹配方法,1)设备树 2)ACPI 3)id_table 匹配
 
  2.platform 驱动
 
  * 字符设备驱动操作集
  */
  static struct file_operations xxx_fops = {
   .owner = THIS_MODULE,
   .open = xxx_open,
   .write = xxx_write,
  };
   /*
   * platform 驱动的 probe 函数
   * 驱动与设备匹配成功以后此函数就会执行
   */
   static int xxx_probe(struct platform_device *dev)
   {
    ......
    cdev_init(&xxxdev.cdev, &xxx_fops); /* 注册字符设备驱动 */
    /* 函数具体内容 */
    return 0;
   }
   static int xxx_remove(struct platform_device *dev)
   {
    ......
    cdev_del(&xxxdev.cdev);/* 删除 cdev */
    /* 函数具体内容 */
    return 0;
   }
   /* 匹配列表 */
   static const struct of_device_id xxx_of_match[] = {
    { .compatible = "xxx-gpio" },
    { /* Sentinel */ }
   };
   /*
   * platform 平台驱动结构体
   */
   static struct platform_driver xxx_driver = {
    .driver = {
    .name = "xxx",
    .of_match_table = xxx_of_match,
    },
    .probe = xxx_probe,
    .remove = xxx_remove,
   };
   /* 驱动模块加载 */
   static int __init xxxdriver_init(void)
   {
   return platform_driver_register(&xxx_driver);
   }
   /* 驱动模块卸载 */
   static void __exit xxxdriver_exit(void)
   {
   platform_driver_unregister(&xxx_driver);
   }
   module_init(xxxdriver_init);
   module_exit(xxxdriver_exit);
  3.platform 设备 1、 platform 设备框架
 
  /* 资源 */
  static struct resource xxx_resources[] = {
   [0] = {
   .start = xx,
   .end = xxx,
   .flags = xxxx,
    },
  };
  /* platform 设备结构体 */
  static struct platform_device xxxdevice = {
   .name = "xxx-",
   .id = -1,
   .num_resources = ARRAY_SIZE(xxx_resources),
   .resource = xxx_resources,
  };
   /* 设备模块加载 */
   static int __init xxxdevice_init(void)
   {
   return platform_device_register(&xxxdevice);
   }
   /* 设备模块注销 */
   static void __exit xxx_resourcesdevice_exit(void)
   {
   platform_device_unregister(&xxxdevice);
   }
   module_init(xxxdevice_init);
   module_exit(xxxdevice_exit);
  2、 设备树
 
   gpioled {
   #address-cells = <1>;
   #size-cells = <1>;
   compatible = "atkalpha-gpioled";
   pinctrl-names = "default";
   pinctrl-0 = <&pinctrl_led>;
   led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
   status = "okay";
   };
  总结
 
  上述就是字符设备学习的笔记,后面I2C和SPI都是按照设备总线驱动来的,大部分是调用接口,总线驱动基本由厂家完成,设备驱动需要对不同的设备进行适配linux 驱动,设备树都是按照官方给到的原版进行修改适配,目前学完只是会改,不禁感叹前辈们的对此的贡献,才有如此简单的使用方式。
 

(编辑:PHP编程网 - 钦州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!