android内核入口函数,Android Sensor详解(4)driver的攻防战

kernel drvier架构

下面我将以psensor,light sensor为例具体说明整个sensor的driver是如何启动的

注册驱动

很多人在看driver的时候首先会去注意probe函数,仅知道这个是入口函数,其他的不在管了。

当然在我开发过程中也确实如此,因为整个框架都是固定好的,一般是不会改变的。

但身为一个rd就该知道整体的架构是什么,不能让人给问倒了。于是可以看下面的code

static const struct i2c_device_id cm36xxx_i2c_id[] = {

{CM36xxx_I2C_NAME, 0},

{}

};

#ifdef CONFIG_OF

static struct of_device_id cm36xxx_match_table[] = {

{ .compatible = "capella,cm36xxx",},

{ },

};

#else

#define cm36xxx_match_table NULL

#endif

static struct i2c_driver cm36xxx_driver = {

.id_table = cm36xxx_i2c_id,

.probe = cm36xxx_probe,

.driver = {

.name = CM36xxx_I2C_NAME,

.owner = THIS_MODULE,

.pm = &cm36xxx_pm,

.of_match_table = of_match_ptr(cm36656_match_table),

},

};

static int __init cm36xxxinit(void)

{

return i2c_add_driver(&cm36xxx_driver);

}

static void __exit cm36xxx_exit(void)

{

i2c_del_driver(&cm36xxx_driver);

}

看到整个函数包含了__init与__exit函数,其中就是添加i2c的driver与delete driver。

那么整个cm36xxx_driver又是如何构造的呢?

它包含了id_table,probe,driver,of_match_table。其中值得你关心的是of_match_table,cm36xxx_match_table这张table直接定义了系统map时的信息,因而在Android Sensor详解(3)porting drvier

讲到compatible要与kernel driver中的cm36xxx_match_table中的compatible一致就是源于此处。

probe函数的家常

众所周知probr函数是入口函数,那么它主要的功能简单,就是初始化整个driver。当然在这里仅仅介绍driver的一些基本功能,具体不会进行细化。

malloc驱动结构题,并获取i2c的client与中断。

struct cm36xxx_info *lpi;

lpi = kzalloc(sizeof(struct cm36xxx_info), GFP_KERNEL);

if (!lpi)

return -ENOMEM;

lpi->i2c_client = client;

lpi->irq = client->irq;

i2c_set_clientdata(client, lpi);

读取dtsi进行相关初始化

static int cm36xxx_parse_dt(struct device *dev,

struct cm36xxx_info *lpi)

{

struct device_node *np = dev->of_node;

u32 temp_val;

int rc;

rc = of_get_named_gpio_flags(np, "capella,intrpin-gpios",

0, NULL);//设置int的gpio

if (rc < 0)

{

dev_err(dev, "Unable to read interrupt pin number\n");

return rc;

}

else

{

lpi->intr_pin = rc;

D("[LS][CM36656]%s GET INTR PIN \n", __func__);

}

rc = of_property_read_u32(np, "capella,slave_address", &temp_val);//设置driver的i2c地址

if (rc)

{

dev_err(dev, "Unable to read slave_address\n");

return rc;

}

else

{

lpi->slave_addr = (uint8_t)temp_val;

}

D("[PS][CM36xxx]%s PARSE OK \n", __func__);

return 0;

}

if( cm36xxx_parse_dt(&client->dev, lpi) < 0 )

{

ret = -EBUSY;

goto err_platform_data_null;

}

初始化电

这个就要自己写regulator了,当然在这里不介绍了,后续会对regulator做一些解释(届时会在这里做一个链接)

上各种锁

要知道你在操作底层的driver时,特别ic可能就需要时序,突然有人打断,那么整个driver就是一场灾难性的bug

各种初始化操作

这部分请自行参照ic的spec进行动作,特别注意一些setup函数的先后顺序

创建input树与misc树

static int psensor_setup(struct cm36xxx_info *lpi)

