从今天开始我们分析一下led子系统,该子系统主要实现对led设备的驱动和操作。led子系统和我们之前介绍的hwmon、gpio子系统有一个共同的特点,即借助sysfs创建一个设备相关的属性文件,可供应用程序借助sysfs方面的访问设备的属性。而针对led子系统的trigger模块实现而言,大多数的trigger也是借助sysfs进行trigger参数的配置(如亮灭时间设置、亮度设置等)。
针对led子系统学习,主要涉及如下几方面的内容:
一、led子系统概述
二、led子系统软件架构及数据结构
三、led device驱动分析、led trigger驱动分析
四、实现一个虚拟的led-trigger(ledtrig-gpio-pwm)
本章我们主要是说明led子系统概述,主要涉及如下几个方面的内容:
一、led子系统概念说明
二、led子系统框架简述
一、led子系统概念说明
针对led子系统而言,led子系统主要涉及两个方向的抽象:
- 抽象一个leddevice,记为struct led_classdev,该数据结构包括操作一个led器件的方法、led设备相关的参数(led亮度、和触发器的关联等);
- 抽象一个led 亮度控制方法的数据结构(又可理解为led触发器),记为struct led_trigger,其主要实现led器件的控制策略(ledtrigger-timer,则实现一个周期亮灭的触发器,亮灭的最小精度为毫秒;而ledtrigger-cpu,则是对cpu的状态进行指示,当cpu处于suspend状态时,则关闭led;当cpu处于工作状态时,则开启led。而针对mmc host创建的ledtrigger,则在mmc进行数据读写时,点亮led;mmc数据传输完成后,则关闭led)。
针对led子系统而言,主要就是这两个数据结构,同时提供了一系列的接口,用于led device、led-trigger的注册。
二、led子系统框架简述
上面我们说明了相关的数据结构,下面我们简要说明下led子系统的框架。如下图所示,针对led
子系统可包括如下几个方面:
- Led trigger层包括所有注册到led子系统的trigger,而led-device可以绑定到一个指定的led-trigger,从而即为该led device绑定了一个操作方法;
- led子系统接口层,主要由led-device、led-trigger调用,可由具体的led device驱动调用,而liunx其他子系统模块则可以实现led-trigger,并注册至led子系统,这样led-device即可绑定到注册的led0trigger;
- Led device层主要完成led器件的驱动,并将led-device注册至led子系统中,该led device层直接对应到具体的led器件。
针对led-trigger、led-device,它们之间的匹配类似于设备驱动模型中的device、driver的关系,但是比设备驱动模型简单许多。一个led-device仅可绑定一个led-trigger;但一个led-trigger则可以适配多个led-device。
针对我们具体的开发而言,最简单的led灯即是通过gpio进行控制,而针对gpio而言,linux子系统已经抽象出统一的数据结构,并向其他子系统提供了统一的访问接口。因此针对gpio控制的led而言,led子系统实现了统一的驱动(即leds-gpio.c文件),只要是gpio控制的led,则无需实现led device驱动,另外led子系统还提供了ledtrigger-timer,实现led的周期亮灭设置,那通过leds-gpio、ledtrigger-timer这两个实现模块,即可实现led灯的闪烁、长亮、长灭控制,因此针对gpio控制的led灯,完全不需要写驱动即可实现对该led灯的控制。
另外linux子系统针对gpio、led等系统的抽象,又极大的方便开发,如上面所说的leds-gpio实现,若没有抽象出gpio子系统并提供统一的对外操作接口,就不可能抽象一个统一的leds-gpio。
三、补充知识
在上面我们说了,hwmon、gpio、input、led以及tty、uart等都会涉及在sysfs下创建属性文件,从而可通过sysfs文件直接控制外设的参数。下面我们就简要说明下,应用程序是如何访问到sysfs下的属性文件的。
如下图所示,sysfs主要是由设备驱动模型调用,而sysfs也提供了针对kobject的操作接口。
- 一个struct device对应到sysfs的一个目录,针对sysfs而言,目录或文件均对一个struct sysfs_dirent类型的数据结构;
- 针对struct device,注册了kobject的type,该type提供了device属性文件的读写接口,即dev_attr_show、dev_attr_store;
- 针对一个属性文件而言,其也对应一个struct sysfs_dirent类型的变量,该变量中包括该属性文件对应的属性参数(即struct device_attribute类型的变量attr);同时包含了一个struct sysfs_open_dirent类型的变量,该变量中包含了已打开的sysfs文件的私有变量(struct sysfs_buffer类型的变量,而sysfs_buffer中又包含了针对该属性文件的操作接口,也就是kobj_type->sysfs_ops(也就是dev_attr_show、dev_attr_store))。
- 针对文件描述符struct file,当打开一个sysfs文件后,则在其open接口中设置file->private_data=(struct sysfs_buffer*)buffer(该buffer中已经提供了属性文件的操作接口dev_sysfs_ops);这样当对sysfs进行读写操作时,继而调用dev_attr_show/dev_attr_store进行操作,而在dev_attr_show/dev_attr_store中,则最终调用属性文件已创建的device_attribute->store/show接口
- 针对一个struct device相关的属性文件的创建,只需要调用接口sysfs_create_group即可创建相应的属性文件。
通过下面的关联图,把device、sysfs、vfs、task_struct做了关联,借助vfs、task_struct,即实现了与sysfs的关联。
目前的好多设备驱动子系统均会创建sysfs属性文件供应用程序访问。
以上便是本章的主要内容,主要对led子系统进行简要的概述说明。