HAL
分析hardware/akm/AK8975_FS
大致有4类文件,有着不同的分工
1:hardware\akm\ak8975_fs\libsensors\Sensors.cpp
hal中一般支持多类设备,起框架作用,主要关注poll方法
2:AkmSensor.cpp
具体sensor的驱动代码
3:SensorBase.cpp
sensor的共有方法,比如open /dev/input/eventx...
4:InputEventReader.cpp
读取数据等方法
- hardware\akm\ak8975_fs\libsensors\Sensors.cpp
起总领作用
static int open_sensors(const struct hw_module_t* module, const char* id,
struct hw_device_t** device)
{
sensors_poll_context_t *dev = new sensors_poll_context_t();
// sensors_poll_context_t::sensors_poll_context_t
mSensors[akm] = new AkmSensor();
mPollFds[akm].fd = mSensors[akm]->getFd();
// 填充回调函数
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;
*device = &dev->device.common;
}
static struct hw_module_methods_t sensors_module_methods = {
.open = open_sensors
};
// HAL入口
struct sensors_module_t HAL_MODULE_INFO_SYM = {
.common = {
.id = SENSORS_HARDWARE_MODULE_ID,
.methods = &sensors_module_methods,
},
.get_sensors_list = sensors__get_sensors_list,
};
重点分析一下poll方法:对每个sensor使用sensor->readEvents读取数据
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); // sensors_poll_context_t::pollEvents
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); // 多态机制,读取数据
count -= nb;
nbEvents += nb;
data += nb;
}
}
} while (n && count);
}
- hardware\akm\ak8975_fs\libsensors\AkmSensor.cpp
具体sensor驱动
// 得到指定设备的fd
AkmSensor::AkmSensor()
: SensorBase(NULL, "compass"), // 对/dev/input/eventx进行ioctl(EVIOCGNAME)得到name,如果是"compass",则能使用该HAL code
{
mPendingEvents[MagneticField].version = sizeof(sensors_event_t);
mPendingEvents[MagneticField].sensor = ID_M;
mPendingEvents[MagneticField].type = SENSOR_TYPE_MAGNETIC_FIELD; // 上报的数据类型
mPendingEvents[MagneticField].magnetic.status = SENSOR_STATUS_ACCURACY_HIGH;
}
再看数据读取函数,对接上Sensors.cpp
int AkmSensor::readEvents(sensors_event_t* data, int count)
// 读取数据
ssize_t n = mInputReader.fill(data_fd); //
// 处理数据
while (count && mInputReader.readEvent(&event)) {
int type = event->type;
if (type == EV_ABS) {
processEvent(event->code, event->value); // 稍加处理
case EVENT_TYPE_MAGV_X:
mPendingMask |= 1<<MagneticField;
mPendingEvents[MagneticField].magnetic.x = value * CONVERT_M;
break;
mInputReader.next();
}
}
- hardware\akm\ak8975_fs\libsensors\SensorBase.cpp
sensor的共有部分抽象
// 遍历"/dev/input"下的所有节点,使用ioctl(EVIOCGNAME)得到name,看能否匹配上,匹配上则记录fd
SensorBase::SensorBase(
const char* dev_name,
const char* data_name)
: dev_name(dev_name), data_name(data_name),
dev_fd(-1), data_fd(-1)
data_fd = openInput(data_name);
const char *dirname = "/dev/input";
dir = opendir(dirname);
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while((de = readdir(dir))) {
strcpy(filename, de->d_name);
fd = open(devname, O_RDONLY);
if (fd>=0) {
char name[80];
if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
name[0] = '\0';
}
if (!strcmp(name, inputName)) {
strcpy(input_name, filename);
break;
}
}
}
closedir(dir);
return fd;
- hardware\akm\ak8975_fs\libsensors\InputEventReader.cpp
维护sensor数据
// 读取"/dev/input/eventx"数据
ssize_t InputEventCircularReader::fill(int fd)
{
// read name为compass的"/dev/input/eventx"
const ssize_t nread = read(fd, mHead, mFreeSpace * sizeof(input_event));
numEventsRead = nread / sizeof(input_event);
if (numEventsRead) {
mHead += numEventsRead;
mFreeSpace -= numEventsRead;
if (mHead > mBufferEnd) {
size_t s = mHead - mBufferEnd;
memcpy(mBuffer, mBufferEnd, s * sizeof(input_event));
mHead = mBuffer + s;
}
}
return numEventsRead;
}
// 更新数据指针位置
ssize_t InputEventCircularReader::readEvent(input_event const** events)
{
*events = mCurr;
}
void InputEventCircularReader::next()
{
mCurr++;
}