HAL层分析
编者:厦门大学航空航天学院机电系2015级研究生王凯,能源学院能效工程2015级研究生王猛
目录:bdk/hardware/bsp/intel/peripheral/light/mraa
1.open_lights函数
函数目的:打开背光灯
static int open_lights(const struct hw_module_t *module, char const *name,
struct hw_device_t **device)
{
struct light_device_ext_t *dev;
int rc = 0, type = -1;
ALOGV("%s: Opening %s lights module", __func__, name);
首先定义了一个struct light_device_ext_t *dev;
ALOGV("%s: Opening %s lights module", __func__, name);
这个是打印相关的信息,首先我们需要定义一个TAG;
比如:
#define LOG_TAG "lights"
这个LOG_TAG在21行定义过。这样将来logcat出来的东西就是这样的:
V/lights(422):hardware/bsp/intel/peripheral/light/mraa/lights.c: Opening ... lights module
这里的就是传进来的name参数。
//
if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
type = NOTIFICATIONS_TYPE;
} else {
return EINVAL;
}
接着看传进来的name参数是不是LIGHT_ID_NOTIFICATIONS,这个定义为:
#define LIGHT_ID_NOTIFICATIONS "notifications"
如果不相等,那么直接返回打开不成功标志EINVAL。
//
然后初始化dev变量
dev = (struct light_device_ext_t *)(light_devices + type);
pthread_mutex_lock(&dev->write_mutex);
if (dev->refs != 0) {
/* already opened; nothing to do */
goto inc_refs;
}
接下来是先将线程互斥锁定,然后在进行操作,这样比较安全,最后记得取消锁定。 之后就判断dev是否已经打开了,判断的方法是判断refs的引用次数,如果引用次数大于0,那么就表示已经打开了,然后直接引用加1返回打开成功标志。
//
接下来是模型初始化
rc = init_module(type);
if (rc != 0) {
ALOGE("%s: Failed to initialize lights module", __func__);
goto mutex_unlock;
}
模型初始化是将全局变量
struct light_device_ext_t light_devices[] = {[ 0 ... (LIGHTS_TYPE_NUM - 1) ] = { .write_mutex = PTHREAD_MUTEX_INITIALIZER}};
给初始化。如果初始化失败,那么打印出失败信息,同时返回rc失败标志。
//
接下来是背光灯同步源初始化,也就是创建一个新的线程
rc = init_light_sync_resources(&dev->flash_cond,&dev->flash_signal_mutex);
if (rc != 0)
{
goto mutex_unlock;
}
同样如果没有成功就返回rc失败标志。
//
接下来是设备信息更新,给dev变量赋值。接下来是引用加1,然后线程锁解锁。
dev->base_dev.common.tag = HARDWARE_DEVICE_TAG;
dev->base_dev.common.version = 0;
dev->base_dev.common.module = (struct hw_module_t *)module;
dev->base_dev.common.close = (int (*)(struct hw_device_t *))close_lights;
dev->base_dev.set_light = set_light_generic;
inc_refs:
dev->refs++;
*device = (struct hw_device_t *)dev;
mutex_unlock:
pthread_mutex_unlock(&dev->write_mutex);
return rc;
2.close_lights函数
函数目的:关闭背光灯
//
首先对传进来的参数进行正确性判断,如果是NULL就打印失败信息,同时返回关闭失败标志。
static int close_lights(struct light_device_t *base_dev)
{
struct light_device_ext_t *dev = (struct light_device_ext_t *)base_dev;
int rc = 0;
if (dev == NULL)
{
ALOGE("%s: Cannot deallocate a NULL light device", __func__);
return EINVAL;
}
//
接下来是判断引用.
if (dev->refs == 0)
/* the light device is not open */
{
rc = EINVAL;
goto mutex_unlock;
}
else if (dev->refs > 1)
{
goto dec_refs;
}
如果refs引用次数为0表示设备根本没打开。这样可以直接返回。 否则如果被引用次数大于1,那么只需要减少一次引用次数,然后直接返回。 否则,也就是如果只被一个程序打开,那就就需要关闭设备了。
//
接下来就关闭设备,如果是闪烁模式,那么则销毁闪烁线程,将flashMode设置为未闪烁模式。
if (dev->state.flashMode)
{
/* destroy flashing thread */
pthread_mutex_lock(&dev->flash_signal_mutex);
dev->state.flashMode = LIGHT_FLASH_NONE;
pthread_cond_signal(&dev->flash_cond);
pthread_mutex_unlock(&dev->flash_signal_mutex);
pthread_join(dev->flash_thread, NULL);
}
free_light_sync_resources(&dev->flash_cond,&dev->flash_signal_mutex);
然后将相关的设置更新,接着释放背光灯同步源。实质上就是销毁线程。
static void free_light_sync_resources(pthread_cond_t *cond,pthread_mutex_t *signal_mutex)
{
pthread_mutex_destroy(signal_mutex);
pthread_cond_destroy(cond);
}
//
然后将引用次数减1,再取消线程互斥锁,然后返回成功标志。
3.set_light_generic函数
函数目的:设置背光灯状态
//
static int set_light_generic(struct light_device_t *base_dev,struct light_state_t const *state)
{
struct light_device_ext_t *dev = (struct light_device_ext_t *)base_dev;
struct light_state_t *current_state;
int rc = 0;
if (dev == NULL)
{
ALOGE("%s: Cannot set state for NULL device", __func__);
return EINVAL;
}
current_state = &dev->state;
pthread_mutex_lock(&dev->write_mutex);
if (dev->refs == 0)
{
ALOGE("%s: The light device is not opened", __func__);
pthread_mutex_unlock(&dev->write_mutex);
return EINVAL;
}
首先还是检查设备信息,如果传入参数是无效参数,或者设备没有打开,那么则进行相关的错误处理。 //
接下来直接打印设备的信息,包括闪烁模式,颜色
ALOGV("%s: flashMode:%x, color:%x", __func__, state->flashMode, state->color);
//
接下来如果现在的状态是闪烁模式,那么销毁闪烁线程,更新状态。
if (current_state->flashMode)
{
/* destroy flashing thread */
pthread_mutex_lock(&dev->flash_signal_mutex);
current_state->flashMode = LIGHT_FLASH_NONE;
pthread_cond_signal(&dev->flash_cond);
pthread_mutex_unlock(&dev->flash_signal_mutex);
pthread_join(dev->flash_thread, NULL);
}
//
接着对灯光进行设置。
*current_state = *state;
if (dev->transform != NULL)
{
current_state->color = dev->transform(current_state->color);
}
if (current_state->flashMode)
{
/* start flashing thread */
if (check_flash_state(current_state) == 0)
{
rc = pthread_create(&dev->flash_thread, NULL,flash_routine, (void *)dev);
if (rc != 0)
{
ALOGE("%s: Cannot create flashing thread", __func__);
current_state->flashMode = LIGHT_FLASH_NONE;
}
} else
{
ALOGE("%s: Flash state is invalid", __func__);
current_state->flashMode = LIGHT_FLASH_NONE;
}
}
else
{
rc = set_gpio_value(dev->pin, current_state->color);
if (rc != 0)
{
ALOGE("%s: Cannot set light color.", __func__);
}
}
如果需要设置的是闪烁状态,那么先创建一个闪烁的线程。否则如果不需要闪烁,那么直接就设置颜色就好。
//
pthread_mutex_unlock(&dev->write_mutex);
return rc;
}