首页 > 其他分享 >【Android驱动07】Sensor传感器框架以及驱动移植和调试方法(Hal层部分)

【Android驱动07】Sensor传感器框架以及驱动移植和调试方法(Hal层部分)

时间:2024-08-03 14:53:09浏览次数:14  
标签:Hal 07 int dev module device 驱动 sensors poll

一,Android sensor 系统架构

Hal 就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间,而Linux内核驱动程序运行在内核空间。
在这里插入图片描述
二,HAL 层Sensor 框架实现
Sensor HAL层相对来说比较简单,它的意图就是为framework层提供接口API的实现,如open_sensors,poll等,一旦实现完毕,framewoerk 里面的SensorManager,SensorService 里面的native(本地)方法可以直接被调用。
在这里插入图片描述

2.1 HAL 客制化
在alps\device\mediatek$(proj)\ProjectConfig.mk中 配置对应的传感器为y
等效路径(kernel3.18\arch\arm64\configs$(proj).deconfig)

CONFIG_MTK_SENSOR_SUPPORT=y
CONFIG_CUSTOM_KERNEL_ACCELEROMETER=y
CONFIG_MTK_ICM20645G=y
CONFIG_CUSTOM_KERNEL_ALSPS=y
CONFIG_MTK_CM36558=y
CONFIG_CUSTOM_KERNEL_GYROSCOPE=y
CONFIG_MTK_ICM20645GY=y

2.2 获取module函数
Hal层的库文件是怎么被上层调用的?上层调用时的入口(相当于main)又是什么呢?它就是HAL_MODULE_INFO_SYM。
路径:vendor/mediatek/proprietary/hardware/sensor/sensors.c

static int open_sensors(const struct hw_module_t* module, const char* name,
        struct hw_device_t** device)
{
   ALOGD("%s: name: %s! fwq debug\r\n", __func__, name);
 
 
   return init_nusensors(module, device);
}

static struct hw_module_methods_t sensors_module_methods = {
    .open = open_sensors
};

struct sensors_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .version_major = 1,
        .version_minor = 0,
        .id = SENSORS_HARDWARE_MODULE_ID,
        .name = "MTK SENSORS Module",
        .author = "Mediatek",
        .methods = &sensors_module_methods,
    },
    .get_sensors_list = sensors__get_sensors_list,
};

路径:vendor/mediatek/proprietary/hardware/sensor/nusensors.cpp

int init_nusensors(hw_module_t const* module, hw_device_t** device)
{
    int status = -EINVAL;
 
 
    dev = new sensors_poll_context_t();
    memset(&dev->device, 0, sizeof(sensors_poll_device_1));
 
 
    dev->device.common.tag = HARDWARE_DEVICE_TAG;
#if defined(SENSOR_BATCH_SUPPORT) || defined(CUSTOM_KERNEL_SENSORHUB)
    dev->device.common.version  = SENSORS_DEVICE_API_VERSION_1_1;
#else
    dev->device.common.version  = SENSORS_DEVICE_API_VERSION_1_0;
#endif
    dev->device.common.module   = const_cast<hw_module_t*>(module);
    dev->device.common.close    = poll__close;
    dev->device.activate        = poll__activate;
    dev->device.setDelay        = poll__setDelay;
    dev->device.poll            = poll__poll;
    dev->device.batch           = poll__batch;
    dev->device.flush            = poll__flush;
 
 
    *device = &dev->device.common;
    status = 0;
    return status;
}

2.3 创建 sensors_poll_context_t 对象

