三、Lights Hardware Interfaces
由com_android_server_LightsService.cpp源码中可知,它引入了hardware中的lights.h
路径hardware/libhardware/include/hardware/lights.h
lights.h的一些注释
//关键定义,暂时不知道是做什么用的 #ifndef ANDROID_LIGHTS_INTERFACE_H #define ANDROID_LIGHTS_INTERFACE_H /** * The id of this module 定义模块ID */ #define LIGHTS_HARDWARE_MODULE_ID "lights" /* * These light IDs correspond to logical lights, not physical. * So for example, if your INDICATOR light is in line with your * BUTTONS, it might make sense to also light the INDICATOR * light to a reasonable color when the BUTTONS are lit. * 这些LIGHT ID对应着逻辑上的Light,非物理上的。例如,如果您的指示灯与按钮一致,那么当按钮被点亮时,将指示灯点亮到一个合理的颜色也是有意义的 */ #define LIGHT_ID_BACKLIGHT "backlight" #define LIGHT_ID_KEYBOARD "keyboard" #define LIGHT_ID_BUTTONS "buttons" #define LIGHT_ID_BATTERY "battery" #define LIGHT_ID_NOTIFICATIONS "notifications" #define LIGHT_ID_ATTENTION "attention" /* * These lights aren't currently supported by the higher * layers, but could be someday, so we have the constants * here now. * 这几个类在将来可以能会被使用,先定义在这里 */ #define LIGHT_ID_BLUETOOTH "bluetooth" #define LIGHT_ID_WIFI "wifi" //关键引入 #include <hardware/hardware.h> //模式定义 /* * Flash modes for the flashMode field of light_state_t. * 不闪烁 */ #define LIGHT_FLASH_NONE 0 /** * To flash the light at a given rate, set flashMode to LIGHT_FLASH_TIMED, * and then flashOnMS should be set to the number of milliseconds to turn * the light on, followed by the number of milliseconds to turn the light * off. * 根据设定的时间闪烁 */ #define LIGHT_FLASH_TIMED 1 /** * To flash the light using hardware assist, set flashMode to * the hardware mode. * 由硬件控制进行闪烁 */ #define LIGHT_FLASH_HARDWARE 2 /** * Light brightness is managed by a user setting. 由用户设定背光亮度 */ #define BRIGHTNESS_MODE_USER 0 /** * Light brightness is managed by a light sensor. 由传感器自动设置背光亮度 */ #define BRIGHTNESS_MODE_SENSOR 1 //定义light_state_t 结构体 /** * The parameters that can be set for a given light. * 定义了Light对象所有可以设置的参数 * Not all lights must support all parameters. If you * can do something backward-compatible, you should. */ struct light_state_t { /** * The color of the LED in ARGB. * LED灯ARGS模式的颜色值 * Do your best here. * - If your light can only do red or green, if they ask for blue, * you should do green. * 如果你的灯只能做红色或绿色,如果他们要求蓝色,你应该设置为绿色 * - If you can only do a brightness ramp, then use this formula: * 如果你只做亮度渐变,那么使用下面这个公式: * unsigned char brightness = ((77*((color>>16)&0x00ff)) * + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8; * - If you can only do on or off, 0 is off, anything else is on. * 如果你只是开关LED,0为关闭,其它值 为打开 * The high byte should be ignored. Callers will set it to 0xff (which * would correspond to 255 alpha). */ unsigned int color; /** * See the LIGHT_FLASH_* constants */ int flashMode; //闪烁模式 int flashOnMS; //点亮时间 int flashOffMS; //熄灭时间 /** * Policy used by the framework to manage the light's brightness. * 框架使用的策略来管理灯光的亮度 * Currently the values are BRIGHTNESS_MODE_USER and BRIGHTNESS_MODE_SENSOR. */ int brightnessMode; }; //定义light_device_t 结构体 struct light_device_t { struct hw_device_t common; /** * Set the provided lights to the provided values. * * Returns: 0 on succes, error code on failure. 设置light参数 */ int (*set_light)(struct light_device_t* dev, struct light_state_t const* state); }; /*函数名称前面加指针符号“*”,代表它是函数指针。 *函数指针是一个指向函数的指针,函数指针表示一个函数的入口地址。使用函数指针的好处就是在处理“在运行时根据数据的具体状态来选择相应的处理方式”这种需求时更加灵活。 */
hardware.h
light.h中引用了hardware.h
路径hardware/libhardware/include/hardware/hardware.h
hardwared.h的一些注释
只看一些重要的方法
/** * Get the module info associated with a module by id. * 根据module id获取对应的module,例如获取Lights module的ID 就是LIGHTS_HARDWARE_MODULE_ID * @return: 0 == success, <0 == error and *module == NULL */ int hw_get_module(const char *id, const struct hw_module_t **module); //根据class id获取module,这里暂时不讨论 int hw_get_module_by_class(const char *class_id, const char *inst, const struct hw_module_t **module); //重要结构体有三个 struct hw_module_t; //数据结构的字段必须以hw_module_t开头 struct hw_module_methods_t; //然后公共方法 struct hw_device_t; //最后是模块特定信息 //第一个重要结构体 /** * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM * and the fields of this data structure must begin with hw_module_t * followed by module specific information. * 每个硬件模块都必须有一个名为HAL_MODULE_INFO_SYM的数据结构,该数据结构的字段必须以 * hw_module_t开头,然后是模块特定的信息。 */ typedef struct hw_module_t { /** tag must be initialized to HARDWARE_MODULE_TAG */ uint32_t tag; //TAG信息 uint16_t module_api_version; //module 的API版本信息 #define version_major module_api_version uint16_t hal_api_version; //hal层的API版本信息 #define version_minor hal_api_version /** Identifier of module */ const char *id; //module id /** Name of this module */ const char *name; //module名称 /** Author/owner/implementor of the module */ const char *author; //作者 /** Modules methods */ struct hw_module_methods_t* methods; //定义的方法 /** module's dso */ void* dso; /** padding to 128 bytes, reserved for future use */ uint32_t reserved[32-7]; } hw_module_t; //可以看到,hw_module_t定义了一些版本,作者和定义的方法等相关信息 //第二个结构体 typedef struct hw_module_methods_t { /** Open a specific device */ //函数指针 int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device); } hw_module_methods_t; //第三个结构体 /** * Every device data structure must begin with hw_device_t * followed by module specific public methods and attributes. * 每个设备数据结构都必须以hw_device_t开头,然后是模块特定的公共方法和属性。 */ typedef struct hw_device_t { /** tag must be initialized to HARDWARE_DEVICE_TAG */ uint32_t tag; uint32_t version; /** reference to the module this device belongs to */ struct hw_module_t* module; /** padding reserved for future use */ uint32_t reserved[12]; /** Close this device */ int (*close)(struct hw_device_t* device);//函数指针 } hw_device_t;
抽象接口实现 lights.c
路径vendor/xxx/open-source/libs/liblights/lights.c
注意:linux中的所有操作都是通过文件的形式,所以LED的最终操作也是通过读写节点文件来实现的
该类中提供了操作LED灯节点文件的方法,通过向节点文件写入数据,位于kernel下面的LED灯的驱动程序会检测到文件的改动,进而对LED的状态根据写入的值进行重新设定。
lights.c的一些注释
//定义所有的LED灯类型 //all lights enum { RED_LED, //红灯 GREEN_LED, //绿灯 BLUE_LED, //蓝灯 LCD_BACKLIGHT, //LCD背光灯 BUTTONS_LED, //按键背光灯 NUM_LEDS, //LED灯个数 }; //定义LED灯可操作的类型,实际对应了多个节点文件 struct led { struct led_prop brightness; //设置亮度 struct led_prop high_time; struct led_prop low_time; struct led_prop rising_time; struct led_prop falling_time; struct led_prop on_off; //开关 }; //定义生成的节点路径 //light nodes struct led leds[NUM_LEDS] = { [RED_LED] = { .brightness = { "/sys/class/leds/red/brightness", -1}, .high_time = { "/sys/class/leds/red_bl/high_time", -1}, .low_time = { "/sys/class/leds/red_bl/low_time", -1}, .rising_time = { "/sys/class/leds/red_bl/rising_time", -1}, .falling_time = { "/sys/class/leds/red_bl/falling_time", -1}, .on_off = { "/sys/class/leds/red_bl/on_off", -1}, }, [GREEN_LED] = { .brightness = { "/sys/class/leds/green/brightness", -1}, .high_time = { "/sys/class/leds/green_bl/high_time", -1}, .low_time = { "/sys/class/leds/green_bl/low_time", -1}, .rising_time = { "/sys/class/leds/green_bl/rising_time", -1}, .falling_time = { "/sys/class/leds/green_bl/falling_time", -1}, .on_off = { "/sys/class/leds/green_bl/on_off", -1}, }, [BLUE_LED] = { .brightness = { "/sys/class/leds/blue/brightness", -1}, .high_time = { "/sys/class/leds/blue_bl/high_time", -1}, .low_time = { "/sys/class/leds/blue_bl/low_time", -1}, .rising_time = { "/sys/class/leds/blue_bl/rising_time", -1}, .falling_time = { "/sys/class/leds/blue_bl/falling_time", -1}, .on_off = { "/sys/class/leds/blue_bl/on_off", -1}, }, [LCD_BACKLIGHT] = { .brightness = { "/sys/class/backlight/sprd_backlight/brightness", -1}, }, [BUTTONS_LED] = { .brightness = {"/sys/class/leds/keyboard-backlight/brightness", -1}, }, }; //初始化所有节点 void init_globals(void) { int i; for (i = 0; i < NUM_LEDS; ++i) { init_prop(&leds[i].brightness); init_prop(&leds[i].high_time); init_prop(&leds[i].low_time); init_prop(&leds[i].rising_time); init_prop(&leds[i].falling_time) init_prop(&leds[i].on_off); } } //看一下与hardwared.h对应的结构体 /*第一个结构体 * 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, }; //第二个结构体,通过open_lights获取所有公用函数 static struct hw_module_methods_t lights_module_methods = { //open是一个函数指针,这里赋值为open_lights,open_lights函数下面有介绍 .open = open_lights, //打开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); //从前面分析lights.h知道,set_light是一个函数指针,其作用就是这里根据不同的LED灯类型,设置不同的处理函数 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_BUTTONS, name)) set_light = set_light_buttons; else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) set_light = set_light_leds_notifications; else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) set_light = set_light_leds_attention; else if (0 == strcmp(LIGHT_ID_BATTERY,name)) 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; //设置TAG信息 dev->common.version = 0; //设置版本信息 dev->common.module = (struct hw_module_t *)module; //设置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 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; } } //其它的就是一些设置方法了,简述一下 static int set_light_backlight(struct light_device_t *dev, struct light_state_t const *state) static int set_light_keyboard(struct light_device_t* dev, struct light_state_t const* state) static int is_lit(struct light_state_t const* state) static int set_light_buttons(struct light_device_t* dev, struct light_state_t const* state) static int set_breath_light(struct light_device_t* dev, struct light_state_t const* state) ....
该文件可能需要根据具体使用的LED灯设备节点进行修改,可参考我另一篇文章Android4.4移植-LED灯驱动适配
四、驱动层
驱动文件一般位于kernel下面,根据不同的硬件厂商而有所不同。
驱动程序会监测上面提到的所有节点文件是否被写入,如果节点文件有写入不同的值,那么驱动程序会读取该值 ,并依据具体情况设定不同的LED灯状态。驱动文件详情不再详述。
如有问题,欢迎交流!!!