Android4.4移植-LED灯驱动适配

简介: 笔记

因为项目中用到的LED灯与安卓原生的不太一样,需要对驱动进行适配,修改驱动接口文件。

注:本贴只示例了修改LED灯驱动接口文件

目标文件位置:vendor/xxx/open-source/libs/liblights/lights.c


修改的一些注释


#define LOG_TAG "LIGHTS"
#include <cutils/log.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <hardware/lights.h>
static pthread_once_t g_init = PTHREAD_ONCE_INIT;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
//结构体:LED对应的文件节点路径和句柄
struct led_prop {
    const char *filename;
    int fd;
};
//结构体:每个LED可操作的节点,根据使用的LED灯设备来进行定义
struct led {
    struct led_prop brightness; //亮度
    struct led_prop delay_on;   //闪烁时熄灭时长
    struct led_prop delay_off;  //闪烁时点亮时长
    struct led_prop triggers;   //闪烁时的亮度
};
//定义所有的LED灯,这里只用了三个
enum {
    RED_LED,    //红色LED灯
    GREEN_LED,  //绿色LED灯
    LCD_BACKLIGHT,  //LCD背光灯
    BUTTONS_LED,    //按键背光灯
    NUM_LEDS,
};
//定义LED文件节点,一定要根据LED驱动程序指定的路径进行填写
struct led leds[NUM_LEDS] = {
    [RED_LED] = {
        .brightness = { "/sys/class/leds/red/brightness", 0}, //正常亮度
        .delay_on = { "/sys/class/leds/red/delay_on", 0},   //LED闪烁熄灭时长
        .delay_off = { "/sys/class/leds/red/delay_off", 0}, //LED闪烁点亮时长
        .triggers = { "/sys/class/leds/red/triggers", 0},     //LED闪烁时的亮度
    },
    [GREEN_LED] = {
        .brightness = { "/sys/class/leds/green/brightness", 0},
        .delay_on = { "/sys/class/leds/green/delay_on", 0},
        .delay_off = { "/sys/class/leds/green/delay_off", 0},
        .triggers = { "/sys/class/leds/green/triggers", 0},
    },
    [LCD_BACKLIGHT] = {
        .brightness = { "/sys/class/backlight/sprd_backlight/brightness", -1},
    },
    [BUTTONS_LED] = {
        .brightness = {"/sys/class/leds/keyboard-backlight/brightness", -1},
    },
};
void init_g_lock(void)
{
        pthread_mutex_init(&g_lock, NULL);
}
//初始化所有节点,即打开节点文件获得句柄
void init_globals(void)
{
    int i;
    for (i = 0; i < NUM_LEDS; ++i) {
        init_prop(&leds[i].brightness);
        init_prop(&leds[i].delay_on);
        init_prop(&leds[i].delay_off);
        init_prop(&leds[i].triggers);
    }
}
//初始化一个节点
static int init_prop(struct led_prop *prop)
{
    int fd;
    prop->fd = -1;
    if (!prop->filename)
        return 0;
    //打开文件
    fd = open(prop->filename, O_RDWR);
    if (fd < 0) {
        ALOGE("init_prop: %s cannot be opened (%s)\n", prop->filename,
             strerror(errno));
        return -errno;
    }
    //获得句柄
    prop->fd = fd;
    return 0;
}
//写数据到指定文件,是实际对LED节点进行写操作的方法
static int write_int(struct led_prop *prop, int value)
{
        int fd;
        static int already_warned;
        already_warned = 0;
        ALOGE("file:%s, func:%s, path=%s, value=%d\n", __FILE__, __func__, prop->filename, value);
     //   fd = open(path, O_RDWR);
          fd = open(prop->filename, O_RDWR);
        if (fd >= 0) {
                char buffer[20];
                int bytes = sprintf(buffer, "%d\n", value);
                int amt = write(fd, buffer, bytes);
                close(fd);
                return amt == -1 ? -errno : 0;
        } else {
                if (already_warned == 0) {
                        ALOGE("file:%s, func:%s, failed to open %s,fd = %d\n", __FILE__, __func__, prop->filename,fd);
                        already_warned = 1;
                }
                return -errno;
        }
}
//RGB颜色转化为亮度值,其实就是取出颜色值
static int rgb_to_brightness(struct light_state_t const *state)
{
        int color = state->color & 0x00ffffff;
        return ((77*((color>>16) & 0x00ff))
                + (150*((color>>8) & 0x00ff)) + (29*(color & 0x00ff))) >> 8;
}
//设置背光灯亮度
static int set_light_backlight(struct light_device_t *dev, struct light_state_t const *state)
{
        int err = 0;
        int brightness = rgb_to_brightness(state);
        ALOGD("file:%s, func:%s, brightness=%d\n", __FILE__, __func__, brightness);
        if(NULL==leds[LCD_BACKLIGHT].brightness.filename) {
                ALOGE("file:%s, func:%s, unsupported light!\n", __FILE__, __func__);
                return -EINVAL;
        }
        pthread_mutex_lock(&g_lock);
        err = write_int(&leds[LCD_BACKLIGHT].brightness, brightness);
        pthread_mutex_unlock(&g_lock);
        return err;
}
//判断LED灯是否被点亮,颜色值也代表了亮度0-255
static int is_lit(struct light_state_t const* state)
{
        return state->color & 0x00ffffff;//返回颜色值
}
//设置按键背光
static int set_light_keyboard(struct light_device_t* dev, struct light_state_t const* state)
{
        int err = 0;
        int on = is_lit(state);
        ALOGD("file:%s, func:%s, on=%d\n", __FILE__, __func__, on);
        if(NULL==LIGHT_KEYBOARD) {
                ALOGE("file:%s, func:%s, unsupported light!\n", __FILE__, __func__);
                return -EINVAL;
        }
        pthread_mutex_lock(&g_lock);
        err = write_int(LIGHT_KEYBOARD, on?255:0);
        pthread_mutex_unlock(&g_lock);
        return err;
}
//关闭LED灯
static int close_lights(struct light_device_t *dev)
{
        int i;
        ALOGV("file:%s, func:%s\n", __FILE__, __func__);
        for (i = 0; i < NUM_LEDS; ++i) {
            close_prop(&leds[i].brightness);
            close_prop(&leds[i].delay_on);
            close_prop(&leds[i].delay_off);
            close_prop(&leds[i].triggers);
        }
        if (dev)
                free(dev);
        return 0;
}
// 设置彩色LED灯,因为只用到了红灯和绿灯,所以只设置了两种灯
static int set_lights(struct light_device_t* dev, struct light_state_t const* state)
{
        int len;
        int value;
        unsigned int colorRGB;
        unsigned int colorR;
        unsigned int colorG;
        unsigned int colorB;
        unsigned int brightness, delay_on,delay_off,triggers;
        colorRGB = state->color & 0xFFFFFF;
        if (colorRGB == 0xFFFFFF) { /* white */
            colorRGB = 0x0;
        }
        colorR = (colorRGB >> 16) & 0x00ff;
        colorG = (colorRGB >> 8) & 0x00ff;
        colorB = colorRGB & 0x00ff;
        ALOGD("file:%s, func:%s, colorR=%d,colorG=%d,colorB=%d\n", __FILE__, __func__, colorR,colorG,colorB);
        ALOGD("file:%s, func:%s, state->flashMode=%d\n", __FILE__, __func__, state->flashMode);
        pthread_mutex_lock(&g_lock);
        //设置闪烁模式
        switch (state->flashMode) {
            case LIGHT_FLASH_HARDWARE:
            case LIGHT_FLASH_TIMED:
                    delay_on = state->flashOnMS;
                    delay_off = state->flashOffMS;
                    break;
            case LIGHT_FLASH_NONE:
            default:
                    delay_on = 0;
                    delay_off = 0;
                    break;
                ALOGD("set_led_state colorRGB=%08X, unknown mode %d\n",
                      colorRGB, state->flashMode);
        }
        if(delay_on > 0 && delay_off > 0){
            if (colorR) {   //注意要先设置delay_on和delay_off,再设置triggers
                triggers = colorR; //颜色值即代表亮度值
                write_int(&leds[RED_LED].delay_on, delay_on);
                write_int(&leds[RED_LED].delay_off, delay_on);
                write_int(&leds[RED_LED].triggers, triggers);
            } else {  /*off*/
                write_int(&leds[RED_LED].triggers, 0);
                write_int(&leds[RED_LED].brightness, 0);
            }
            if (colorG) {
                triggers = colorG;
                write_int(&leds[GREEN_LED].delay_on, delay_on);
                write_int(&leds[GREEN_LED].delay_off, delay_on);
                write_int(&leds[GREEN_LED].triggers, triggers);
            } else {  /*off*/
                write_int(&leds[GREEN_LED].triggers, 0);
                write_int(&leds[GREEN_LED].brightness, 0);
            }
        }
        else{
            if (colorR) {
                brightness = colorR;
                write_int(&leds[RED_LED].brightness, brightness);
            } else {  /*off*/
                write_int(&leds[RED_LED].brightness, 0);
                write_int(&leds[RED_LED].triggers, 0);
                write_int(&leds[RED_LED].delay_on, 0);
                write_int(&leds[RED_LED].delay_off, 0);
            }
            if (colorG) {
                brightness = colorG;
                write_int(&leds[GREEN_LED].brightness, brightness);
            } else {  /*off*/
                write_int(&leds[GREEN_LED].brightness, 0);
                write_int(&leds[GREEN_LED].triggers, 0);
                write_int(&leds[GREEN_LED].delay_on, 0);
                write_int(&leds[GREEN_LED].delay_off, 0);
            }
        }
        pthread_mutex_unlock(&g_lock);
        return 0;
}
//设置通知LED指示灯,其实调用了set_lights
static int set_light_leds_notifications(struct light_device_t *dev, struct light_state_t const *state)
{
        ALOGE("file:%s, func:%s, light!\n", __FILE__, __func__);
        set_lights(dev, state);
        return -EINVAL;
}
//设置警示灯,也调用了set_lights
static int set_light_leds_attention(struct light_device_t *dev, struct light_state_t const *state)
{
        ALOGE("file:%s, func:%s, light!\n", __FILE__, __func__);
        set_lights(dev, state);
        return -EINVAL;
}
//打开LED灯
static int open_lights(const struct hw_module_t *module, char const *name,
                       struct hw_device_t **device)
{
        int (*set_light)(struct light_device_t *dev,
                         struct light_state_t const *state);
        ALOGV("file:%s, func:%s name=%s\n", __FILE__, __func__, name);
        //根据LED灯的ID值,为函数指针set_light设置不同的函数
        if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))  //背光灯
                set_light = set_light_backlight;
        else if (0 == strcmp(LIGHT_ID_KEYBOARD, name))//键盘灯
                set_light = set_light_keyboard;
        else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))//绿色LED灯
                set_light = set_light_leds_notifications;
        else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) //红色LED灯
                set_light = set_light_leds_attention;
        else if (0 == strcmp(LIGHT_ID_BATTERY,name))    //绿色LED灯
                set_light = set_light_leds_notifications;
        else
                return -EINVAL;
        pthread_once(&g_init, init_g_lock);
