• 8.2 Android灯光系统_led_class驱动


    android-5.0.2hardwarelibhardwareincludehardwarelights.h  //系统一些宏定义

    android源码只带的灯光驱动在linux内核的driver/leds/led-class.c中,其是led驱动的顶层框架文件

    该驱动的提供的功能在leds_class->dev_attrs = led_class_attrs;//在led_class_attrs提供了设备属性,当通过echo或cat访问设备节点的时候会导致响应的函数被调用

    //只带驱动提供的方法

    echo 255 > /sys/class/leds/led1/brightness//设置亮度
    cat /sys/class/leds/led1/brightness//获取当前亮度值
    cat /sys/class/leds/led1/max_brightness//获取最大亮度值

    闪烁

    //可以在注册led_classes之前设置trigger,eg:led_devs[i].cdev.default_trigger = "timer",这样就可以不用echo timer了
    echo timer > /sys/class/leds/led1/trigger  //表示使用定时器作为触发器
    echo 100 > /sys/class/leds/led1/delay_on //设置点亮时间
    echo 200 > /sys/class/leds/led1/delay_off  //设置熄灭时间

    关闭
    echo 0 > /sys/class/leds/led1/delay_on

    echo 0 > /sys/class/leds/led1/brightness


    分析闪烁功能:
    echo timer > /sys/class/leds/led1/trigger // timer对应 ledtrig-timer.c

    //在led-classes.c文件中数组led_class_attrs[]设置的dev的三个属性,其中一个是trigger,在led1下会根据这里的属性创建节点以及操作节点是对应的函数

    eg:__ATTR(trigger,0644,led_trigger_show,led_trigger_store)//echo节点导致led_trigger_store被调用,cat节点导致led_trigger_show被调用

    led_trigger_store // 1. 从trigger_list找出名为"timer"的trigger
      list_for_each_entry(trig, &trigger_list, next_trig) {
        if (!strcmp(trigger_name, trig->name)) {
          // 2. 调用
          led_trigger_set(led_cdev, trig);
            // 3. 把trigger放入led_classdev的trig_list链表里
            list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
            led_cdev->trigger = trigger;
            // 4.
            trigger->activate(led_cdev);
              // 5. 对于"timer",在ledtring-timer.c中定义
              timer_trig_activate
                // 6. 创建2个文件: delay_on, delay_off,同时制定读写这两个文件时调用的函数
                device_create_file  
                device_create_file
                led_blink_set // 让LED闪烁,会传入默认的点亮时间、熄灭时间,值都可以在led_classdev中设置
                  led_set_software_blink
                    mod_timer();

        }
      }


    echo 100 > /sys/class/leds/led1/delay_on
    led_delay_on_store(,,buf,size)//这里的buf中存放的是字符串“100”
      state = simple_strtoul(buf, &after, 10);
      led_blink_set // // 让LED闪烁
      led_cdev->blink_delay_on = state;//并且在led_classes结构体中保存时间

    echo 200 > /sys/class/leds/led1/delay_off
    led_delay_off_store
      state = simple_strtoul(buf, &after, 10);
      led_blink_set // 让LED闪烁
      led_cdev->blink_delay_off = state;

    怎么写驱动:
    a1. 分配led_classdev
    a2. 设置 :
    led_cdev->max_brightness
    led_cdev->brightness_set
    led_cdev->flags
    led_cdev->brightness
    led_cdev->name

    a3. 注册 : led_classdev_register

    驱动代码举例:

    example1:

    //头文件

    struct led_desc{

      int gpio;

      char *name;

    };

    static struct led_desc[] = {

      {EXYNOS4212_GPM(0),"led4"},

      {EXYNOS4212_GPM(1),"led4"},

      {EXYNOS4212_GPM(2),"led4"},

      {EXYNOS4212_GPM(3),"led4"},

    };

    //构造一个结构体用来保存led_classdec与之对应的led灯

    struct led_classdev_4412{

      struct led_classdev cdev;

      int 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);

      }

      else

      {

        gpio_set_value(dev->gpio,1);

      }

    }

    static int leds_init(void)

    {

      int i;

      int ret;

      /*1、alloc  led_classdev 为我们的四个led灯分配led_classdev结构体*/

      led_devs = kzalloc(sizeof(struct led_classdev_4412)*sizeof(led_gpios)/sizeof(led_gpios[0]),GFP_KERNEL);

      if(led_devs == NULL){

        printk("No memory for device ");

        return -ENOMEM;

      }  

      for(i = 0;i<sizeof(led_gpios)/sizeof(led_gpios[0];i++)

      {

        s3c_gpio_cfgpin(led_gpios[i].gpio,S3C_GPIO_OUTPUT);//设置为输出引脚  

        gpio_set_value(led_gpio[i].gpio,1);//熄灭灯

        /*2、set*/

        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值

        led_devs[i].cdev.name= led_gpios[i].name;///sys/class/leds/下创建节点

        led_devs[i].gpio = led_gpios[i].gpio;

        /*3、led_classdev_register*/

        ret = led_classes_register(NULL,&led_devs[i].cdev);

        if(ret){

          i--;

          while(i >=0){

            led_classes_unregister(&led_devs[i].cdev);

            i--;

          }

          kfree(led_devs);

          return -EIO;

        }

      }

    }

    static void leds_exit(void)

    {

      int i;

      for(i = 0;i<sizeof(led_gpios)/sizeof(led_gpios[0];i++)

      {

        led_classes_unregister(&led_devs[i].cdev);

      ]

      kfree(led_devs);

    }

    module_init(leds_init);

    module_exit(leds_exit);

    MODULE_LICENSE("GPL");

    注意:我们的驱动程序是嵌入到linux的led驱动框架中去的

    把 leds_4412.c 放到drivers/leds
    修改 drivers/leds/Makefile:
    obj-y += leds_4412.o 

    make menuconfig

    CONFIG_LEDS_CLASS
    CONFIG_LEDS_TRIGGERS
    CONFIG_LEDS_TRIGGER_TIMER

    -> Device Drivers
      -> LED Support
        [*] LED Class Support 
        [*] LED Trigger support  //实现定时器功能,led闪烁依赖定时器
        <*> LED Timer Trigger

    make zImage

    关掉开发板,设置为SD卡启动,使用minitools烧写Android Kernel:zImage

    关掉开发板,设置为nand启动

    ls /sys/class/leds   会发现有了led1、led2、led3、led4

  • 相关阅读:
    如何招到一个靠谱的程序员_转
    区块链blockchina简述
    TCP和UDPsocket中SO_SNDBUF和SO_RCVBUF_转
    Medium开发团队谈架构设计_转
    cgi与fastcgi区别_转
    RESTful
    各种开源协议介绍 BSD、Apache Licence、GPL V2 、GPL V3 、LGPL、MIT_转
    mosquitto简单应用
    组播MAC地址_转
    纳德拉再造微软:如何重回第一阵营?
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/9129114.html
Copyright © 2020-2023  润新知