Android灯光系统
1.Linux的leds class驱动
-
Android 系统的灯光很多:
电池指示灯,按键灯,键盘灯,屏幕亮度调节灯 -
打开安卓源码 /home/topeet/Android/iTop4412_ICS_git/hardware/libhardware/include/hardware/lights.h
可以看到有八种逻辑上的灯光
-
在Android系统中灯光的使用方式有哪些
brightness: 0-255不同数值对应不同的亮度 或者只有亮灭 OFF-0/ON-255
color RGB
blink 亮nms 灭nms,可以通过定时器实现闪烁功能 -
以前的驱动程序只有控制等的亮灭,满足不了android系统应用。比如我们要实现闪烁功能,可以自己用定时器,设置亮灭的时间来操作,比较麻烦。
-
实际中我们也不需要从0开始写灯光系统驱动,在linux内核已经有了Led class驱动程序,它已经实现了设置brightness,和闪烁blink的功能
源码路径 源码 drivers/leds/Led-class.c,可以找到入口函数
在入口函数中创建class,这个class有dev_attrs这个设备属性
这是一个数组里边有三个属性
我们想设置brightness,我们可通过 这个语句设置
echo 255 > sys/class/leds/led1/brightness
通过这样的语句设置亮度brightness数值,最终会导致这个属性的led_brightness_store会被调用
在这个函数中,手续获得一个led_classdev,然后把buf中的字符串转化为整数state,最后调用函数led_set_brightness()
这个函数通过led_cdev中的brightness_set来设置led的亮度。
cat sys/class/ldes/led1/max_brightness
这个语句只能读取max_brightness,函数led_max_brightness_show就会被调用
-
怎么写驱动:
-
1.分配led_classdev
-
2.设置
led_cdev->max_brightness
led_cdev->brightness_set()
led_cdev->flags
led_cdev->brightness
led_cdev->name -
3.注册:led_classdev_register()
-
如果我们通过这个语句获取brightness的数值,那么这个函数就会被执行
cat sys/class/ldes/led1/brightness
这个函数中首先得到一个led_classdev然后,返回这个结构体的成员brightness
2. 编写leds驱动程序
- leds_4412.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
//#include <mach/gpio-bank.h>
#include <mach/regs-gpio.h>
#include <asm/io.h>
#include <linux/regulator/consumer.h>
//#include "gps.h"
#include <linux/delay.h>
#include <linux/leds.h>
#define LEDS_DEBUG
#ifdef LEDS_DEBUG
#define DPRINTK(x...) printk("LEDS_CTL DEBUG:" x)
#else
#define DPRINTK(x...)
#endif
#define DRIVER_NAME "leds"
struct led_desc{
int gpio;
char *name;
};
static struct led_desc led_gpios[] = {
{EXYNOS4_GPL2(0),"led1"},
{EXYNOS4_GPK1(1),"led2"},
};
#define LED_NUM ARRAY_SIZE(led_gpios)
struct led_classdev_4412 {
struct led_classdev cdev;
int gpio;
};
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->blink_brightness = brightness;
if(brightness != LED_OFF)
gpio_set_value(dev->gpio, 0);
else
gpio_set_value(dev->gpio, 1);
}
static struct led_classdev_4412 *led_devs;
static int __init leds_init(void)
{
int i,ret;
/*1. alloc led_classdev */
led_devs = kzalloc(sizeof(struct led_classdev_4412)*LED_NUM, GFP_KERNEL);
if (led_devs == NULL) {
printk("No memory for device\n");
for (i = 0;i < LED_NUM;i++)
{
s3c_gpio_cfgpin(led_gpios[i].gpio, S3C_GPIO_OUTPUT);
gpio_set_value(led_gpios[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_devs[i].cdev.name = led_gpios[i].name;
led_devs[i].gpio = led_gpios[i].gpio;
/* 3. 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;
}
}
}
static void __exit leds_exit(void)
{
int i = 0;
for (i = 0;i < LED_NUM;i++)
{
led_classdev_unregister(&led_devs[i]);
}
kfree(led_devs);
}
module_init(leds_init);
module_exit(leds_exit);
MODULE_LICENSE("Dual BSD/GPL");
- 将leds_4412.c上传到drivers/leds目录
- 修改目录下drivers/leds 的makefile文件
添加 obj-y += leds_4412.o
另外需要添加配置项,CONFIG_LEDS_CLASS CONFIG_LEDS_TRIGGERS
trigger是用来控制led闪烁的,它需要定时器,CONFIG_LEDS_TRIGGER_TIMER
- make menuconfig 配置以上选项
- 编译成功,重新烧录内核,重启itop4412开发板
- 发送一下语句,看看到开发板两个灯的亮灭
- 如何让led实现闪烁
可以看到设备led1有trigger,cat trigger
none表示当前的触发器为none,可以把trigger触发器设置为后边这三种,我们把timer设置到trigger中,看效果
可以看到led1闪烁,并且目录下出现了一些文件。
可以设置led的闪烁亮灭时间
- 分析
echo timer > /sys/class/leds/led1/trigger
当把timer 写到文件sys/class/leds/led1/trigger中时,led_trigger_store被调用
首先trigger_name把buf中把name取出来,如果trigger等于none什么都不做返回,从triggerlist中找出相同名字的,如果相等,调用led_trigger_set(),把trigger放入到led_classdev的trigger_list链表中,