//      pthread_once(&g_init, init_globals);
        struct light_device_t *dev = malloc(sizeof(struct light_device_t));
        memset(dev, 0, sizeof(*dev));
        //设置一些其它信息
        dev->common.tag = HARDWARE_DEVICE_TAG;
        dev->common.version = 0;
        dev->common.module = (struct hw_module_t *)module;
        dev->common.close = (int (*)(struct hw_device_t *))close_lights;
        dev->set_light = set_light;
        *device = (struct hw_device_t *)dev;
        return 0;
}
static struct hw_module_methods_t lights_module_methods = {
        .open =  open_lights,
};
/*
 * The lights Module
 */
struct hw_module_t HAL_MODULE_INFO_SYM = {
        .tag = HARDWARE_MODULE_TAG,
        .version_major = 1,
        .version_minor = 0,
        .id = LIGHTS_HARDWARE_MODULE_ID,
        .name = "lights Module",
        .author = "Google, Inc.",
        .methods = &lights_module_methods,
};
//关闭节点
static void close_prop(struct led_prop *prop)
{
    int fd;
    if (prop->fd > 0)
        close(prop->fd);    //关闭文件
    return;
}


目录
相关文章
|
8月前
|
XML 开发工具 Android开发
|
4月前
|
调度 Android开发 UED
Android经典实战之Android 14前台服务适配
本文介绍了在Android 14中适配前台服务的关键步骤与最佳实践,包括指定服务类型、请求权限、优化用户体验及使用WorkManager等。通过遵循这些指南,确保应用在新系统上顺畅运行并提升用户体验。
283 6
|
5月前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(五):基于GPIO、LED子系统的LED驱动
这篇文章是关于如何在基于Amlogic T972的Android 9.0系统上,使用GPIO和LED子系统来实现LED驱动的教程,包括了DTS设备树配置、驱动源码编写以及如何在用户空间控制LED的亮度和开关。
149 0
基于Amlogic 安卓9.0, 驱动简说(五):基于GPIO、LED子系统的LED驱动
|
5月前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
本文介绍了如何在基于Amlogic T972的Android 9.0系统上使用Platform平台驱动框架和设备树(DTS),实现设备与驱动的分离,并通过静态枚举在设备树中描述设备,自动触发驱动程序的加载和设备创建。
90 0
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
|
5月前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
如何使用Amlogic T972安卓9.0系统上的misc框架来简化驱动程序开发,通过misc框架自动分配设备号并创建设备文件,从而减少代码量并避免设备号冲突。
60 0
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
|
5月前
|
Android开发 C语言
基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
这篇文章是关于如何在基于Amlogic T972的Android 9.0系统上,通过自动分配设备号和自动创建设备节点文件的方式,开发字符设备驱动程序的教程。
86 0
基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
|
5月前
|
自然语言处理 Shell Linux
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
本文是关于在Amlogic安卓9.0平台上创建字符设备驱动的教程,详细介绍了驱动程序的编写、编译、部署和测试过程,并提供了完整的源码和应用层调用示例。
122 0
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
|
5月前
|
传感器 Android开发 芯片
不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动
本文是系列文章的第三篇,展示了如何在Android系统中利用现有的i2c bus驱动,通过编写设备树节点和应用层的控制代码,实现对基于i2c bus的Slaver设备(如六轴陀螺仪模块QMI8658C)的控制,而无需编写设备驱动代码。
62 0
不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动
|
5月前
|
Android开发
不写一行代码(二):实现安卓基于PWM的LED设备驱动
本文介绍了在Android系统中不编写任何代码,通过设备树配置和内核支持的通用PWM LED驱动来实现基于PWM的LED设备驱动,并通过测试命令调整LED亮度级别。
68 0
不写一行代码(二):实现安卓基于PWM的LED设备驱动
|
5月前
|
Linux Android开发 C语言
不写一行代码(一):实现安卓基于GPIO的LED设备驱动
本文通过实践操作,展示了在Android系统中不编写任何代码,利用设备树(DTS)配置和内核支持的通用GPIO LED驱动来控制LED设备,并进一步通过C语言编写NDK测试APP来实现LED的闪烁效果。
221 0
不写一行代码(一):实现安卓基于GPIO的LED设备驱动