电子罗盘Kernel层分析

电子罗盘的流程顺序涉及到第三方库的调用,以及g-sensor数据的获取,因此需要externel中库文件的支撑。

         目前以akm8975c数据为例子,首先modify的文件位置大致在3个文件夹中

Hal层

External层

Kernel层

 

Kernel层驱动

1、  Kernel层驱动分析

文件位置:kernel\drivers\misc\xx_compass_akm8975c.c

该函数采用模块化函数方法进行注册,通过module_init调用该模块化初始化函数akm8975_init(void)函数。

在akm8975_init(void)函数中调用系统函数i2c_add_driver将i2c_driver类型结构体akm8975_dirver添加到系统内核中。当然,退出模块时需要在akm8975_exit中调用i2c_del_driver将akm8975_driver删除。

关于akm8975_driver结构体包含以下几个函数,也就是对i2c_driver定义结构体的填充。

Static struct i2c_driver akm8975_driver = {

         .probe= akm8975_probe,

         .remove= akm8975_remove,

         .id_table= akm8975_id,

         .driver= {

                   .name= AKM8975_I2C_NAME,

},

};

 

接下来分析该结构体中分析入口函数akm8975_probe函数,该函数实现了设备启动配电后模块注册到系统内核的过程,对相关的寄存器及要使用的工作队列进行初始化。

目前疑问是akm8975_probe函数中有两个参数是如何引入系统的?

第一个参数是i2c_client,第二个参数是i2c_device_id

3.1 这里应当注意的是i2c_client参数最后赋值给该文件的全局变量,用于封装i2c读写函数(AKI2C_RxData, AKI2C_TxData).

Probe函数中首先调用i2c_check_functionality(client->adapter,I2C_FUNC_I2C)验证i2c适配器功能。然后对akm8975_data(自定义,可以按照需要继承各种数据类型,例如input等)类型局部数据分配空间,然后调用i2c_set_clientdata---à>>dev_set_driverdata,在dev_set_driverdata中实现赋值dev->drivedata= data。

以上就完成了i2c_client数据的初始化。

3.2 接着,利用平台设备实现akm8975_data数据的初始化(这里不需要初始化,初始化部分已经被删除掉)。

平台数据的实现步骤主要如下

         If(client->dev.platform_data==NULL){

                  Return ….

}

Pdata =client->dev.platform_data;(pdata为全局akm8975_platform_data自定义结构体)

This->client= client;(this->client为全局i2c_client)

         //Pdata->init;

3.3 声明input设备

Input_dev封装在akm8975_data变量当中,调用input_allocate_device对其需要分配空间,成功后调用set_bit(EV_ABS,akm->input->dev)对其声明上报数据类型

调用input_set_abs_params(akm->input_dev,ABS_RX,0,23040,0,0)设置上报事件的数据范围。

给输入设备名字赋值。Akm->input_dev->name= “compass”

调用input_register_device注册input设备。

3.4 注册混杂设备,实现用户层与内核层数据的控制。

这里注册了两个misc设备,具体作用还没有搞明白,一个通过akm_aot_ioctl,主要是获取和设置sensor状态(打开和关闭)和延时,另外一个通过akmd_ioctl实现数据与内核层和externel层的写入和读取。

阅读akm_aot_ioctl代码,ECS_IOCTL_APP_SET_MVFLAG,表示设置原始的磁场矢量标志符。调用copy_from_user将参数argp拷贝到flag中.

设置完成后,在下一个开关语句中,调用atomic_set(&mv_flag,flag)实现设置标识位为flag。

(注意:static atomic_t mv_flag)

该ioctl操作中共有3个开关语句,主要实现的是执行原子操作,实现对各种sensor状态的控制。

 

然后阅读akmd_ioctl代码,

这里首先分析ECS_IOCTL_READ,分别在以下三个开关函数中实现read功能。

首先,判断参数有效后,调用copy_from_user将参数argp拷贝到rwbuf(char数组类型)

然后,判断rwbuf区域没有越界后,调用AKI2C_RxData(&rwbuf[1],rwbuf[0])实现i2c读数据。

最后,调用copy_to_user将rwbuf拷贝到argp参数,注意rwbuf大小为rwbuf[0]+1

 ECS_IOCTL_READ,ECS_IOCTL_WRITE主要是数据的传输过程,在extenel层中获取数据的方式包括从akm8975的寄存器或者是eprom上,在AK8975Driver.c文件中调用。

另外注意的应该是ECS_IOCTL_GET_TEST, ECS_IOCTL_SET_TEST, ECS_IOCTL_GET_TEST_RESULT, ECS_IOCTL_SET_TEST_RESULT,控制命令,这些命令对应的是externel空间中的操作,主要是原厂提供的算法库。

需要注意的是新的linux内核中删去了ioctl,使用unlocked_ioctl代替原来的功能

 

Misc设备中的操作函数除了上面介绍的ioctl,还应包括akm_aot_open,akm_aot_release函数。

分析akm_aot_open时,

 

atomic_cmpxchg((v),c, c + (a)); //如果v的值等于c就加a,old=c。如果v的值不等于c,old=v的值;返回值为v的值

需要思考的是open_count,open_flag与reserve_open_flag分别代表的逻辑意义是什么,open_count和open_flag只要一个代表1就会退出唤醒工作队列open_wq

 

akm_aot_release函数中将以上需要思考的三个标示符置为0后页唤醒工作队列open_wq,因此在下一个段落中将重点分析下open_wq的意义

3.5 open_wq

从字面上理解是打开工作队列。

在该文件中实现open_wq的步骤可以总结如下:

         1声明

Static DECLEAR_WAIT_QUEUE_HEAD(open_wq)

         2初始化

Init_workqueue_head(&open_wq);

         3睡眠

调用wait_event_interruptible(open_wq,(atomic_read(&open_flag)<=0));

         4唤醒

调用wake_up(&open_wq)

注意:在probe函数中实现第二步,完成初始化,然后在读取状态时将open_wq睡眠下去,遇到原子操作时唤醒该队列。

本文件中除了该队列还定义了data_ready_wq,该队列从字面上理解应该是准备好相关的数据。实现步骤同上,其中睡眠在AKECS_GetData中调用,从而实现文件的阻塞。

Wake_up在akm8975_func_work函数中调用,应该注意的是采用轮训方式后,文件没有调用该函数,具体如何实现唤醒数据,待具体分析

仔细观察了data_ready_wq调用的是

wait_event_interruptible_timeout(data_ready_wq,atomic_read(&data_ready),1000)

该函数唤醒有两种方式,1.其他人在等待队列上调用了wake_up 2.超时到期(实际为本文采用方式)。schedule_timeout的进程始终会在超时到期时被唤醒,在本文件中可以替代该函数。

 

3.6 关于early_suspend函数

Akm->early_suspend.level

Akm->early_suspend.suspend

Akm->early_suspend.resume

调用register_early_suspend(&akm->early_suspend)

这里为什么要用到early_suspend?

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

newtonnl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值