一、前言
本文主要分析mtk平台hal层如何获取alps框架下光距感数据和光距感的使能开关对应的hal层接口;
二、光距感上报数据的流程
应用层获取光感数据的方式通过open “/dev/m_als_misc”
设备节点,调用read函数即可读取到alps架构下的光感数据;
参考第一章所讲的timer_als定时器触发流程,在机器开机的过程中,默认设置下hal层会操控/sys/class/sensor/m_als_misc/alsactive
节点,触发定时器,光感数据通过als_data_report->sensor_input_event函数将获取到的光感值添加到全局的缓存队列buffer中,同时唤醒sensor_event_poll函数中的client->wait等待队列;sensor_event_poll函数就会将对应应用层的休眠进程唤醒,表示这个设备有数据可读,最后调用对应的read函数来读取光感值;
//alsps.c
//light_fops
static int light_open(struct inode *inode, struct file *file)
{
nonseekable_open(inode, file); //在 open 方法中调用 nonseekable_open() 时,它会通知内核设备不支持 llseek
return 0;
}
static ssize_t light_read(struct file *file, char __user *buffer, size_t count,
loff_t *ppos)
{
ssize_t read_cnt = 0;
read_cnt = sensor_event_read(alsps_context_obj->als_mdev.minor, file,
buffer, count, ppos);
return read_cnt;
}
static unsigned int light_poll(struct file *file, poll_table *wait)
{
return sensor_event_poll(alsps_context_obj->als_mdev.minor, file, wait);
}
hal层中open ”/dev/m_als_misc“
获取fd套接字,根据fd,调用read函数来读取内核中的数据;sensor_event_read函数就是该节点对应的内核读取数据的具体实现;
//sensors-1.0\hwmon\sensor_event\sensor_event.c
ssize_t sensor_event_read(unsigned char handle, struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct sensor_event_client *client = &event_obj->client[handle];
struct sensor_event event;
size_t read = 0;
if (count != 0 && count < sizeof(struct sensor_event)) {
SE_PR_ERR("sensor_event_read handle: %d err count(%d)\n", handle, (int)count);
return -EINVAL;
}
for (;;) {
if (client->head == client->tail) {
return 0;
}
if (count == 0) {
SE_LOG("sensor_event_read count: %d\n", (int)count);
break;
}
while (read + sizeof(struct sensor_event) <= count &&
sensor_event_fetch_next(client, &event)) {
if (copy_to_user(buffer + read, &event, sizeof(struct sensor_event)))
return -EFAULT;
read += sizeof(struct sensor_event);
}
if (read)
break;
}
return read;
}
unsigned int sensor_event_poll(unsigned char handle, struct file *file, poll_table *wait)
{
struct sensor_event_client *client = &event_obj->client[handle];
unsigned int mask = 0;
poll_wait(file, &client->wait, wait);
if (client->head != client->tail) {
/* SE_PR_ERR("sensor_event_poll handle:%d\n", handle); */
mask |= POLLIN | POLLRDNORM;
}
return mask;
}
int sensor_input_event(unsigned char handle,
const struct sensor_event *event)
{
struct sensor_event_client *client = &event_obj->client[handle];
unsigned int dummy = 0;
/* spin_lock safe, this function don't support interrupt context */
spin_lock(&client->buffer_lock);
if (unlikely(client->buffull == true)) {
pr_err_ratelimited("input buffull, handle:%d, head:%d, tail:%d\n", handle, client->head, client->tail);
spin_unlock(&client->buffer_lock);
wake_up_interruptible(&client->wait);
return -1;
}
client->buffer[client->head++] = *event;
client->head &= client->bufsize - 1;
/* remain 1 count */
dummy = client->head + 1;
dummy &= client->bufsize - 1;
if (unlikely(dummy == client->tail))
client->buffull = true;
spin_unlock(&client->buffer_lock);
wake_up_interruptible(&client->wait);
return 0;
}
1、hal层获取光感驱动层的数据流程
在sensors.cpp文件中init_sensors->dev->device.poll = poll__poll;初始化阶段定义了poll函数;
static int poll__poll(struct sensors_poll_device_t * /dev/,
sensors_event_t* data, int count) {
return mSensorManager->pollEvent(data, count);
}
上一章有分析到当驱动层中的光感上报定时器timer_als被触发时,最终会导致驱动的light_poll函数中client->wait等待队列被唤醒,同时给hal层的fd文件描述符fd.revents传入POLLIN | POLLRDNORM;
int sensors_poll_context_t::pollEvent(sensors_event_t* data, int count) {
int nbEvents = 0;
int n = 0;
int averageCount = 0, loop = 0, loopcount = 0;
int backupcount = count, backuploop = 0;
do {
loopcount++;
computeCountForEachFd(count, &averageCount, &loop);
backuploop = loop;
for (int i = 0; count && loop && i < numFds; i++) {
SensorBase* const sensor(mSensors[i]);
//mPollFds[i].revents值根据内核的poll函数返回值决定的,当光距感light_poll中的队列被唤醒时,mPollFds[3].revents=POLLIN | POLLRDNORM;表示监听光感的文字描述符有相应,调用对应光感的AmbiLightSensor::readEvents方法;
if (mPollFds[i].revents & POLLIN || sensor->pendingEvent()) {
int nb = sensor->readEvents(data, averageCount);
for (int j = 0; j < nb; j++) {
if (data[j].type == SENSOR_TYPE_META_DATA)
data[j].meta_data.sensor += ID_OFFSET;
else
data[j].sensor += ID_OFFSET;
}
count -= nb;
nbEvents += nb;
data += nb;
loop--;
if (count < 0) {
}
}
}
n = TEMP_FAILURE_RETRY(poll(mPollFds, numFds, nbEvents ? 0 : -1)); //poll阻塞,当nbEvents返回值为0时唤醒,调用readEvents方法来读取驱动层的光感值;
} while (n && count);
return nbEvents;
}
//SensorEventReader.cpp
#define DEVICE_PATH "/dev/m_als_misc"
AmbiLightSensor::AmbiLightSensor()
//将/dev/m_als_misc节点路径传入
if (mSensorReader.selectSensorEventFd(DEVICE_PATH) >= 0)
}
int SensorEventCircularReader::selectSensorEventFd(const char *path) {
mReadFd = TEMP_FAILURE_RETRY(open(path, O_RDONLY));//打开path路径下的节点,成功返回mReadFd文字描述符;
}
ssize_t SensorEventCircularReader::fill() {
size_t numEventsRead = 0;
if (mFreeSpace) {
//读取mReadFd文字描述符的对应节点值;那么这个mReadFd文字描述符来自哪里呢,在selectSensorEventFd方法中获取的;mReadFd是在SensorEventCircularReader类中定义私有属性;该类中的selectSensorEventFd和fill方法都可以设置和获取该类的属性;
//mHead为内核上报数据存放的首地址
const ssize_t nread = TEMP_FAILURE_RETRY(read(mReadFd, mHead, mFreeSpace * sizeof(struct sensor_event)));
//mBuffer为上报数据的存放地址;
memcpy(mBuffer, mBufferEnd, s * sizeof(struct sensor_event));
return numEventsRead;
}
//AmbienteLight.cpp
int AmbiLightSensor::readEvents(sensors_event_t* data, int count)
{
if (count < 1)
return -EINVAL;
ssize_t n = mSensorReader.fill(); //fill方法是根据驱动层的光感设备节点的路径,获取fd;
while (count && mSensorReader.readEvent(&event)) {//event指向mCurr;
processEvent(event); //根据上报事件的event->handle来设置mPendingEvent,当是光感上报值,
if (event->flush_action <= FLUSH_ACTION) {
*data++ = mPendingEvent;
numEventReceived++;
count--;
}
mSensorReader.next(); //mCurr指向上报数据的地址mBuffer
}
return numEventReceived;
}
//SensorEventReader.cpp
ssize_t SensorEventCircularReader::fill() {
size_t numEventsRead = 0;
if (mFreeSpace) {
const ssize_t nread = TEMP_FAILURE_RETRY(read(mReadFd, mHead, mFreeSpace * sizeof(struct sensor_event)));
if (nread < 0 || nread % sizeof(struct sensor_event)) {
return 0;
}
numEventsRead = nread / sizeof(struct sensor_event);
if (numEventsRead) {
mHead += numEventsRead;
mFreeSpace -= numEventsRead;
if (mHead > mBufferEnd) {
size_t s = mHead - mBufferEnd;
if (s < ULONG_MAX / sizeof(struct sensor_event)) {
memcpy(mBuffer, mBufferEnd, s * sizeof(struct sensor_event));
mHead = mBuffer + s;
} else
ALOGE("SensorEventCircularReader fill data failed");
}
}
}
return numEventsRead;
}
//SensorEventReader.cpp
ssize_t SensorEventCircularReader::readEvent(struct sensor_event const** events) {
*events = mCurr;
}
//SensorEventReader.cpp
void SensorEventCircularReader::next() {
mCurr = mBuffer; //mCurr指向上报数据的地址;
}
2、hal层控制光感驱动,对光感逻辑处理
//AmbienteLight.cpp
AmbiLightSensor::AmbiLightSensor()
{
//当/dev/m_als_misc设备节点不存在时直接返回;
if (mSensorReader.selectSensorEventFd(DEVICE_PATH) >= 0) {
strlcpy(input_sysfs_path, "/sys/class/sensor/m_als_misc/", sizeof(input_sysfs_path));
input_sysfs_path_len = strlen(input_sysfs_path);
} else {
ALOGE("couldn't find sensor device ");
return;
}
char datapath[64]={"/sys/class/sensor/m_als_misc/alsactive"};
fd = TEMP_FAILURE_RETRY(open(datapath, O_RDWR)); //打开alsactive节点,获取fd文件描述符
TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf) - 1));//读取该节点值,buf为存放值的地址;
}
//当调用enable方法时
int AmbiLightSensor::enable(int32_t handle, int en)
{
int fd = -1;
char buf[8] = {0};
ALOGI("enable: handle:%d, en:%d \r\n", handle, en);
strlcpy(&input_sysfs_path[input_sysfs_path_len], "alsactive", sizeof(input_sysfs_path) - input_sysfs_path_len);
fd = TEMP_FAILURE_RETRY(open(input_sysfs_path, O_RDWR));
if(fd < 0) {
ALOGE("no enable control attr\r\n" );
return -1;
}
sprintf(buf, "%d,%d", handle, en);
TEMP_FAILURE_RETRY(write(fd, buf, sizeof(buf)));
close(fd);
return 0;
}
int AmbiLightSensor::batch(int handle, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs)
{
int fd = -1;
char buf[128] = {0};
ALOGI("batch: handle:%d, flag:%d,samplingPeriodNs:%" PRId64 " maxBatchReportLatencyNs:%" PRId64 "\r\n",
handle, flags,samplingPeriodNs, maxBatchReportLatencyNs);
strlcpy(&input_sysfs_path[input_sysfs_path_len], "alsbatch", sizeof(input_sysfs_path) - input_sysfs_path_len);
fd = TEMP_FAILURE_RETRY(open(input_sysfs_path, O_RDWR));
if(fd < 0) {
ALOGD("no batch control attr\r\n");
return -1;
}
sprintf(buf, "%d,%d,%" PRId64 ",%" PRId64 "", handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
TEMP_FAILURE_RETRY(write(fd, buf, sizeof(buf)));
close(fd);
return 0;
}