笔记六:linux3.0以后自己实现i2c驱动probe探测函数不执行原因
先不上直接结果,随我娓娓道来。。一、回顾:在笔记五:linux下i2c子系统学习中,是基于linux2.6.内核。在linux3.0一下,i2c的设备表示是使用的板级程序实现,及i2c设备使用i2c_client表示,将设备信息用struct i2c_board_info加载,用i2c_new_device函数将设备加载到i2c总线。exp:device.cstat...
先不上直接结果,随我娓娓道来。。
一、回顾:
在笔记五:linux下i2c子系统学习中,是基于linux2.6.内核。在linux3.0一下,i2c的设备表示是使用的板级程序实现,及i2c设备使用i2c_client表示,将设备信息用struct i2c_board_info加载,用i2c_new_device函数将设备加载到i2c总线。
exp:device.c
static struct i2c_board_info xxx_info = {
I2C_BOARD_INFO("xxx", 0x48), //xxx为匹配名字!!!
};
driver.c
const struct i2c_device_id xxx_id[] = {
{ "xxx", 0 }, //i2c_device_id结构体中的xxx才是匹配的名字!!!
{ }
};
static struct i2c_driver it6801_drv = {
.driver = {
.name = "xxx",
.owner = THIS_MODULE,
},
.probe = xxx_drv_probe,
.remove = xxx_drv_remove,
.id_table = xxx_id,
};
二、新的内核(linux3.0以后的内核),引入DTS设备树。设备的表述全部用DTS设备树表示。
引出我实现的i2c驱动而且probe函数不执行的原因-->问题代码:
exp:dts
&i2cN { //N代表是第N路i2c总线
status = "okay";
xxx@48 {
status = "okay";
compatible = "xxx"; //compatible变量为匹配的名字
reg = <0x48>;
};
}
driver:
static const struct of_device_id of_xxx_match[] = {
{ .compatible = "xxx" }, //可以看出,这个为匹配dts中的设备
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_xxx_match);
static struct i2c_driver xxx_drv = {
.driver = {
.name = "xxx",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_xxx_match),
},
.probe = xxx_drv_probe,
.remove = xxx_drv_remove,
};
飞速写完代码,发现我的xxx_drv_probe函数并没有执行,我写的另外两个i2c驱动,也是挂载到一路总线,而且另外两个驱动跑的尚好,emmm...为啥这个就不行呢?分析原因:首先怀疑dts没有写对,compatible 变量名字不一致;其次,查看/sys/bus/i2c/devices/下,设备存在,查看/sys/bus/i2c/drivers/下,我的xxx_i2c_driver也存在!这就奇怪了;然后我用arm-linux-nm 命令查看我的驱动,显示xxx_drv_probe也编译进去了。。。。还是无果,最后这个驱动和好使的两个驱动比较,发现少了一个struct i2c_driver中的id_table没有实现。
driver:
static const struct of_device_id of_xxx_match[] = {
{ .compatible = "xxx" }, //可以看出,这个为匹配dts中的设备
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_xxx_match);
const struct i2c_device_id xxx_id[] = {
{ "xxx", 0 },
{ }
};
static struct i2c_driver xxx_drv = {
.driver = {
.name = "xxx",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_xxx_match),
},
.probe = xxx_drv_probe,
.remove = xxx_drv_remove,
.id_table = xxx_id, //虽然没有使用到,但是必须实现,否则probe函数不会调用!!!
};
加上struct i2c_driver中的id_table之后,果然probe函数调用成功,,,我的天!!!带着问题查看源代码,如下。
三、i2c总线匹配流程
调用流程:
i2c_add_driver
-->i2c_register_driver
-->driver->driver.bus = &i2c_bus_type;
-->driver_register
-->bus_add_driver
-->driver_attach
-->bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); // 轮询查找i2c总线上的设备
-->__driver_attach
-->driver_match_device
-->driver_probe_device
-->really_probe
-->dev->bus->probe(dev);
-->i2c_device_probe<i2c_bus_type;结构体中实现>
-->if (!driver->probe || !driver->id_table)
-->driver->probe(client, i2c_match_id(driver->id_table, client));
-->xxx_drv_probe<i2c_driver结构体中我们的驱动实现的probe>
最终在really_probe函数中:
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;
... ...//省略无关代码
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
... ...
}
在注册i2c总线时, bus->probe函数已经实现,及 i2c_device_probe函数;
在 i2c_device_probe函数中:
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
int status;
if (!client)
return 0;
... ...
driver = to_i2c_driver(dev->driver);
if (!driver->probe || !driver->id_table)//判断可知,如果driver->id_table为空,则直接return,不会再往下执行。所以id_table必须实现!!!,才会调用probe函数
return -ENODEV;
... ...
status = driver->probe(client, i2c_match_id(driver->id_table, client));
... ...
}
四、综上代码流程总结自己写的i2c驱动probe不执行的原因:
如果在自己的驱动中:i2c_driver的id_table不实现,最终会在i2c_device_probe函数中的
if (!driver->probe || !driver->id_table) return -ENODEV;
语句中直接返回,从而调不到自己实现的xxx_drv_probe函数!
所以,在新内核的dts设备树表述设备时,注册i2c_driver时,一定要将i2c_driver中的id_table实现!!!
更多推荐
所有评论(0)