• led子系统【转】


    本文转载自:http://blog.csdn.net/yuanlulu/article/details/6438841

    ============================================
    作者:yuanlulu
    http://blog.csdn.NET/yuanlulu


    版权没有,但是转载请保留此段声明
    ============================================

     
    数据结构
    /include/linux/leds.h
    enum led_brightness {
         LED_OFF          = 0,
         LED_HALF     = 127,
         LED_FULL     = 255,
    };

    led_classdev代表led的实例
    struct led_classdev {
         const char          *name;               //名字
         int               brightness;                   //当前亮度
         int               flags;                         //标志,目前只支持 LED_SUSPENDED

    #define LED_SUSPENDED          (1 << 0)

         /*设置led的亮度,不可以睡眠,有必要的话可以使用工作队列*/
         void          (*brightness_set)(struct led_classdev *led_cdev,
                               enum led_brightness brightness);
         /* 获取亮度 */
         enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);

         /* 激活硬件加速的闪烁 */
         int          (*blink_set)(struct led_classdev *led_cdev,
                             unsigned long *delay_on,
                             unsigned long *delay_off);

         struct device          *dev;
         struct list_head     node;               /* 所有已经注册的led_classdev使用这个节点串联起来 */
         const char          *default_trigger;     /* 默认触发器 */

    #ifdef CONFIG_LEDS_TRIGGERS               //如果配置内核时使能了触发器功能,才会编译下面一段
         /* 这个读写子轩锁保护下面的触发器数据 */
         struct rw_semaphore     trigger_lock;

         struct led_trigger     *trigger;          //触发器指针
         struct list_head     trig_list;               //触发器使用的链表节点,用来连接同一触发器上的所有led_classdev
         void               *trigger_data;            //触发器使用的私有数据
    #endif
    };
     
    触发器的结构体
    #define TRIG_NAME_MAX 50
    struct led_trigger {
         const char     *name;          //触发器名字
         void          (*activate)(struct led_classdev *led_cdev);     //激活ledled。led_classdev和触发器建立连接时会调用这个方法。
         void          (*deactivate)(struct led_classdev *led_cdev);     //取消激活。led_classdev和触发器取消连接时会调用这个方法。

         /* 本触发器控制之下的led链表 */
         rwlock_t       leddev_list_lock; //保护链表的锁
         struct list_head  led_cdevs;    //链表头

         /* 连接下一个已注册触发器的链表节点 ,所有已注册的触发器都会被加入一个全局链表*/
         struct list_head  next_trig;
    };
     
    平台设备相关的led数据结构
    struct led_info {
         const char     *name;
         char          *default_trigger;
         int          flags;
    };

    struct led_platform_data {
         int          num_leds;
         struct led_info     *leds;
    };
     
    平台设备相关的gpio led数据结构
    struct gpio_led {
         const char *name;
         char *default_trigger;
         unsigned      gpio;
         u8           active_low;
    };

    struct gpio_led_platform_data {
         int           num_leds;
         struct gpio_led *leds;
         int          (*gpio_blink_set)(unsigned gpio,
                             unsigned long *delay_on,
                             unsigned long *delay_off);
    };
     

    led_classdev接口分析/driver/rtc/led-class.c
     
    注册struct led_classdev:
    int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
    {
         int rc;

         /* 创建一个struct device,他的父设备是parent,drvdata是led_cdev,名字是led_cdev->name,类别是 leds_class*/
         led_cdev->dev = device_create_drvdata(leds_class, parent, 0, led_cdev,
                                   "%s", led_cdev->name);
         if (IS_ERR(led_cdev->dev))
              return PTR_ERR(led_cdev->dev);

         /* register the attributes */
         rc = device_create_file(led_cdev->dev, &dev_attr_brightness);//在sys/class/rtc/下创建一个led的属性文件。
         if (rc)
              goto err_out;

         /* add to the list of leds */
         down_write(&leds_list_lock);
         list_add_tail(&led_cdev->node, &leds_list);//将新的led加入链表,全局链表是leds_list
         up_write(&leds_list_lock);

         led_update_brightness(led_cdev);//获取led当前的亮度更新led_cdev的brightness成员

    #ifdef CONFIG_LEDS_TRIGGERS
         init_rwsem(&led_cdev->trigger_lock);//初始化led_cdev的触发器自旋锁

         rc = device_create_file(led_cdev->dev, &dev_attr_trigger);//在sys/class/led中为触发器创建属性文件
         if (rc)
              goto err_out_led_list;

         led_trigger_set_default(led_cdev); //为led_cdev设置默认的触发器
    #endif

         printk(KERN_INFO "Registered led device: %s/n",
                   led_cdev->name);

         return 0;

    #ifdef CONFIG_LEDS_TRIGGERS
    err_out_led_list:
         device_remove_file(led_cdev->dev, &dev_attr_brightness);
         list_del(&led_cdev->node);
    #endif
    err_out:
         device_unregister(led_cdev->dev);
         return rc;
    }
    EXPORT_SYMBOL_GPL(led_classdev_register);
     
    注销struct led_classdev:
    void led_classdev_unregister(struct led_classdev *led_cdev);
    注销所做的工作和注册相反。
     
    将led挂起:将led的flag设为LED_SUSPENDED,关闭led.
    void led_classdev_suspend(struct led_classdev *led_cdev)
    从挂起中恢复:
    void led_classdev_resume(struct led_classdev *led_cdev)
     
    sysfs中的属性文件
    /driver/rtc/led-class.c会首先创建一个leds类,生成/sys/class/leds目录。
    在led_classdev_register中生成了两个sysfs属性文件,它们使用的属性参数如下:
     
    static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
    static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
     
    led_brightness_show和led_brightness_store分别负责显示和设置亮度,用户控件通过
    /sys/class/leds/<device>/brightness查看和设置亮度就是和这两个函数交互的。
     led_trigger_show用于读取当前触发器的名字,led_trigger_store用于指定触发器的名字,
    它会寻找所有已注册的触发器,找到同名的并设置为当前led的触发器。
    /sys/class/leds/<device>/trigger用于用户空间查看和设置触发器。
     
     led_classdev全局链表:
    led_classdev_register注册的struct led_classdev会被加入leds_list链表,这个链表定义在driver/leds/led-core.c。
     

    led_trigger接口分析/driver/leds/led-triggers.c
     
    注册触发器
    int led_trigger_register(struct led_trigger *trigger);
    这个函数注册的trigger会被加入全局链表trigger_list,这个链表头是在/driver/leds/led-triggers.c定义的。
    此外,这个函数还会遍历所有的已注册的 led_classdev,如果有哪个led_classdev的默认触发器和自己同名,则
    调用led_trigger_set将自己设为那个led的触发器。
    led_classdev注册的时候也会调用led_trigger_set_default来遍历所有已注册的触发器,找到和led_classdev.default_trigger同名的触发器则将它设为自己的触发器。
     
    注销触发器
    void led_trigger_unregister(struct led_trigger *trigger);
    这个函数做和注册相反的工作,并把所有和自己建立连接的led的led_classdev.trigger设为NULL。
     
    设置触发器上所有的led为某个亮度
    void led_trigger_event(struct led_trigger *trigger, enum led_brightness brightness);
     
    注册触发器的简单方法
    指定一个名字就可以注册一个触发器,注册的触发器通过**tp返回,但是这样注册的触发器没有active和deactivede。
    void led_trigger_register_simple(const char *name, struct led_trigger **tp);
    相对应的注销函数为:
    void led_trigger_unregister_simple(struct led_trigger *trigger);
     
    触发器和led的连接
    void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger);//建立连接。建立连接的时候会调用触发器的activate方法
    void led_trigger_remove(struct led_classdev *led_cdev);//取消连接。取消连接的时候会调用触发器的deactivate方法
    void led_trigger_set_default(struct led_classdev *led_cdev);//在所有已注册的触发器中寻找led_cdev的默认触发器并调用 led_trigger_set建立连接
     
    最后总结一下led、led_classdev、led_trigger的关系:
     也就是说trigger好比是控制LED类设备的算法,这个算法决定着LED什么时候亮什么时候暗。LED trigger类设备可以是现实的硬件设备,比如IDE硬盘,也可以是系统心跳等事件。
  • 相关阅读:
    react 使用 redux 的时候 用 ref获取子组件的state
    node-rsa 非对称加密和解密
    electron 前端开发桌面应用
    react-router v4 使用 history 控制路由跳转
    react 写一个贪吃蛇
    【Java并发编程】:并发新特性—塞队列和阻塞栈
    【Java并发编程】:并发新特性—Executor框架与线程池
    【Java并发编程】:深入Java内存模型—内存操作规则总结
    【Java并发编程】:深入Java内存模型——happen-before规则及其对DCL的分析
    【Java并发编程】:加锁和volatile变量
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/6942106.html
Copyright © 2020-2023  润新知