sensors_poll_context_t::sensors_poll_context_t()
{
    memset(&device, 0, sizeof(device));
    mSensors[accel] = new AccelerationSensor();
    mPollFds[accel].fd = ((AccelerationSensor*)mSensors[accel])->mdata_fd;
    mPollFds[accel].events = POLLIN;
    mPollFds[accel].revents = 0;
 
 
    mSensors[proximity] = new ProximitySensor();
    mPollFds[proximity].fd = ((ProximitySensor*)mSensors[proximity])->mdata_fd;
    mPollFds[proximity].events = POLLIN;
    mPollFds[proximity].revents = 0;
 
    int wakeFds[2];
    int result = pipe(wakeFds);
    if (result < 0) {
        ALOGE_IF(result < 0, "error creating wake pipe (%s)", strerror(errno));
    mWritePipeFd = -1;
    } else {
        result = fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);
        ALOGE_IF(result < 0, "fcntl(wakeFds[0] fail (%s)", strerror(errno));
        result = fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);
        ALOGE_IF(result < 0, "fcntl(wakeFds[1] fail (%s)", strerror(errno));
        mWritePipeFd = wakeFds[1];
    }
 
 
    mPollFds[wake].fd = wakeFds[0];
    mPollFds[wake].events = POLLIN;
    mPollFds[wake].revents = 0;
}

2.4 创建Sensor对象
路径:vendor/mediatek/proprietary/hardware/sensor/Proximity.cpp

ProximitySensor::ProximitySensor()
    : SensorBase(NULL, "m_alsps_input"),//PRO_INPUTDEV_NAME
      mEnabled(0),
      mInputReader(32)
{
 
 
    char datapath[64]={"/sys/class/misc/m_alsps_misc/psactive"};
    int fd = -1;
    char buf[64]={0};
    int len;
 
 
    mdata_fd = FindDataFd();
    if (mdata_fd >= 0) {
        strcpy(input_sysfs_path, "/sys/class/misc/m_alsps_misc/");
        input_sysfs_path_len = strlen(input_sysfs_path);
    }
    else
    {
        ALOGE("couldn't find input device ");
        return;
    }
    ALOGD("prox misc path =%s", input_sysfs_path);
 
 
    fd = open(datapath, O_RDWR);
    if (fd >= 0)
    {
        len = read(fd,buf,sizeof(buf)-1);
        if (len <= 0)
        {
            ALOGD("read div err, len = %d", len);
        }
        else
        {
            buf[len] = '\0';
            sscanf(buf, "%d", &mDataDiv);
            ALOGD("read div buf(%s), mdiv %d", datapath,mDataDiv);
        }
        close(fd);
    }
    else
    {
    ALOGE("open acc misc path %s fail ", datapath);
    }
}

2.5 通用sensor 的使能函数

static int poll__activate(struct sensors_poll_device_t *dev,
        int handle, int enabled) {
    sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
    return ctx->activate(handle-ID_OFFSET, enabled);
}
int sensors_poll_context_t::activate(int handle, int enabled)
{
    ....
    int index = handleToDriver(handle);
    .....
    if(NULL != mSensors[index])
    {
       ALOGD( "use new sensor index=%d, mSensors[index](%x)", index, mSensors[index]);
       if(this->device.common.version  >= SENSORS_DEVICE_API_VERSION_1_1)
       {
               ALOGD("support batch active \n" );
               mSensors[batchsensor]->enable(handle, enabled);
       }
       err =  mSensors[index]->enable(handle, enabled);
    }
 
 
     return err;
}

2.6 封装poll 函数
poll 函数对应framework中poll操作,这里只需了解它的功能实现,调用逻辑需要查看framework层代码
poll 是一个非常重要的接口,它的实现基于linux 内核中IO多路复用策略(一种效率非常高的机制)

static int poll__poll(struct sensors_poll_device_t *dev,
        sensors_event_t* data, int count) {
    sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
    return ctx->pollEvents(data, count);
}

轮询事件方法,这是一个构造方法,该对象创建,会启动轮询机制,监听sensorlist[]中文件描述符,等待事件上报 (使用IO多路复用策略)

