zoukankan      html  css  js  c++  java
  • Android灯光系统(1)——led_class驱动实现

    1.对灯光的要求

    (1)亮度可调节,如背光灯
    (2)颜色可变化,如电池电量指示灯
    (3)能闪烁,如通知灯


    2.Linux内核对led的支持

    在Linux内核中已经实现了一个led class, 它里面已经实现了brightness的调节和blink,文件为:drivers/leds/led-class.c
    在ledinit()中的led_class_attrs在/sys/class/leds下创建了brightness max_brightness trigger文件。


    3.使用Linux内核中的led class
    (1)配置内核
    make menuconfig选中:
    CONFIG_LEDS_CLASS
    CONFIG_LEDS_TRIGGERS
    CONFIG_LEDS_TRIGGER_TIMER
    (2)驱动编写流程
    a.分配led_classdev结构体
    b.设置
    c.注册
    可以参考leds-s3c24xx.c,驱动Demo如下:

    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/miscdevice.h>
    #include <linux/device.h>
    #include <linux/fs.h>
    #include <linux/types.h>
    #include <linux/moduleparam.h>
    #include <linux/slab.h>
    #include <linux/ioctl.h>
    #include <linux/cdev.h>
    #include <linux/delay.h>
    
    #include <linux/gpio.h>
    #include <mach/gpio.h>
    #include <plat/gpio-cfg.h>
    
    #include <linux/leds.h>
    
    struct led_desc {
        int gpio;
        char *name;
    };
    
    /*三星的goio引脚根本就不需要获取就可以直接使用*/
    static struct led_desc led_gpios[] = {
        {EXYNOS4212_GPM4(0), "led1"},
        {EXYNOS4212_GPM4(1), "led2"},
        {EXYNOS4212_GPM4(2), "led3"},
        {EXYNOS4212_GPM4(3), "led4"},
    };
    
    struct led_classdev_4412 {
        struct led_classdev cdev; /*核心结构体*/
        int gpio; /*每一个led绑定的gpio*/
    };
    
    
    static struct led_classdev_4412 *led_devs;
    
    static void     brightness_set_4412(struct led_classdev *led_cdev,
                  enum led_brightness brightness)
    {
        struct led_classdev_4412 *dev = (struct led_classdev_4412 *)led_cdev;
    
        led_cdev->brightness = brightness;
    
        if (brightness != LED_OFF)
            gpio_set_value(dev->gpio, 0); /*打开led*/
        else
            gpio_set_value(dev->gpio, 1); /*关闭led*/
    }
    
    
    static int leds_init(void)
    {
        int i;
        int ret;
    
        /* 1. alloc led_classdev */
        led_devs = kzalloc(sizeof(struct led_classdev_4412) * ARRAY_SIZE(led_gpios), GFP_KERNEL);
        if (led_devs == NULL) {
            printk("No memory for device
    ");
            return -ENOMEM;
        }
    
        for (i = 0; i < ARRAY_SIZE(led_gpios); i++)
        {
            s3c_gpio_cfgpin(led_gpios[i].gpio, S3C_GPIO_OUTPUT);
            /*默认led全部关闭*/
            gpio_set_value(led_gpios[i].gpio, 1);
    
            /* 2. set 这里面哪些域需要设置由led-class.c的实现决定的*/
            led_devs[i].cdev.max_brightness = LED_FULL;
            led_devs[i].cdev.brightness_set = brightness_set_4412;
            led_devs[i].cdev.flags = LED_CORE_SUSPENDRESUME;
            led_devs[i].cdev.brightness = LED_OFF;
            led_devs[i].cdev.name = led_gpios[i].name;
            led_devs[i].gpio = led_gpios[i].gpio;
    
            //led_devs[i].cdev.default_trigger = "timer";
            //led_devs[i].cdev.blink_delay_on = 100;
            //led_devs[i].cdev.blink_delay_off = 900;
    
            /* 3. led_classdev_register */
            ret = led_classdev_register(NULL, &led_devs[i].cdev);
            if (ret) {
                i--;
                while (i >= 0) {
                    led_classdev_unregister(&led_devs[i].cdev);
                    i--;
                }
                kfree(led_devs);
                return -EIO;
            }
        }
    
        return 0;
    }
    
    static void leds_exit(void)
    {
        int i;
        for (i = 0; i < ARRAY_SIZE(led_gpios); i++)
        {
            led_classdev_unregister(&led_devs[i].cdev);
        }
        kfree(led_devs);
    }
    
    module_init(leds_init);
    module_exit(leds_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Mr.Sun");
    View Code

    重新编译内核启动后,会在/sys/class/leds下看到led1——led4

    4.应用程序设置方法
    应用程序是通过sysfs文件来控制led的。

    # echo 255 > /sys/class/leds/led1/brightness 点亮
    # echo 0 > /sys/class/leds/led1/brightness 熄灭

    # echo timmer > /sys/class/leds/led1/trigger 此时led1就应该在以1HZ频率闪烁了。之后此目录下会多出delay_on/delay_off两个文件
    配置它两个可以配置闪烁行为。

    echo none > trigger 和 echo 0 > brightness 都会使led不在依附trigger。

    5.也可以在驱动代码里面设置默认的trigger,让led一上电就开始闪动。

    6.这个显示效果还是可以借鉴一下的,由led_trigger_show()实现的,括起来的是led目前attach的trigger,其它是系统中还存在的trigger。
    shell@tiny4412:/sys/class/leds/led1 # cat trigger
    none mmc0 mmc1 mmc2 [timer]


    7.从这里看不但可以指定class的sysfs属性文件,还可以指定dev的!

    struct class {
        ...
        struct class_attribute  *class_attrs;
        struct device_attribute *dev_attrs;
        struct bin_attribute    *dev_bin_attrs;
        ...
    }

    class_create()时指定的属性在每一个依此class创建的设备文件的sysfs目录中都存在。见leds-class.c中的leds_init()。

    8.device_create()只是创建设备模型,并不会在/dev/下创建设备文件
    如led_classdev_register中调用了device_create但是并没有/dev/下的设备文件。
    led_cdev->dev = device_create(leds_class, parent, 0, led_cdev, "%s", led_cdev->name); //无论arg3是否为0测试都不会创建设备文件。


    9.list_for_each_entry的使用

    来自led_trigger_show():
    trig: 空闲变量指针
    trigger_list: 单链表的链表头
    next_trig: 构成链表的next指针成员
    list_for_each_entry(trig, &trigger_list, next_trig) {use trig...}

  • 相关阅读:
    阿里云在云栖大会发布SaaS加速器3.0版最新成果,让天下没有难做的SaaS
    阿里云重磅发布全域集成解决方案,帮助提升5倍全域集成效率
    2019亚太内容分发大会,阿里云获CDN领袖奖、技术突破奖
    阿里云应用上边缘云解决方案助力互联网All in Cloud
    云栖大会压轴好戏 阿里云智能视频云专场划重点啦!
    阿里云研究员金戈:视频云新“三网一云”,驱动行业应用创新
    阿里云启动视频云V5计划,全面赋能生态合作伙伴
    数据库实例性能调优利器:Performance Insights
    n转m进制标准写法(必须记忆)
    傻逼暴力法画蛇皮矩阵图
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10812183.html
Copyright © 2011-2022 走看看