四、注册 i2c_driver
来源:互联网 发布:正则表达式邮箱匹配php 编辑:程序博客网 时间:2024/04/29 16:21
前三步跟平台相关,从这里开始就只与具体的设备驱动相关了,这里我选取FLD00060光距感的驱动进行说明。
// 3rdparty/lsensor/fld60/special/driver/FLD60.c
static int __init fld60_pls_init(void)
{
int temp=0;
printk("baker :%s\n",__func__);
fld60_pls_config_pins();
printk("after baker :%s\n",__func__);
temp = i2c_add_driver(&fld60_pls_driver);
printk("add driver result = %d--\n",temp);
return temp;
}
//kernel/include/linux/i2c.h
static inline int i2c_add_driver(struct i2c_driver *driver)
{
return i2c_register_driver(THIS_MODULE, driver);
}
/*
* An i2c_driver is used with one or morei2c_client (device) nodes to access
* i2c slave chips, on a bus instanceassociated with some i2c_adapter.
*/
//kernel/drivers/i2c/i2c-core.c
int i2c_register_driver(struct module *owner, struct i2c_driver*driver)
{
int res;
/* Can't register until after drivermodel init */
if (unlikely(WARN_ON(!i2c_bus_type.p)))
return -EAGAIN;
/* add the driver to the list of i2cdrivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus =&i2c_bus_type;
/* Whenregistration returns, the driver core
* will have called probe() for allmatching-but-unbound devices.
*/
//i2c_driver结构体中的driver变量是个device_driver类型的结构体
res = driver_register(&driver->driver);
if (res)
return res;
pr_debug("i2c-core: driver [%s]registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are alreadypresent */
mutex_lock(&core_lock);
bus_for_each_dev(&i2c_bus_type, NULL,driver, __process_new_driver);
mutex_unlock(&core_lock);
return 0;
}
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to thebus_add_driver() call,
* since most of the things we have to do dealwith the bus
* structures.
*/
//kernel/drivers/base/driver.c
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
if ((drv->bus->probe &&drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver'%s' needs updating - please use "
"bus_typemethods\n", drv->name);
other = driver_find(drv->name,drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error:Driver '%s' is already registered, "
"aborting...\n",drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv,drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
//kernel/drivers/base/bus.c
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver%s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv),GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices,NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset =bus->p->drivers_kset;
error =kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
if(drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
error = driver_create_file(drv,&driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: ueventattr (%s) failed\n",
__func__, drv->name);
}
//如果有 driver和 client 匹配,就把 driver添加到总线中。
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out ofthis pickle? Give up */
printk(KERN_ERR "%s:driver_add_attrs(%s) failed\n",
__func__, drv->name);
}
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s:add_bind_files(%s) failed\n",
__func__,drv->name);
}
}
kobject_uevent(&priv->kobj,KOBJ_ADD);
return 0;
out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
/**
* driver_attach - try to bind driver todevices.
* @drv: driver.
*
* Walk the list of devices that the bus has onit and try to
* match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set,we've found a
* compatible pair.
*/
//kernel/drivers/base/dd.c
intdriver_attach(structdevice_driver *drv)
{
return bus_for_each_dev(drv->bus,NULL, drv, __driver_attach);
}
//kernel/drivers/base/dd.c
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
/*
*Lock device and try to bind to it. We drop the error
*here and always return 0, because we need to keep trying
*to bind to devices and some drivers will return an error
*simply if it didn't support the device.
*
*driver_probe_device() will spit a warning if there
*is an error.
*/
if (!driver_match_device(drv, dev))
return 0;
if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
先执行 driver_match_device,当client和driver匹配时,再调用driver_probe_device。下面我们先看看driver_match_device
//kernel/drivers/base/base.h
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ?drv->bus->match(dev, drv) : 1;
//drv就是i2c_driver->driver,当i2c_driver->driver->bus->match函数存在时,就调用该函数,否则返回1。
}
还记得在i2c_register_driver中对i2c_driver->driver->bus的初始化吗?
//kernel/drivers/i2c/i2c-core.c
int i2c_register_driver(structmodule *owner, struct i2c_driver *driver)
{
… …
driver->driver.bus =&i2c_bus_type;
… …
}
//kernel/drivers/i2c/i2c-core.c
struct bus_type i2c_bus_type = {
.name ="i2c",
.match = i2c_device_match,
.probe =i2c_device_probe,
.remove =i2c_device_remove,
.shutdown =i2c_device_shutdown,
.pm =&i2c_device_pm_ops,
};
//kernel/drivers/i2c/i2c-core.c
static inti2c_device_match(structdevice *dev, struct device_driver *drv)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
if (!client)
return 0;
driver = to_i2c_driver(drv);
/* match on an id table if there is one*/
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
return 0;
}
//kernel/drivers/i2c/i2c-core.c
static conststruct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
conststruct i2c_client *client)
{
while (id->name[0]) {
//比较项为 client->name和 i2c_driver->id_table->name,因此 client的注册要在 driver之前,要不然这里将无法比较
if (strcmp(client->name,id->name) == 0)
return id;
id++;
}
return NULL;
}
driver_match_device完了后,接下来我们再看看 driver_probe_device
/**//driver_probe_device 的作用
* driver_probe_device - attempt to bind device& driver together
* @drv: driver to bind a device to
* @dev: device to try to bind to the driver
*
* This function returns -ENODEV if the deviceis not registered,
* 1 if the device is bound successfully and 0otherwise.
*
* This function must be called with @dev lockheld. When called for a
* USB interface, @dev->parent lock must beheld as well.
*/
//kernel/drivers/base/dd.c
int driver_probe_device(struct device_driver *drv, struct device*dev)
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
pr_debug("bus: '%s': %s: matcheddevice %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev),drv->name);
pm_runtime_get_noresume(dev);
pm_runtime_barrier(dev);
ret = really_probe(dev, drv);
pm_runtime_put_sync(dev);
return ret;
}
//kernel/drivers/base/dd.c
static int really_probe(struct device *dev, struct device_driver*drv)
{
int ret = 0;
atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probingdriver %s with device %s\n",
drv->bus->name, __func__, drv->name,dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv;
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s:driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
if (dev->bus->probe) {
//如果总线存在probe函数存在,先调用该probe函数
//这里dev->bus和drv->bus是一样的吗?由drv.bus=&i2c_bus_type以及dev->driver=drv知,这里的dev是不是要换成dev->driver?
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
//否则调用i2c_driver->device_driver->probe函数
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bounddevice %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev),drv->name);
goto done;
probe_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
if (ret != -ENODEV && ret !=-ENXIO) {
/* driver matched but the probefailed */
printk(KERN_WARNING
"%s: probe of %s failed with error%d\n",
drv->name, dev_name(dev), ret);
}
/*
*Ignore errors returned by ->probe so that the next driver can try
*its luck.
*/
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}
//kernel/drivers/i2c/i2c-core.c
int i2c_register_driver(structmodule *owner, struct i2c_driver *driver)
{
… …
driver->driver.bus= &i2c_bus_type;
… …
}
//kernel/drivers/i2c/i2c-core.c
struct bus_type i2c_bus_type = {
.name ="i2c",
.match =i2c_device_match,
.probe = i2c_device_probe,
.remove =i2c_device_remove,
.shutdown =i2c_device_shutdown,
.pm =&i2c_device_pm_ops,
};
//kernel/drivers/i2c/i2c-core.c
static inti2c_device_probe(structdevice *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
int status;
if (!client)
return 0;
//从really_probe函数可知,dev->driver = drv,因此dev->driver实际就是i2c_driver->device_driver。
//利用to_i2c_driver将device_driver转换成了i2c_driver
driver =to_i2c_driver(dev->driver);
if (!driver->probe ||!driver->id_table)
return -ENODEV;
client->driver = driver;
if(!device_can_wakeup(&client->dev))
device_init_wakeup(&client->dev,
client->flags& I2C_CLIENT_WAKE);
dev_dbg(dev, "probe\n");
status = driver->probe(client, i2c_match_id(driver->id_table,client));
if (status) {
client->driver = NULL;
i2c_set_clientdata(client, NULL);
}
return status;
}
// 3rdparty/lsensor/fld60/special/driver/FLD60.c
static structi2c_driver fld60_pls_driver = {
.driver = {
.owner = THIS_MODULE,
.name = FLD60_PLS_DEVICE,
},
.probe = fld60_pls_probe,
.remove = fld60_pls_remove,
.id_table = fld60_pls_id,
};
- 四、注册 i2c_driver
- linux I2C 驱动之----i2c_driver的注册 .
- linux I2C 驱动之----i2c_driver的注册
- linux I2C 驱动之----i2c_driver的注册
- linux I2C 驱动之----i2c_driver的注册
- i2c_driver的注册及probe探测函数调用
- linux内核的I2C子系统详解5——i2c_driver的注册、i2c_client的来源
- i2c_driver结构体
- i2c_driver结构体
- 四、usb设备注册
- (四) 注册设备
- 四、usb设备注册
- linux i2c_driver 结构体解析
- 简易聊天室四 注册用户
- i2c struct i2c_adapter /i2c_client /i2c_driver /i2c_add_driver() /i2c_register_driver()
- i2c_driver的detect函数的调用
- 注册(四)之删除绑定
- 注册测绘师学习笔记(四)
- 三、创建 i2c_adapter 和 i2c_client
- 【java】递归实现文件列表
- 财经类节目
- maxdb backup error code 3700 hostfile_error
- Secret of the JavaScript Ninja 学习笔记 - 3
- 四、注册 i2c_driver
- IOS开发之----XML常用操作
- Review_2012_10_29
- Review_2012_10_30
- Android Mms专题之:Mms概览介绍
- Review_2012_10_31
- Android Mms专题之:Mms源码结构
- Android Mms专题之:信息发送流程
- 知识拾记