{

int ret;

lpi->ps_input_dev = input_allocate_device();

if (!lpi->ps_input_dev) {

pr_err(

"[PS][CM36xxx error]%s: could not allocate ps input device\n",

__func__);

return -ENOMEM;

}

lpi->ps_input_dev->name = "cm36xxx-ps";

set_bit(EV_ABS, lpi->ps_input_dev->evbit);

input_set_abs_params(lpi->ps_input_dev, ABS_DISTANCE, 0, 1, 0, 0);

ret = input_register_device(lpi->ps_input_dev);

if (ret < 0) {

pr_err(

"[PS][CM36xxx error]%s: could not register ps input device\n",

__func__);

goto err_free_ps_input_device;

}

ret = misc_register(&psensor_misc);

if (ret < 0) {

pr_err(

"[PS][CM36xxx error]%s: could not register ps misc device\n",

__func__);

goto err_unregister_ps_input_device;

}

return ret;

err_unregister_ps_input_device:

input_unregister_device(lpi->ps_input_dev);

return ret;

err_free_ps_input_device:

input_free_device(lpi->ps_input_dev);

return ret;

}

整个系统是如何获取sensor的数据的?明确的说其实在我们的眼中有2种模式,一个是通过input子系统,向上层发送event,另外一种是上层向driver写io,driver再将data回复。

input_register_device函数将帮助driver注册倒input子系统中去。此时你可以到input相关节点去找到节点了。最为重要的是,你真的建好了这个节点吗?

adb shell getevent

直接就能知道你的driver注册上没,当底层adc值发生变化时,是否有数值在event上。

misc_register函数将帮忙driver建立起一整套misc文件树,只要包含open enable disable relase ioctol,当然这个会在后续的博客中说明。

static const struct file_operations psensor_fops = {

.owner = THIS_MODULE,

.open = psensor_open,

.release = psensor_release,

.unlocked_ioctl = psensor_ioctl

};

创建class文件树

ret = cm36xxx_setup(lpi);

if (ret < 0) {

pr_err("[PS_ERR][CM36xxx error]%s: cm36xxx_setup error!\n", __func__);

goto err_cm36xxx_setup;

}

lpi->cm36xxx_class = class_create(THIS_MODULE, "capella_sensors");

if (IS_ERR(lpi->cm36xxx_class)) {

ret = PTR_ERR(lpi->cm36xxx_class);

lpi->cm36xxx_class = NULL;

goto err_create_class;

}

lpi->ls_dev = device_create(lpi->cm36xxx_class,

NULL, 0, "%s", "lightsensor");

if (unlikely(IS_ERR(lpi->ls_dev))) {

ret = PTR_ERR(lpi->ls_dev);

lpi->ls_dev = NULL;

goto err_create_ls_device;

}

lpi->ps_dev = device_create(lpi->cm36xxx_class,

NULL, 0, "%s", "proximity");

if (unlikely(IS_ERR(lpi->ps_dev))) {

ret = PTR_ERR(lpi->ps_dev);

lpi->ps_dev = NULL;

goto err_create_ps_device;

}

当然,在完成了setup之后,需要在建立sysclass树,这将方便我们进行debug。

class_create(THIS_MODULE, “capella_sensors”)函数将建立在sys/class/capella_sensor

而device_create

将在上述目录下分别建立起自己的节点。这些函数的用法可以在百度上都找的到

启动workqueue处理事件

lpi->lp_wq = create_singlethread_workqueue("cm36656_wq");

if (!lpi->lp_wq) {

pr_err("[PS][CM36656 error]%s: can't create workqueue\n", __func__);

ret = -ENOMEM;

goto err_create_singlethread_workqueue;

}

强制出错处理

这个是你在写driver最需要关注的一点。当你写driver的时候一定要确保哪一步出了错,在出错处理时绝对不会影响到系统。不会使系统hang up。

驱动完善

此时你该做的是将所有的需求进行整理,然后进行各式各样的修改,当请注意,sensor上报数据只有16个data。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值