int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
{
    .....
    do {
 
 
    for (int i=0 ; count && i<numSensorDrivers ; i++) {
            SensorBase* const sensor(mSensors[i]);
            if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) {
                int nb = sensor->readEvents(data, count);
    .....  
        }    
        if (count) {
            // we still have some room, so try to see if we can get
            // some events immediately or just wait if we don't have
            // anything to return
 
 
            n = poll(mPollFds, numFds, nbEvents ? 0 : -1);
            if (n<0) {
                int err;
        err = errno;
                ALOGE("poll() failed (%s)", strerror(errno));
                return -err;
            }
            if (mPollFds[wake].revents & POLLIN) {
                char msg;
                int result = read(mPollFds[wake].fd, &msg, 1);
                ALOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));
                ALOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg));
                mPollFds[wake].revents = 0;
            }
        }
        // if we have events and space, go read them
    } while (n && count);
 
 
    return nbEvents;
}

2.7 读取事件函数

int ProximitySensor::readEvents(sensors_event_t* data, int count)
{
    ....
 
 
    ssize_t n = mInputReader.fill(mdata_fd);
    if (n < 0)
        return n;
    int numEventReceived = 0;
    input_event const* event;
 
 
    while (count && mInputReader.readEvent(&event)) {
        int type = event->type;
        //ALOGE("fwq1....\r\n");
       if (type == EV_REL)
        {
            processEvent(event->code, event->value);
            //ALOGE("fwq2....\r\n");
        }
         .....
          mInputReader.next();
    }
    //ALOGE("fwq read Event 2\r\n");
    return numEventReceived;
}
void ProximitySensor::processEvent(int code, int value)
{
    ALOGD("processEvent code=%d,value=%d\r\n",code, value);
    switch (code) {
    case EVENT_TYPE_PS_VALUE:
        mPendingEvent.distance= value-1;
        break;
    }
}

2.8 获得sensor 列表函数
路径:vendor/mediatek/proprietary/hardware/sensor/sensors.c
这一步非常重要,HAL_MODULE_INFO_SYM 映射了hal 层XXX.so 库的入口,上层hw_get_module 将获得该入口,使得上层可以和底层.so库进行交互

static int sensors__get_sensors_list(struct sensors_module_t* module,
        struct sensor_t const** list)
{
    ALOGD(" sSensorList addr =%p, module addr =%p\r\n",sSensorList,module);
    ALOGD(" ARRAY_SIZE(sSensorList) =%d SENSORS_NUM=%d MAX_NUM_SENSOR=%d \r\n",ARRAY_SIZE(sSensorList), SENSORS_NUM, MAX_NUM_SENSOR);
    *list = sSensorList;
    return ARRAY_SIZE(sSensorList);
}
struct sensor_t sSensorList[] =
{
#ifdef CUSTOM_KERNEL_ACCELEROMETER
    {
        .name       = ACCELEROMETER,
        .vendor     = ACCELEROMETER_VENDER,
        .version    = 3,
        .handle     = ID_ACCELEROMETER+ID_OFFSET,
        .type       = SENSOR_TYPE_ACCELEROMETER,
        .maxRange   = ACCELEROMETER_RANGE,//32.0f,
        .resolution = ACCELEROMETER_RESOLUTION,//4.0f/1024.0f,
        .power      = ACCELEROMETER_POWER,//130.0f/1000.0f,
        .minDelay   = 10000,
        .maxDelay   = 1000000,
        .reserved   = {}
    },
#endif
 
 
#if defined(CUSTOM_KERNEL_ALSPS) || defined(CUSTOM_KERNEL_ALS) 
    {
        .name       = LIGHT,
        .vendor     = LIGHT_VENDER,
        .version    = 1,
        .handle     = ID_LIGHT+ID_OFFSET,
        .type       = SENSOR_TYPE_LIGHT,
        .maxRange   = LIGHT_RANGE,//10240.0f,
        .resolution = LIGHT_RESOLUTION,//1.0f,
        .power      = LIGHT_POWER,//0.13f,
        .reserved   = {}
    },
#endif
};

三,Selinux权限问题
在这里插入图片描述
四,HAL 层log分析

psensor 手机中常见的使用就是拨号时贴脸灭屏,拨号后遮挡psensor,使用Adb抓取android log ,过滤的的psensor log部分如下:
在这里插入图片描述驱动部分后续再介绍

