4. /dev/akm8975_dev设备节点
驱动中注册了一个杂项设备akm8975_dev,主要实现了ioctl的功能供第三方的库文件操作,主要包含以下操作:
#define ECS_IOCTL_READ _IOWR(AKMIO, 0x01, char*)
#define ECS_IOCTL_WRITE _IOW(AKMIO, 0x02, char*)
#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x03, short)
#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x04, char[SENSOR_DATA_SIZE])
#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x05,int[YPR_DATA_SIZE])
#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x06, int)
#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x07, int)
#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x08, long longint[AKM_NUM_SENSORS])
#define ECS_IOCTL_GET_LAYOUT _IOR(AKMIO, 0x09, char)
#define ECS_IOCTL_GET_ACCEL _IOR(AKMIO, 0x30, short[3])
² ECS_IOCTL_READ:通过I2C读取AKM8975寄存器中的数据
² ECS_IOCTL_WRITE:通过I2C向AKM8975寄存器写入数据
² ECS_IOCTL_SET_MODE:设置AKM8975的工作模式
² ECS_IOCTL_GETDATA:读取地磁数据
² ECS_IOCTL_SET_YPR:将第三方库计算的结果保存到驱动中,并产生input事件,在这里是通过调用AKECS_SetYPR( ),判断akm->enable_flag来确定是否上报
² ECS_IOCTL_GET_OPEN_STATUS:查看akm8975的打开状态
² ECS_IOCTL_GET_CLOSE_STATUS:查看akm8975的关闭状态
² ECS_IOCTL_GET_DELAY:获得驱动设置的延时事件
² ECS_IOCTL_GET_LAYOUT:获得芯片的贴片位置
² ECS_IOCTL_GET_ACCEL:获得G-sensor的数据
[url=]3. HAL[/url]部分地磁的HAL部分的代码在\qics1003\hardware\libhardware\modules\libsensors\AkmSensor.cpp中, 其提供了函数接口供qics1003\hardware\libhardware\modules\libsensors\
sensors.cpp调用,在sensors.cpp中调用open_sensors( ):
static int open_sensors(const struct hw_module_t*module, const char* id,struct hw_device_t** device)
{
intstatus = -EINVAL;
sensors_poll_context_t *dev = new sensors_poll_context_t();
memset(&dev->device, 0, sizeof(sensors_poll_device_t));
******
*device= &dev->device.common;
status =0;
returnstatus;
}
其中通过new sensors_poll_context_t( )创建了一个sensors_poll_context_t实例,首先执行构造函数sensors_poll_context_t( ):
sensors_poll_context_t::sensors_poll_context_t()
{
mSensors[acc]= new AcclerSensor();
mPollFds[acc].fd= mSensors[acc]->getFd();
mPollFds[acc].events= POLLIN;
mPollFds[acc].revents= 0;
mSensors[akm] = new AkmSensor();
mPollFds[akm].fd= mSensors[akm]->getFd();
mPollFds[akm].events = POLLIN;
mPollFds[akm].revents= 0;
******
mWritePipeFd= wakeFds[1];
mPollFds[wake].fd = wakeFds[0];
mPollFds[wake].events = POLLIN;
mPollFds[wake].revents = 0;
}
在函数中又通过调用mSensors[akm] = new AkmSensor( )创建了一个AkmSensor实例,class AkmSensor则实现在上文提到的AkmSensor.cpp中。首先运行构造函数AkmSensor( ):
AkmSensor::AkmSensor()
: SensorBase(NULL,"compass"),
mPendingMask(0),
mInputReader(32)
{
for (inti=0; i<numSensors; i++) {
mEnabled= 0;
mDelay= 0;
}
****
if (data_fd){
strcpy(input_sysfs_path,"/sys/class/compass/akm8975/");
input_sysfs_path_len =strlen(input_sysfs_path);
} else {
input_sysfs_path[0]= '\0';
input_sysfs_path_len= 0;
}
}
在SensorBase( )中,通过调用data_fd = openInput(data_name)将找到compass在input中对应的节点位置,并返回文件的句柄保存到data_fd中,在AkmSensor.cpp中就可以用data_fd句柄读取input系统中的数据。后面将/sys/class/compass/akm8975/路径保存到input_sysfs_path中,这个路径主要是用来在setEnable( )、setDelay( )时对enable和delay的节点进行设置。
同时在这个路径下还有一个节点“accel“,这个节点就是完成将G-sensor的数据写回到akm8975的驱动中,其代码如下:
int AkmSensor::setAccel(sensors_event_t* data)
{
int err;
int16_tacc[3];
acc[0] =(int16_t)(data->acceleration.x / GRAVITY_EARTH * AKSC_LSG);
acc[1] =(int16_t)(data->acceleration.y / GRAVITY_EARTH * AKSC_LSG);
acc[2] =(int16_t)(data->acceleration.z / GRAVITY_EARTH * AKSC_LSG);
strcpy(&input_sysfs_path[input_sysfs_path_len],"accel");
err =write_sys_attribute(input_sysfs_path, (char*)acc, 6);
if (err< 0) {
LOGD("AkmSensor:%s write failed.",
&input_sysfs_path[input_sysfs_path_len]);
}
returnerr;
}
这个写G-sensor的数据到akm8975的驱动中的函数在sensors.cpp的activate( ),pollEvents()中:
if (mSensors[akm]->getEnable(ID_M) ||mSensors[akm]->getEnable(ID_O)) {
if(!mag_enable_gsensor){
if(mSensors[acc]->getEnable(ID_A)){
gsensor_enable_flag= 1;
}else{
err = mSensors[acc]->setEnable(ID_A, 1);
mag_enable_gsensor= 1;
}
}
}
如果打开了地磁触感器就会判断mSensors[acc]->getEnable(ID_A)标志G-sensor是否打开,如果没有打开这会mSensors[acc]->setEnable(ID_A, 1)调用打开G-sensor。并且在pollEvents( )中通过(mSensors[akm]))->setAccel(&data[nb-1])将G-sensor的数据写入到akm8975的驱动中。
读取input子系统中的数据主要是通过函数readEvents( )调用processEvent( )完成读取input中的数据。
[url=]4. 第三方库文件[/url]第三方库文件路径在qics1003\external\akmd8975文件夹下,首先进入man.c的main()函数大致流程如下:
l AKD_InitDevice() 打开"/dev/akm8975_dev"设备节点
l ReadAK8975FUSEROM() 读取AKM8975的ID
l MeasureSNGLoop() 进入地磁测量代码
在MeasureSNGLoop()中完成了读取在驱动中设置的delay、读取地磁sensor中的数据、计算地磁方位等操作,代码大致流程如下:
l GetInterval() 读取驱动中设置的delay
l AKD_SetMode() 通过IOCTL中的cmd:ECS_IOCTL_SET_MODE设置AKM8975到采样模式
l AKD_GetMagneticData() 通过IOCTL中的cmd:ECS_IOCTL_GETDATA获取采样数据
l AKD_GetAccelerationData() 在AOT_GetAccelerationData函数中通过IOCTL中的cmd:ECS_IOCTL_GET_ACCEL获得G-sensor数据
l CalcDirection() 计算方向,在这里调用了libAK8975.a中的库函数计算地磁方向
l Disp_MeasurementResultHook() 在AKD_SetYPR( )中通过过IOCTL中的cmd:ECS_IOCTL_SET_YPR设置计算结果到驱动中,并触发input上报数据。