嵌入式软件开发之------浅析linux驱动模型(五)I2C驱动
Linux代码版本:linux3.0
开发板环境: tiny4412
导读:i2c控制器作为platform_device挂接在platform总线上,在《嵌入式软件开发之------浅谈linux驱动模型(四)device和driver》以i2c控制器为例,分析了
s3c_device_i2c1和s3c24xx_i2c_driver的注册过程,总结下来就是下图:
每个i2c控制器都是一个i2c 总线,i2c控制器即挂接在platform总线上,也为i2c提供总线。platform总线有platform_device和platform_driver,相应的i2c总线也有对应的device和driver,只不过是i2c_client和i2c_driver.
一、i2c_adapter的注册及 i2c_client 的实例化
下面看i2c_client,有没有觉得和platform_device很像?都是封装了devcie后添加了部分各自特点的成员:
struct i2c_client {
unsigned short flags; /* div., see below */
unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter; /* the adapter we sit on */
struct i2c_driver *driver; /* and our access routines */
struct device dev; /* the device structure */
int irq; /* irq issued by device */
struct list_head detected;
};
unsigned short flags;
标志,用 I2C_CLIENT_TEN 表示 10 bit 地址,用 I2C_CLIENT_PEC 表示SMBus的错误数据检测
unsigned short addr;
器件的地址
char name[I2C_NAME_SIZE];
设备的名字,在 new_device 属性文件中,低7位代表地址
struct i2c_adapter *adapter; /* the adapter we sit on */
虽然是挂接在I2C总线上的,client->dev.bus = &i2c_bus_type,可是 总要 指向所在的i2c控制器吗
struct i2c_driver *driver; /* and our access routines */
对应的驱动
struct device dev; /* the device structure */
封装的device结构体
int irq; /* irq issued by device */
用来表示此设备产生的IRQ
struct list_head detected;
用于插入 i2c_driver.clients 的节点,在遍历 i2c_drive r探测到实际挂接在 i2c_adapter 但又未注册
的 i2c 设备时,实例化成 i2c_client 后以此成员插入 i2c_driver.clients。
看到i2c_client就不得不看i2c设备的注册,这个时候可能有人会说,大概和platform设备注册差不多吧,确实 差不多,可还是有点区别下面就以mma7660为例,
static struct i2c_board_info i2c_devs3[] __initdata = {
{
I2C_BOARD_INFO("mma7660", 0x4c),
.platform_data = &mma7660_pdata,
},
};
展开
static struct i2c_board_info i2c_devs3[] __initdata = {
{
.type = "mma7660",
.addr = 0x4c,
.platform_data = &mma7660_pdata,
},
};
有没有发现什么不对?不是说i2c设备的结构体说 i2c_client ?咋变成了 i2c_board_info ?platform_device就是对应的啊。这里面肯定有蹊跷,i2c_board_info 最后肯定还得转成成 i2c_client,是的,这既是i2c设备的实例化,从定义的 i2c_board_info 组装成 i2c_client,这个过程将在代码中分析。接下来看一下 platform_device通过 platform_device_register来注册 ,那么 i2c_board_info 设备是通过i2c_register_board_info。
先看下 i2c_board_info 结构体
struct i2c_board_info {
char type[I2C_NAME_SIZE];
unsigned short flags;
unsigned short addr;
void *platform_data;
struct dev_archdata *archdata;
struct device_node *of_node;
int irq;
};
再看一个结构体,下面会用到
struct i2c_devinfo {
struct list_head list;
int busnum;
struct i2c_board_info board_info;
};
下面再看 i2c_register_board_info 实例
i2c_register_board_info(3, i2c_devs3, ARRAY_SIZE(i2c_devs3));
{
int status;
down_write(&__i2c_board_lock);
/* dynamic bus numbers will be assigned after the last static one */
/*__i2c_first_dynamic_bus_num总是要比最大的bus号大1,后面会用到*/
if (busnum >= __i2c_first_dynamic_bus_num)
__i2c_first_dynamic_bus_num = busnum + 1;
for (status = 0; len; len--, info++) {
struct i2c_devinfo *devinfo;
devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
if (!devinfo) {
pr_debug("i2c-core: can't register boardinfo!\n");
status = -ENOMEM;
break;
}
/*将i2c_board_info的信息赋值给 devinfo ,然后将devinfo插入 __i2c_board_list ,所有的i2c设备都会插入
__i2c_board_list,所以一定要记住__i2c_board_list,
devinfo->busnum = 3
devinfo->board_info = &i2c_devs3 */
devinfo->busnum = busnum;
devinfo->board_info = *info;
list_add_tail(&devinfo->list, &__i2c_board_list);
}
up_write(&__i2c_board_lock);
return status;
}
上面的知识将在下面的代码中用到,下面接着 分析 s3c24xx_i2c_probe,由于是在分析驱动框架,不是分析BSP,
硬件设备千变万化,看芯片手册写或者调试驱动是一个驱动工程师的基本功,所以对于硬件相关的设置将省略。
下面接着分析经过platform总线匹配后调用的 s3c24xx_i2c_probe
static int s3c24xx_i2c_probe(&s3c_device_i2c3)
{
struct s3c24xx_i2c *i2c;
struct s3c2410_platform_i2c *pdata;
struct resource *res;
int ret;
......
/*赋值 i2c->adap.name = "s3c2410-i2c",后面会用到*/
strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
/*i2c->adap进行复制,又看到了 THIS_MODULE 只有当此驱动编译成module的时候指向此模块
,如果没有编译成module则为NULL,绝大多数owner都是 THIS_MODULE */
i2c->adap.owner = THIS_MODULE;
/*i2c->adap.algo,对应实际硬件的通信方法,控制硬件产生读写时序的函数,adapter是对硬件控制器的抽象,
实际产生硬件通信时序的s3c24xx_i2c_algorithm*/
i2c->adap.algo = &s3c24xx_i2c_algorithm;
/*通信失败重新尝试的次数*/
i2c->adap.retries = 2;
/*此adapter支持的硬件类型,公共也就是三种 I2C_CLASS_HWMON、I2C_CLASS_SPD 和 I2C_CLASS_DDC
相应的,i2c_client或者i2c_driver肯定也会有相应的class来和 i2c->adap.class 匹配 */
i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
......
/* setup info block for the i2c core */
i2c->adap.algo_data = i2c;
/*i2c->adap.dev.parent 指向 s3c_device_i2c1 ,
意味着i2c->adap对应的目录会在/sys/devices/platform/s3c2440-i2c.3下*/
i2c->adap.dev.parent = &pdev->dev;
......
/* Note, previous versions of the driver used i2c_add_adapter()
* to add the bus at any number. We now pass the bus number via
* the platform data, so if unset it will now default to always
* being bus 0.
*/
/*此adapter所对应的i2c总线号,这里是通过 paltform_device的私有结构体传递,实际还有另一个代表
/sys/devices/platform/s3c2440-i2c.3
i2c总线号的,还记得 s3c_device_i2c3.id = 3吗*/
i2c->adap.nr = pdata->bus_num;
/*注册adapter*/
ret = i2c_add_numbered_adapter(&i2c->adap);
{
int id;
int status;
if (adap->nr & ~MAX_ID_MASK)
return -EINVAL;
/*下面涉及idr机制,简单的说idr机制就是将一个整数id和特定指针映射起来,然后可以通过id号
找到对应的指针*/
retry:
/*为idr分配内存,通过idr获取id之前需要先分配内存*/
if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
return -ENOMEM;
mutex_lock(&core_lock);
/* "above" here means "above or equal to", sigh;
* we need the "equal to" result to force the result
*/
/*分配id号并和adap指针关联,对于i2c adapter分配的id就是bus号,所以下面会有
id和adap->nr的判断*/
status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
if (status == 0 && id != adap->nr) {
status = -EBUSY;
idr_remove(&i2c_adapter_idr, id);
}
mutex_unlock(&core_lock);
if (status == -EAGAIN)
goto retry;
if (status == 0)
/*开始注册adapter*/
status = i2c_register_adapter(adap);
{
int res = 0;
/* Can't register until after driver model init */
/*i2c被初始化过才能注册adapter,显然注册 i2c_bus_type 就已经初始化过*/
if (unlikely(WARN_ON(!i2c_bus_type.p))) {
res = -EAGAIN;
goto out_list;
}
/* Sanity checks */
/*前面已经初始化 adap->name[0] = "s3c2410-i2c" */
if (unlikely(adap->name[0] == '\0')) {
pr_err("i2c-core: Attempt to register an adapter with "
"no name!\n");
return -EINVAL;
}
/*上面已经初始化过 i2c->adap.algo = &s3c24xx_i2c_algorithm */
if (unlikely(!adap->algo)) {
pr_err("i2c-core: Attempt to register adapter '%s' with "
"no algo!\n", adap->name);
return -EINVAL;
}
rt_mutex_init(&adap->bus_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
/* Set default timeout to 1 second if not already set */
/*上面没有初始化超时时间,所以默认设置为1s*/
if (adap->timeout == 0)
adap->timeout = HZ;
/*赋值 i2c->adap->dev->kobj->name = "i2c-3",意味着将来创建目录的名字为 i2c-3 */
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
/*adapter也是一个device,类型为 i2c_adapter_type ,所以指向i2c_bus_type,其本身提供具体的i2c总线*/
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
/*下面即使device的注册过程*/
res = device_register(&adap->dev);
{
device_initialize(dev);
{
/*adapter也是一个device,所以其 kobject 属于 devices_kset,类型为 device_ktype*/
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
lockdep_set_novalidate_class(&dev->mutex);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_pm_init(dev);
set_dev_node(dev, -1);
}
return device_add(dev);
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
dev = get_device(dev);
if (!dev)
goto done;
if (!dev->p) {
error = device_private_init(dev);
{
dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
if (!dev->p)
return -ENOMEM;
dev->p->device = dev;
klist_init(&dev->p->klist_children, klist_children_get,
klist_children_put);
return 0;
}
if (error)
goto done;
}
/*
* for statically allocated devices, which should all be converted
* some day, we need to initialize the name. We prevent reading back
* the name, and force the use of dev_name()
*/
/* i2c->adap->dev->init_name未被赋值,也就是为NULL*/
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}
/* i2c->adap->dev->kobj->name = "i2c-3" ,所以此条件不会被满足 */
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
/*前面初始化 i2c->adap.dev.parent = &pdev->dev */
parent = get_device(dev->parent);
/*device层面的parent已经建立,setup_parent要建立kobject 层面 的parent关系*/
setup_parent(dev, parent);
/* use parent numa_node */
/*NUMA架构一般应用于大型多CPU的设备,嵌入式单个多核CPU使用SMP架构*/
if (parent)
set_dev_node(dev, dev_to_node(parent));
/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
/*又看见kobject_add,在sys/devices/platform/s3c2440-i2c.3创建i2c-3目录*/
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
if (error)
goto Error;
/* notify platform of device entry */
/*暂时不知道具体用途,代码中极少给platform_notify赋值*/
if (platform_notify)
platform_notify(dev);
/*在sys/devices/platform/s3c2440-i2c.1/i2c-3创建uevent文件*/
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
/*此时 i2c->adap->dev 还没有设备号,所以执行不到,等到 device_creat 的时候再详细分析*/
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
devtmpfs_create_node(dev);
}
error = device_add_class_symlinks(dev);
{
int error;
/*i2c->adap->dev->class未赋值,也就是为NULL,在此返回*/
if (!dev->class)
return 0;
error = sysfs_create_link(&dev->kobj,
&dev->class->p->subsys.kobj,
"subsystem");
if (error)
goto out;
if (dev->parent && device_is_not_partition(dev)) {
error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
"device");
if (error)
goto out_subsys;
}
#ifdef CONFIG_BLOCK
/* /sys/block has directories and does not need symlinks */
if (sysfs_deprecated && dev->class == &block_class)
return 0;
#endif
/* link in the class directory pointing to the device */
error = sysfs_create_link(&dev->class->p->subsys.kobj,
&dev->kobj, dev_name(dev));
if (error)
goto out_device;
return 0;
out_device:
sysfs_remove_link(&dev->kobj, "device");
out_subsys:
sysfs_remove_link(&dev->kobj, "subsystem");
out:
return error;
}
if (error)
goto SymlinkError;
/*为 i2c->adap 创建属性文件*/
error = device_add_attrs(dev);
{
struct class *class = dev->class;
const struct device_type *type = dev->type;
int error;
/*i2c->adap->dev->class未赋值,也就是为NULL,在此返回*/
if (class) {
error = device_add_attributes(dev, class->dev_attrs);
{
int error = 0;
int i;
if (attrs) {
for (i = 0; attr_name(attrs[i]); i++) {
error = device_create_file(dev, &attrs[i]);
if (error)
break;
}
if (error)
while (--i >= 0)
device_remove_file(dev, &attrs[i]);
}
return error;
}
if (error)
return error;
error = device_add_bin_attributes(dev, class->dev_bin_attrs);
if (error)
goto err_remove_class_attrs;
}
/*前面赋值 i2c->adap->dev->type = &i2c_adapter_type,其中
i2c_adapter_type->groups = i2c_adapter_attr_groups,
i2c_adapter_attr_groups = &i2c_adapter_attr_group,
i2c_adapter_attr_group->attr = i2c_adapter_attrs,
i2c_adapter_attrs[] = {
&dev_attr_name.attr,
&dev_attr_new_device.attr,
&dev_attr_delete_device.attr,
NULL
};
所以最终将在/sys/devices/platform/s3c2440-i2c.3/i2c-3下创建 name、new_device和delete_device的属性文件*/
if (type) {
error = device_add_groups(dev, type->groups);
{
int error = 0;
int i;
if (groups) {
for (i = 0; groups[i]; i++) {
error = sysfs_create_group(&dev->kobj, groups[i]);
if (error) {
while (--i >= 0)
sysfs_remove_group(&dev->kobj,
groups[i]);
break;
}
}
}
return error;
}
if (error)
goto err_remove_class_bin_attrs;
}
/*i2c->adap->dev->groups也是未初始化的*/
error = device_add_groups(dev, dev->groups);
if (error)
goto err_remove_type_groups;
return 0;
err_remove_type_groups:
if (type)
device_remove_groups(dev, type->groups);
err_remove_class_bin_attrs:
if (class)
device_remove_bin_attributes(dev, class->dev_bin_attrs);
err_remove_class_attrs:
if (class)
device_remove_attributes(dev, class->dev_attrs);
return error;
}
if (error)
goto AttrsError;
/*i2c->adap 添加到 i2c_bus_type*/
error = bus_add_device(dev);
{
struct bus_type *bus = bus_get(dev->bus);
int error = 0;
if (bus) {
pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
error = device_add_attrs(bus, dev);
{
int error = 0;
int i;
/*由于i2c_bus_type->dev_attrs = NULL,
所以不会创建任何属性文件*/
if (!bus->dev_attrs)
return 0;
for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
error = device_create_file(dev, &bus->dev_attrs[i]);
if (error) {
while (--i >= 0)
device_remove_file(dev, &bus->dev_attrs[i]);
break;
}
}
return error;
}
if (error)
goto out_put;
/*在注册i2c_bus_type的时候
priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
下面就是要在/sys/bus/i2c/devices创建指向 /sys/devices/platform/s3c2440-i2c.3/i2c-3
的链接,名字也为i2c-3*/
error = sysfs_create_link(&bus->p->devices_kset->kobj,
&dev->kobj, dev_name(dev));
if (error)
goto out_id;
/*在/sys/devices/platform/s3c2440-i2c.3/i2c-3创建指向/sys/bus/i2c/的链接,
名字为subsystem*/
error = sysfs_create_link(&dev->kobj,
&dev->bus->p->subsys.kobj, "subsystem");
if (error)
goto out_subsys;
/*将 i2c->adap 加入到i2c_bus_type->p->klist_devices链表中*/
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
}
return 0;
out_subsys:
sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
out_id:
device_remove_attrs(bus, dev);
out_put:
bus_put(dev->bus);
return error;
}
if (error)
goto BusError;
/*电源管理相关,后面分析的电源管理机制的时候再详细分析*/
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev);
/* Notify clients of device addition. This call must come
* after dpm_sysf_add() and before kobject_uevent().
*/
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_probe_device(dev);
{
struct bus_type *bus = dev->bus;
int ret;
/* i2c_bus_type 注册的时候初始化 i2c_bus_type->p->drivers_autoprobe = 1
/sys/bus/i2c 下的drivers_autoprobe,drivers_autoprobe被置1
则自动进行驱动匹配*/
if (bus && bus->p->drivers_autoprobe) {
ret = device_attach(dev);
{
int ret = 0;
device_lock(dev);
/*现在只注册 i2c->adap , i2c->adap ->dev->driver = NULL*/
if (dev->driver) {
if (klist_node_attached(&dev->p->knode_driver)) {
ret = 1;
goto out_unlock;
}
ret = device_bind_driver(dev);
{
int ret;
ret = driver_sysfs_add(dev);
if (!ret)
driver_bound(dev);
return ret;
}
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
}
else {
pm_runtime_get_noresume(dev);
/*通过 __device_attach 函数逐个匹配 i2c_bus_type->p->klist_drivers成员
i2c->adap 只是作为一个device注册,没有所谓的驱动,类似 platform_bus 一样,*/
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
pm_runtime_put_sync(dev);
}
out_unlock:
device_unlock(dev);
return ret;
}
WARN_ON(ret < 0);
}
}
/*将 i2c->adap 加入 s3c_device_i2c3 的子设备链表*/
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
/*将 i2c->adap 加入到class的设备链表中,目前 i2c->adap->dev->class = NULL */
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->klist_devices);
/* notify any interfaces that the device is here */
/*暂时还没弄清class_interface的具体用途*/
list_for_each_entry(class_intf,
&dev->class->p->class_interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->class_mutex);
}
done:
put_device(dev);
return error;
DPMError:
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
if (MAJOR(dev->devt))
devtmpfs_delete_node(dev);
if (MAJOR(dev->devt))
device_remove_sys_dev_entry(dev);
devtattrError:
if (MAJOR(dev->devt))
device_remove_file(dev, &devt_attr);
ueventattrError:
device_remove_file(dev, &uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
cleanup_device_parent(dev);
if (parent)
put_device(parent);
name_error:
kfree(dev->p);
dev->p = NULL;
goto done;
}
}
if (res)
goto out_list;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
#ifdef CONFIG_I2C_COMPAT
/* i2c_adapter_compat_class = class_compat_register("i2c-adapter");
在 sys/calss/i2c-adapter 目录下创建链接*/
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,adap->dev.parent);
{
int error;
/* 在 sys/calss/i2c-adapter 目录下创建链接 指向 sys/devices/platform/s3c2440-i2c.3/i2c-3 的链接,名字仍为 i2c-3 */
error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev));
{
return sysfs_do_create_link(kobj, target, name, 1);
}
if (error)
return error;
/*
* Optionally add a "device" link (typically to the parent), as a
* class device would have one and we want to provide as much
* backwards compatibility as possible.
*/
if (device_link) {
/*在 sys/devices/platform/s3c2440-i2c.3/i2c-3 目录下创建指向 sys/devices/platform/s3c2440-i2c.3 ,名字为device */
error = sysfs_create_link(&dev->kobj, &device_link->kobj,
"device");
if (error)
sysfs_remove_link(cls->kobj, dev_name(dev));
}
return error;
}
if (res)
dev_warn(&adap->dev,
"Failed to create compatibility class link\n");
#endif
/* create pre-declared device nodes */
/* 重点来了, i2c_client 的实例化,由 i2c_board_info 生成 i2c_client */
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
{
struct i2c_devinfo *devinfo;
down_read(&__i2c_board_lock);
/*还记得前面 i2c_register_board_info 把所有的 i2c_board_info 都注册到 __i2c_board_list ,
下面就是遍历 __i2c_board_list ,查找 属于 i2c->adap 的设备 */
list_for_each_entry(devinfo, &__i2c_board_list, list) {
if (devinfo->busnum == adapter->nr
&& !i2c_new_device(adapter,&devinfo->board_info))
{
/*每查到一个 属于 i2c->adap 的设备 ,声明一个 i2c_client ,这里就以前面注册的 i2c_devs3 为例*/
struct i2c_client *client;
int status;
client = kzalloc(sizeof *client, GFP_KERNEL);
if (!client)
return NULL;
/*初始化该 i2c_client 所属的 adap */
client->adapter = adap;
/* client->dev.platform_data = i2c_devs3->platform_data = &mma7660_pdata*/
client->dev.platform_data = info->platform_data;
if (info->archdata)
client->dev.archdata = *info->archdata;
/*i2c_devs3->flags 未初始化,也就是为 0 */
client->flags = info->flags;
/*client->addr = 0x4c*/
client->addr = info->addr;
client->irq = info->irq;
/* client->name = "mma7660" */
strlcpy(client->name, info->type, sizeof(client->name));
/* Check for address validity */
/*检查 client->addr 的合法性 */
status = i2c_check_client_addr_validity(client);
if (status) {
dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
goto out_err_silent;
}
/* Check for address business */
/*检查 i2c->adap 是否注册过 相同 address 的 i2c 期间,一个 i2c 总线上的器件address 必须唯一*/
status = i2c_check_addr_busy(adap, client->addr);
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
{
/*前面初始化 i2c->adap->dev->parent = s3c_device_i2c3->dev,所以 parent = NULL */
struct device *parent = adapter->dev.parent;
if (parent != NULL && parent->type == &i2c_adapter_type)
return to_i2c_adapter(parent);
else
return NULL;
}
int result = 0;
/* parent = NULL */
if (parent)
result = i2c_check_mux_parents(parent, addr);
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
int result;
result = device_for_each_child(&adapter->dev, &addr,
__i2c_check_addr_busy);
if (!result && parent)
result = i2c_check_mux_parents(parent, addr);
return result;
}
if (!result)
result = device_for_each_child(&adapter->dev, &addr,i2c_check_mux_children);
{
struct klist_iter i;
struct device *child;
int error = 0;
if (!parent->p)
return 0;
klist_iter_init(&parent->p->klist_children, &i);
while ((child = next_device(&i)) && !error)
error = fn(child, data); //fn = i2c_check_mux_children
{
int result;
if (dev->type == &i2c_adapter_type)
result = device_for_each_child(dev, addrp,
i2c_check_mux_children);
else
/*此地址已经被注册过,则返回 -EBUSY */
result = __i2c_check_addr_busy(dev, addrp);
{
struct i2c_client *client = i2c_verify_client(dev);
int addr = *(int *)addrp;
if (client && client->addr == addr)
return -EBUSY;
return 0;
}
return result;
}
klist_iter_exit(&i);
return error;
}
return result;
}
if (status)
goto out_err;
client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
/* client->dev->kobj = "3-004c" */
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr);
/*将 client 注册到 /sys/devices/platform/s3c2440-i2c.3/i2c-3 目录下,并创建 3-004c 目录,同事创建
uevent、name和 new_device 属性文件和一些链接文件等等 */
status = device_register(&client->dev);
if (status)
goto out_err;
dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
client->name, dev_name(&client->dev));
return client;
out_err:
dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
"(%d)\n", client->name, client->addr, status);
out_err_silent:
kfree(client);
return NULL;
}
dev_err(&adapter->dev,
"Can't create device at 0x%02x\n",
devinfo->board_info.addr);
}
up_read(&__i2c_board_lock);
}
/* Notify drivers */
mutex_lock(&core_lock);
/*遍历已经注册 i2c_driver 和 i2c->adap ,然后探测 i2c->adap 上i2c_driver支持的地址,
如果已经注册则跳过,未注册但有该 i2c 设备,则进行实例化*/
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
{
struct klist_iter i;
struct device_driver *drv;
int error = 0;
if (!bus)
return -EINVAL;
/*遍历 i2c_bus_type->p->klist_drivers ,然后调用 __process_new_adapter*/
klist_iter_init_node(&bus->p->klist_drivers, &i,
start ? &start->p->knode_bus : NULL);
while ((drv = next_driver(&i)) && !error)
error = fn(drv, data); //fn = __process_new_adapter
{
return i2c_do_add_adapter(to_i2c_driver(d), data);
{
/* Detect supported devices on that bus, and instantiate them */
i2c_detect(adap, driver);
{ /* driver 所支持i2c设备的 address 列表*/
const unsigned short *address_list;
/* 声明一个临时的 i2c_client */
struct i2c_client *temp_client;
int i, err = 0;
int adap_id = i2c_adapter_id(adapter);
/*如果 */
address_list = driver->address_list;
if (!driver->detect || !address_list)
return 0;
/* Stop here if the classes do not match */
if (!(adapter->class & driver->class))
return 0;
/* Set up a temporary client to help detect callback */
temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (!temp_client)
return -ENOMEM;
temp_client->adapter = adapter;
for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
"addr 0x%02x\n", adap_id, address_list[i]);
temp_client->addr = address_list[i];
err = i2c_detect_address(temp_client, driver);
{
struct i2c_board_info info;
struct i2c_adapter *adapter = temp_client->adapter;
int addr = temp_client->addr;
int err;
/* Make sure the address is valid */
err = i2c_check_addr_validity(addr);
{
/*
* Reserved addresses per I2C specification:
* 0x00 General call address / START byte
* 0x01 CBUS address
* 0x02 Reserved for different bus format
* 0x03 Reserved for future purposes
* 0x04-0x07 Hs-mode master code
* 0x78-0x7b 10-bit slave addressing
* 0x7c-0x7f Reserved for future purposes
*/
if (addr < 0x08 || addr > 0x77)
return -EINVAL;
return 0;
}
if (err) {
dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
addr);
return err;
}
/* Skip if already in use */
if (i2c_check_addr_busy(adapter, addr))
{
/*前面初始化 i2c->adap->dev->parent = s3c_device_i2c3->dev,所以 parent = NULL */
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
int result = 0;
if (parent)
result = i2c_check_mux_parents(parent, addr);
if (!result)
result = device_for_each_child(&adapter->dev, &addr,i2c_check_mux_children);
{
struct klist_iter i;
struct device *child;
int error = 0;
if (!parent->p)
return 0;
/*遍历 查询 i2c->adap 下的设备,也就是 i2c _client */
klist_iter_init(&parent, &i);
while ((child = next_device(&i)) && !error)
error = fn(child, data); //fn = i2c_check_mux_children
{
int result;
if (dev->type == &i2c_adapter_type)
result = device_for_each_child(dev, addrp,i2c_check_mux_children);
else
result = __i2c_check_addr_busy(dev, addrp);
{
struct i2c_client *client = i2c_verify_client(dev);
int addr = *(int *)addrp;
if (client && client->addr == addr)
return -EBUSY;
return 0;
}
return result;
}
klist_iter_exit(&i);
return error;
}
return result;
}
return 0;
/* Make sure there is something at this address */
if (!i2c_default_probe(adapter, addr))
{
int err;
union i2c_smbus_data dummy;
#ifdef CONFIG_X86
if (addr == 0x73 && (adap->class & I2C_CLASS_HWMON)
&& i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA))
err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
I2C_SMBUS_BYTE_DATA, &dummy);
else
#endif
if (!((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50)
&& i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0,
I2C_SMBUS_QUICK, NULL);
else if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE))
err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
I2C_SMBUS_BYTE, &dummy);
else {
dev_warn(&adap->dev, "No suitable probing method supported\n");
err = -EOPNOTSUPP;
}
return err >= 0;
}
return 0;
/* Finally call the custom detection function */
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = addr;
err = driver->detect(temp_client, &info);
if (err) {
/* -ENODEV is returned if the detection fails. We catch it
here as this isn't an error. */
return err == -ENODEV ? 0 : err;
}
/* Consistency check */
if (info.type[0] == '\0') {
dev_err(&adapter->dev, "%s detection function provided "
"no name for 0x%x\n", driver->driver.name,
addr);
} else {
struct i2c_client *client;
/* Detection succeeded, instantiate the device */
dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
info.type, info.addr);
/*驱动探测到 adapter 上有该驱动支持的设备但又未 注册 ,则给其实例化*/
client = i2c_new_device(adapter, &info);
if (client)
list_add_tail(&client->detected, &driver->clients);
else
dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
info.type, info.addr);
}
return 0;
}
if (unlikely(err))
break;
}
kfree(temp_client);
return err;
}
/* Let legacy drivers scan this bus for matching devices */
if (driver->attach_adapter) {
dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
driver->driver.name);
dev_warn(&adap->dev, "Please use another way to instantiate "
"your i2c_client\n");
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
return 0;
}
}
klist_iter_exit(&i);
return error;
}
mutex_unlock(&core_lock);
return 0;
out_list:
mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock);
return res;
}
return status;
}
if (ret < 0) {
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
goto err_cpufreq;
}
platform_set_drvdata(pdev, i2c);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
clk_disable(i2c->clk);
return 0;
err_cpufreq:
s3c24xx_i2c_deregister_cpufreq(i2c);
err_irq:
free_irq(i2c->irq, i2c);
err_iomap:
iounmap(i2c->regs);
err_ioarea:
release_resource(i2c->ioarea);
kfree(i2c->ioarea);
err_clk:
clk_disable(i2c->clk);
clk_put(i2c->clk);
err_noclk:
kfree(i2c);
return ret;
}
上面的主要工作,就是初始化 i2c_adapter 的硬件,并且注册 i2c_adapter ,注册后将会 遍历 __i2c_board_list 查找挂接在此 i2c_adapter 的 i2c_board_info ,然后实例化 成 i2c_client ,然后 遍历 已经注册的 i2c_driver ,查找此 i2c_adapter 是否有 已经注册的 i2c_driver 支持的 但又未 注册的 i2c 器件,查到后实例化成 i2c_client 并注册。
整个过程下来,仍然会生成一些 属性文件 和一些链接文件,下面关注 new_device 和 delete_device 两个属性文件。
static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
展开
struct device_attribute dev_attr_new_device = {
.attr = {
.name = "new_device",
.mode = S_IWUSR
},
.show = NULL,
.store = i2c_sysfs_new_device,
}
看store函数
static ssize_t i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
{
struct i2c_adapter *adap = to_i2c_adapter(dev);
struct i2c_board_info info;
struct i2c_client *client;
char *blank, end;
int res;
memset(&info, 0, sizeof(struct i2c_board_info));
blank = strchr(buf, ' ');
if (!blank) {
dev_err(dev, "%s: Missing parameters\n", "new_device");
return -EINVAL;
}
if (blank - buf > I2C_NAME_SIZE - 1) {
dev_err(dev, "%s: Invalid device name\n", "new_device");
return -EINVAL;
}
memcpy(info.type, buf, blank - buf);
/* Parse remaining parameters, reject extra parameters */
res = sscanf(++blank, "%hi%c", &info.addr, &end);
if (res < 1) {
dev_err(dev, "%s: Can't parse I2C address\n", "new_device");
return -EINVAL;
}
if (res > 1 && end != '\n') {
dev_err(dev, "%s: Extra parameters\n", "new_device");
return -EINVAL;
}
client = i2c_new_device(adap, &info);
if (!client)
return -EINVAL;
/* Keep track of the added device */
mutex_lock(&adap->userspace_clients_lock);
list_add_tail(&client->detected, &adap->userspace_clients);
mutex_unlock(&adap->userspace_clients_lock);
dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
info.type, info.addr);
return count;
}
new_device 文件就是为用户空间提供 一种添加 i2c 设备的接口,在不管 系统没有注册 此设备的时候 ,可以尝试通过 new_device 写入 i2c 期间的名字 添加该设备。
static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device);
展开
struct device_attribute dev_attr_delete_device = {
.attr = {
.name = "delete_device",
.mode = S_IWUSR
},
.show = NULL,
.store = i2c_sysfs_delete_device,
}
查看 store 函数
static ssize_t i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
{
struct i2c_adapter *adap = to_i2c_adapter(dev);
struct i2c_client *client, *next;
unsigned short addr;
char end;
int res;
/* Parse parameters, reject extra parameters */
res = sscanf(buf, "%hi%c", &addr, &end);
if (res < 1) {
dev_err(dev, "%s: Can't parse I2C address\n", "delete_device");
return -EINVAL;
}
if (res > 1 && end != '\n') {
dev_err(dev, "%s: Extra parameters\n", "delete_device");
return -EINVAL;
}
/* Make sure the device was added through sysfs */
res = -ENOENT;
mutex_lock(&adap->userspace_clients_lock);
list_for_each_entry_safe(client, next, &adap->userspace_clients,
detected) {
if (client->addr == addr) {
dev_info(dev, "%s: Deleting device %s at 0x%02hx\n",
"delete_device", client->name, client->addr);
list_del(&client->detected);
i2c_unregister_device(client);
res = count;
break;
}
}
mutex_unlock(&adap->userspace_clients_lock);
if (res < 0)
dev_err(dev, "%s: Can't find device in list\n",
"delete_device");
return res;
}
二、i2c_driver的注册
上面的代码已经 实例化 i2c_client 并且注册,下面就该注册相应的 i2c_driver ,然后通过 i2c_bus_type 的 match 调用 到
i2c_driver->probe 即 mma7660_probe 。
struct i2c_driver {
unsigned int class;
/* Notifies the driver that a new bus has appeared or is about to be
* removed. You should avoid using this, it will be removed in a
* near future.
*/
int (*attach_adapter)(struct i2c_adapter *) __deprecated;
int (*detach_adapter)(struct i2c_adapter *) __deprecated;
/* Standard driver model interfaces */
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
* For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag").
*/
void (*alert)(struct i2c_client *, unsigned int data);
/* a ioctl like command that can be used to perform specific functions
* with the device.
*/
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver;
const struct i2c_device_id *id_table;
/* Device detection callback for automatic device creation */
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_head clients;
};
unsigned int class;
此driver支持的i2c设备种类,用来和i2c_adapter中的class做对比,共三种类型I2C_CLASS_HWMON、I2C_CLASS_SPD 和 I2C_CLASS_DDC
int (*attach_adapter)(struct i2c_adapter *) __deprecated;
i2c 总线增加设备时的回调函数,已经弃用
int (*detach_adapter)(struct i2c_adapter *) __deprecated;
i2c 总线移除设备时的回调函数,已经弃用
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
void (*alert)(struct i2c_client *, unsigned int data);
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver;
const struct i2c_device_id *id_table;
此driver兼容的设备列表,i2c_device_match 时会调用
int (*detect)(struct i2c_client *, struct i2c_board_info *);
发现设备时的回调函数,在代码中发现 未注册 设备时会调用
const unsigned short *address_list;
此驱动支持的地址列表,注册 i2c_adapter 或 i2c_driver 时会调用此 列表判断
i2c_adapter 是否挂有此驱动兼容的设备
struct list_head clients;
遍历驱动发现的i2c设备将挂入此链表中,和i2c_client的detected对应
上面以 mma7660 为例实例化的 i2c_client,下面还以 mma7660 为例分析 i2c_driver 的注册
i2c_mma7660_driver的定义
static struct i2c_driver i2c_mma7660_driver = {
.driver = {
.name = MMA7660_NAME,
},
.probe = mma7660_probe,
.remove = __devexit_p(mma7660_remove),
.suspend = mma7660_suspend,
.resume = mma7660_resume,
.id_table = mma7660_ids,
};
其中的 id_table 为
static const struct i2c_device_id mma7660_ids[] = {
{ "mma7660", 0 },
{ },
};
下面就看 i2c_mma7660_driver 的注册过程。
static int __init init_mma7660(void)
{
int ret;
ret = i2c_add_driver(&i2c_mma7660_driver);
{
return i2c_register_driver(THIS_MODULE, driver);
{
int res;
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p)))
return -EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver);
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
/* i2c_bus_type->probe = i2c_device_probe
i2c_bus_type->remove = i2c_device_remove
i2c_bus_type->shutdown = i2c_device_shutdown
i2c_mma7660_driver->driver->probe = NULL
i2c_mma7660_driver->driver->remove = NULL
i2c_mma7660_driver->driver->shutdown = NULL*/
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_type methods\n", drv->name);
/*通过name查找是否已经注册过此driver*/
other = driver_find(drv->name, drv->bus);
{
struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
struct driver_private *priv;
if (k) {
priv = to_driver(k);
return priv->driver;
}
return NULL;
}
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);
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
/*前面初始化 i2c_mma7660_driver->driver.bus = &i2c_bus_type*/
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
/*为 i2c_mma7660_driver->driver申请私有结构体*/
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;
/*i2c_mma7660_driver->driver->priv->kobj.kset = i2c_bus_type->p->drivers_kset
还记得sys/bus/i2c 下的drivers目录吗
priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);*/
priv->kobj.kset = bus->p->drivers_kset;
/*在sys/bus/i2c/drivers目录下创建 mma7660 的目录*/
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
/*又见到了drivers_autoprobe,还记得/sys/bus/i2c 下的drivers_autoprobe文件吗
i2c_type->p->drivers_autoprobe = 1,自动匹配device和driver*/
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus || !bus->p)
return -EINVAL;
/*device 注册的时候就是挂接到 i2c_bus_type->p->klist_devices
下面就是遍历 i2c_bus_type 的device 链表,然后通过__driver_attach和driver
做匹配*/
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data); //fn = __driver_attach
{
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))
{ /* drv->bus->match = i2c_device_match ,最终还是调用到 i2c 总线 的match函数
最终会匹配到 mma7660 的 i2c_client*/
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
return 0;
/*dev = client->dev
client->dev.parent = &client->adapter->dev */
if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
/*虽然device和driver都找到了,可还未将driver赋值给device呢*/
if (!dev->driver)
driver_probe_device(drv, dev);
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
pr_debug("bus: '%s': %s: matched device %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);
{
int ret = 0;
atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));
/*这里才将driver和device关联起来*/
dev->driver = drv;
if (driver_sysfs_add(dev)) {
{
int ret;
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BIND_DRIVER, dev);
/*sys/bus/i2c/drivers/mma7660创建指向 3-004c 的链接,
名字仍然为 3-004c */
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj));
if (ret == 0) {
/*在 /sys/devices/platform/s3c2440-i2c.3/i2c-3/3-004c/ 下
创建指向 /sys/bus/i2c/drivers/mma7660 的链接,名字为driver*/
ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
"driver");
if (ret)
sysfs_remove_link(&dev->driver->p->kobj,
kobject_name(&dev->kobj));
}
return ret;
}
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
/*i2c_bus_type->probe = i2c_device_probe ,所以调用
i2c_device_probe ,最终调用 mma7660_probe*/
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;
}
driver_bound(dev);
{ /*前面 client->dev->p->knode_driver未初始化,也就是为NULL*/
if (klist_node_attached(&dev->p->knode_driver)) {
printk(KERN_WARNING "%s: device %s already bound\n",
__func__, kobject_name(&dev->kobj));
return;
}
pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
__func__, dev->driver->name);
/*将device挂接在driver的设备链表中*/
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev);
}
ret = 1;
pr_debug("bus: '%s': %s: bound device %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 probe failed */
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;
}
pm_runtime_put_sync(dev);
return ret;
}
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
klist_iter_exit(&i);
return error;
}
}
if (error)
goto out_unregister;
}
/*将 i2c_mma7660_driver 挂接在 i2c_bus_type 的driver链表中*/
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
/*在/sys/bus/i2c/drivers/mma7660 创建 uevent 文件*/
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
/*为 i2c_mma7660_driver 创建默认的属性文件,可是i2c_bus_type->drv_attrs = NULL,所以此例中没有
没有创建任何文件*/
error = driver_add_attrs(bus, drv);
{
int error = 0;
int i;
if (bus->drv_attrs) {
for (i = 0; attr_name(bus->drv_attrs[i]); i++) {
error = driver_create_file(drv, &bus->drv_attrs[i]);
if (error)
goto err;
}
}
done:
return error;
err:
while (--i >= 0)
driver_remove_file(drv, &bus->drv_attrs[i]);
goto done;
}
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}
/*i2c_mma7660_driver->drv->suppress_bind_attrs 未赋值,也就是为0*/
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
{
int ret;
/*在/sys/bus/i2c/drivers/mma7660 目录下创建 ubind 文件*/
ret = driver_create_file(drv, &driver_attr_unbind);
if (ret == 0) {
/*在/sys/bus/i2c/drivers/mma7660目录下创建 bind 文件*/
ret = driver_create_file(drv, &driver_attr_bind);
if (ret)
driver_remove_file(drv, &driver_attr_unbind);
}
return ret;
}
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
/*发送 KOBJ_ADD */
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;
}
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
if (res)
return res;
/* Drivers should switch to dev_pm_ops instead. */
if (driver->suspend)
pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
driver->driver.name);
if (driver->resume)
pr_warn("i2c-core: driver [%s] using legacy resume method\n",
driver->driver.name);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
i2c_for_each_dev(driver, __process_new_driver);
{
int res;
mutex_lock(&core_lock);
res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn);
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus || !bus->p)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data); //fn = __process_new_driver
{
if (dev->type != &i2c_adapter_type)
return 0;
return i2c_do_add_adapter(data, to_i2c_adapter(dev));
{
/* Detect supported devices on that bus, and instantiate them */
i2c_detect(adap, driver);
{ /* driver 所支持i2c设备的 address 列表*/
const unsigned short *address_list;
/* 声明一个临时的 i2c_client */
struct i2c_client *temp_client;
int i, err = 0;
int adap_id = i2c_adapter_id(adapter);
/* i2c_mma7660_driver->address_list 未赋值,也就是为 NULL 函数在此返回*/
address_list = driver->address_list;
if (!driver->detect || !address_list)
return 0;
......
kfree(temp_client);
return err;
}
/* Let legacy drivers scan this bus for matching devices */
if (driver->attach_adapter) {
dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
driver->driver.name);
dev_warn(&adap->dev, "Please use another way to instantiate "
"your i2c_client\n");
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
return 0;
}
}
klist_iter_exit(&i);
return error;
}
mutex_unlock(&core_lock);
return res;
}
return 0;
}
}
printk(KERN_INFO "MMA7660 sensor driver registered.\n");
return ret;
}
从上面的代码中可以看出,其实和platform的那一套机制是一回事,驱动框架完成了大量的工作,然后实际驱动只需要注册device和driver,驱动框架就会调用到probe函数,开始真正的硬件初始化相关的工作。
三、i2c-dev
不是说 linux 秉承一切皆文件吗(网络设备除外),驱动不是应该完成open、close、read和write等函数吗?到目前为止不管platform还是i2c都没有这些信息。不要忘了,bus、device和driver驱动模型,只是驱动的一种框架,并没有完成任何实质性工作,真正的注册char、block还是网络设备都是开发者自己的事,驱动模型不是最终保证会调用到probe函数吗,对的,你可以在probe函数中完成实际的设备驱动注册,如 register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops),驱动模型只是套了个架子而已,实际驱动工作还得自己做。
对于实际的 i2c 器件,只是将 i2c 作为通信通道而已,再简单的说实际设备功能并不关心是通过spi还是 i2c 进行,比如驱动中的 read 函数,按顺序读写寄存器,并不关心 是 i2c还是spi甚至usb,只要进行数据传输达到目的就行。对于 i2c 器件一般会是input、rtc或者misc,文件系统的接口自然由 input、rtc或misc模型提供,当然你也可以专门为此期间写一个char类型的驱动,完成open、close、read和write等函数,但对于i2c部分,只是利用 i2c_client->adapter->i2c_algorithm->master_xfer和器件进行数据交互。
下面看一下i2c-dev,linux提供的 i2c-dev 并不是实际存在具体的一个i2c器件,而是代表一个i2c总线的设备,可以通过 i2c-dev 提供的 read、write和ioctl来访问总线上的 i2c 器件(根据指定的器件地址)。由于不同的 i2c 器件的 read 和 write 实现各不相同,所以linux提供的 i2c-dev 并不是很通用。
下面简单看一下i2c-dev的注册过程
static const struct file_operations i2cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
.write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
static int __init i2c_dev_init(void)
{
int res;
printk(KERN_INFO "i2c /dev entries driver\n");
/*注册为char型设备,主设备号为 I2C_MAJOR(123)(终于见到设备号了) */
res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
if (res)
goto out;
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
if (IS_ERR(i2c_dev_class)) {
res = PTR_ERR(i2c_dev_class);
goto out_unreg_chrdev;
}
/* Keep track of adapters which will be added or removed later */
res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
if (res)
goto out_unreg_class;
/* Bind to already existing adapters right away */
i2c_for_each_dev(NULL, i2cdev_attach_adapter);
return 0;
out_unreg_class:
class_destroy(i2c_dev_class);
out_unreg_chrdev:
unregister_chrdev(I2C_MAJOR, "i2c");
out:
printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
return res;
}
其中 i2cdev_attach_adapter中会创建设备文件,也就是在/dev/目录下创建 i2c- %d的文件,如 i2c-3 就代表第三个i2c 上的设备或者说i2c_adapter,可通过/dev/i2c-3 来访问该总线上设备(如open、close、read和write等)。
static int i2cdev_attach_adapter(struct device *dev, void *dummy)
{
......
/* register this i2c device with the driver core */
/*创建设备文件,这回 是带 设备号的,所以也会在 /sys/dev/目录下创建文件,如i2c-3*/
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
MKDEV(I2C_MAJOR, adap->nr), NULL,
"i2c-%d", adap->nr);
......
return res;
}
上面就是i2c驱动框架的大致内容了,整体来说还是比较复杂的,不过从代码一点一点分析,还是可以理解的,但是鉴于个人的水平有限,可能会出现理解错误的地方,欢迎交流。