标签:Hal,07,int,dev,module,device,驱动,sensors,poll
From: https://blog.csdn.net/jiangchaobing_2017/article/details/140889909

相关文章

  • springboot演唱会门票管理系统-计算机毕业设计源码15070
    基于微信小程序的演唱会门票管理系统摘 要本文介绍的是基于Spring Boot开发的演唱会门票管理系统。该系统旨在为用户提供一个便捷、高效的平台,以实现演唱会门票的购买和退票功能。随着社交媒体和互联网的普及,传统的演唱会门票购买方式存在过程繁琐、数据统计困难等问题。......
  • 开发调试驱动helloworld
    开发调试驱动helloworldhttps://learn.microsoft.com/zh-cn/windows-hardware/drivers配置开发环境https://learn.microsoft.com/zh-cn/windows-hardware/drivers/download-the-wdk按照步骤依次安装VisualStudioCommunity、SDK、WDK这里的windbg界面更现代一点https://lea......
  • 0729~0802
    Map键值对map<k,v>Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值map常用方法map.put()//添加键和值//put插入键值对//map中值可以重复但是键不可以重复如果重复后面会覆盖前面的map.putAll()//添加整个键值对map.get()//查询boole......
  • 嵌入式Linux中的LED驱动控制(使用Pinctrl和GPIO子系统)
    在前面驱动LED的所有案例中,都是在驱动程序中去设置每个引脚的复用功能,这会导致所编写的驱动程序移植困难,可重用性差,缺乏对引脚的统一管理,容易出现引脚的重复定义等等弊病。为此,Linux内核引入了pinctrl子系统和GPIO子系统的概念。pinctrl子系统主要用于芯片引脚功能的管理,它基本上......
  • 02 Go语言操作MySQL基础教程_20240729 课程笔记
    概述如果您没有Golang的基础,应该学习如下前置课程。Golang零基础入门Golang面向对象编程GoWeb基础Go语言开发RESTAPI接口_20240728基础不好的同学每节课的代码最好配合视频进行阅读和学习,如果基础比较扎实,则阅读本教程巩固一下相关知识点即可,遇到不会的知识点再看视频......
  • Datawhale AI夏令营(AI+生命科学)深度学习-Task3直播笔记
    机器学习lgm上分思路    1、引入新特征(1)对于Task2特征的再刻画        GC含量是siRNA效率中的一个重要且基本的参数,可以作为模型预测的特征。这是因为低GC含量会导致非特异性和较弱的结合,而高GC含量可能会阻碍siRNA双链在解旋酶和RISC复合体作用下的解旋。......
  • 盖世计划--0731--AB班模拟
    今天的题不算难,但是没做出一题,有点失败。A你打完表之后发现并没有什么出色的性质。只能考虑爆搜。代码好写,但是你要分析复杂度。最关键的一点是每一次递归至少多一个\(1\),而\(1\)可以直接return,所以最多递归\(m\)次就够了。#include<bits/stdc++.h>#definepiistd:......
  • 使用帮助文档day07
    案例/*如何使用帮助文档?Scanner1、双击打开帮助文档2、点击索引3、搜索要学习的类Scanner4、看属于哪一个包下的如果这个类是在java.lang包下的话,将来在程序中使用的时候,是不需要导包的。其余包下的类,将来......
  • static关键字day07
    static关键字的使用及其注意事项:1、随着类的加载而加载到静态区,优先对象而存在的,静态成员变量会被系统赋予默认值2、被static修饰的成员,又称之为类成员(被静态修饰的成员变量或者成员方法),可以直接通过类名的方式进行访问3、非静态的成员方法中既可......
  • 代码块day07
    /*代码块:由大括号起来的一段代码,叫做代码块。根据定义的位置不同,修饰符不同,在java中累计有4种代码块。局部代码块:在方法的内部,仅使用大括号起来的代码,叫做局部代码块。构造代码块:写法和局部代码块的写法一样,只是写的位置在类中方法外。每创建一次对象,都会......